diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000000000000000000000000000000000000..107af9d5a97ea884aff60191cd17c0654cdf3303
--- /dev/null
+++ b/.github/CODE_OF_CONDUCT.md
@@ -0,0 +1,77 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to make participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, sex characteristics, gender identity and expression,
+level of experience, education, socio-economic status, nationality, personal
+appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+  advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+  address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+  professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies within all project spaces, and it also applies when
+an individual is representing the project or its community in public spaces.
+Examples of representing a project or community include using an official
+project e-mail address, posting via an official social media account, or acting
+as an appointed representative at an online or offline event. Representation of
+a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq
+
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e5ba81c434e2c21dad573aab6bbd398659510040
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,29 @@
+name: CI
+
+on: [push]
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v2
+      with:
+        # Number of commits to fetch. 0 indicates all history.
+        # jgit task nested in customBuild.xml fails without history.
+        fetch-depth: '0'
+
+    - name: Set up JDK 11
+      uses: actions/setup-java@v1
+      with:
+        java-version: 11.0.3
+
+    - uses: actions/cache@v1
+      with:
+        path: ~/.m2/repository
+        key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+        restore-keys: |
+            ${{ runner.os }}-maven-
+    - name: Build with Maven
+      run: mvn -Dmaven.test.skip=true -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -fae -B verify --file pom.xml
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 3f5754205080593bad60e4a63e4785e5ba092d2a..5258b58a42d3f54ad540dcefa574c0c967e2a2f4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,3 +33,5 @@ tlatools/test-model/CodePlexBug08/checkpoint/
 tlatools/test-model/CallGotoUnlabeledTest.old
 junit[0-9]*.properties
 junitvmwatcher[0-9]*.properties
+test.jfr
+*.jfr
diff --git a/.jenkins.groovy b/.jenkins.groovy
new file mode 100644
index 0000000000000000000000000000000000000000..b90f4b0f60e65f82883d6b5e4e22f3c75d36015d
--- /dev/null
+++ b/.jenkins.groovy
@@ -0,0 +1,233 @@
+//def labels = ['windows', 'master', 'macos'] // labels for Jenkins node types we will build on
+def labels = ['master', 'macos']
+def builders = [:]
+for (x in labels) {
+    def label = x // Need to bind the label variable before the closure - can't do 'for (label in labels)'
+
+    // Create a map to pass in to the 'parallel' step so we can fire all the builds at once
+    builders[label] = {
+      node(label) {
+	   stage('Preparation') { // for display purposes
+	      // Get some code from a GitHub repository
+	      git url: 'https://github.com/tlaplus/tlaplus.git'
+	   }
+	   stage('Tools') {
+		withAnt(installation: 'apache ant', jdk: 'Java11') {
+			if (isUnix()) {
+			    sh "ant -f tlatools/customBuild.xml info compile compile-test dist test-dist"
+			} else {
+			    bat "ant -f tlatools\\customBuild.xml info compile compile-test dist test-dist"
+			}
+		}
+	   }
+
+	   stage ('RecordTestAndCoverageTools') {
+	       junit 'tlatools/target/surefire-reports/onJar/*.xml'
+	      // collect jacoco results for TLC
+	      jacoco classPattern: 'tlatools/class', exclusionPattern: '**/*Test*.class', execPattern: 'tlatools/target/code-coverage.exec', sourcePattern: 'tlatools/src'
+	   }
+
+	   stage('Toolbox') {
+	      // Run the maven build
+		   if (label == 'master') {
+		      wrap([$class: 'Xvnc', takeScreenshot: false, useXauthority: true]) {
+			  withMaven(
+			    // Maven installation declared in the Jenkins "Global Tool Configuration"
+			    maven: '3.5.4',
+			    jdk: 'Java11',
+			    mavenLocalRepo: '.repository',
+			    options: [jacocoPublisher(disabled: true)]) {
+
+			    // Run the maven build
+			    sh "mvn -Pcodesigning -U clean verify -Dmaven.test.failure.ignore=true -Dtest.skip=true"
+
+			  } // withMaven will discover the generated Maven artifacts, JUnit Surefire & FailSafe & FindBugs reports...
+		      }
+	   	      // the macosx zip on the master node to have it signed with the Apple certificate on macosx.  However, only master
+		      // has the lamport certificate to sign the individual toolbox bundles.
+		      stash includes: 'org.lamport.tla.toolbox.product.product/target/products/TLAToolbox-1.6.1-macosx.cocoa.x86_64.zip', name: 'toolbox'
+                    } else {
+			  withMaven(
+			    // Maven installation declared in the Jenkins "Global Tool Configuration"
+			    maven: '3.5.4',
+			    jdk: 'Java11',
+			    mavenLocalRepo: '.repository',
+			    options: [jacocoPublisher(disabled: true)]) {
+
+			    // Run the maven build
+			    if (isUnix()) {
+				    sh "mvn -U clean verify -Dmaven.test.failure.ignore=true -Dtest.skip=true"
+			    } else {
+				    bat "mvn -U clean verify -Dmaven.test.failure.ignore=true -Dtest.skip=true"
+			    }
+
+			  } // withMaven will discover the generated Maven artifacts, JUnit Surefire & FailSafe & FindBugs reports...
+                    }
+	   }
+
+	   stage ('RecordTestToolbox') {
+	       junit '**/target/surefire-reports/*.xml'
+	   }
+      }
+    }
+}
+parallel builders
+
+// Rest runs on master node alone
+
+node ('master') {
+	
+   stage ('ReportSonarQube') {
+       withSonarQubeEnv {
+            withMaven(
+                // Maven installation declared in the Jenkins "Global Tool Configuration"
+                maven: '3.5.4',
+                jdk: 'Java11') {
+                sh "mvn $SONAR_MAVEN_GOAL -Dsonar.login=$SONAR_AUTH_TOKEN -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.branch=master"
+            }
+       }
+   }
+   
+   stage('p2Tests') {
+      wrap([$class: 'Xvnc', takeScreenshot: false, useXauthority: true]) {
+       sh '''
+          rm -rf TLAToolbox-?.?.?-linux.gtk.x86_64.zip
+		rm -rf toolbox/
+
+		## copy currently released Toolbox and extract it (We want to make sure that we can update from it to this build)
+		wget http://dl.tlapl.us/tlatoolbox/products/TLAToolbox-1.6.0-linux.gtk.x86_64.zip
+		unzip -qq TLAToolbox*.zip
+
+		cd toolbox/
+		
+		## Update current Toolbox release to this version
+		./toolbox -nosplash -application org.eclipse.equinox.p2.director \
+		-repository file://${WORKSPACE}/org.lamport.tla.toolbox.product.product/target/repository \
+		-uninstallIU org.lamport.tla.toolbox.product.product \
+		-installIU org.lamport.tla.toolbox.product.product \
+		-profileProperties org.eclipse.update.install.features=true
+
+		## Use Toolbox's p2 director to install the test feature into the previuos toolbox release to verify the update above worked and didn't trash anything.
+		./toolbox -nosplash -application org.eclipse.equinox.p2.director \
+		-repository file://${WORKSPACE}/org.lamport.tla.toolbox.p2repository/target/repository/ \
+		-installIU org.lamport.tla.toolbox.feature.uitest.feature.group
+
+		## Run the SWTBot smoke tests to check product zips
+		./toolbox -nosplash -application org.eclipse.swtbot.eclipse.junit.headless.swtbottestapplication \
+		-testApplication org.lamport.tla.toolbox.application \
+		-product org.lamport.tla.toolbox.product.standalone.product \
+		-nouithread \
+		-testPluginName org.lamport.tla.toolbox.tool.tlc.ui.uitest \
+		formatter=org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter \
+		formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,org.lamport.tla.toolbox.tool.tlc.ui.uitest.SmokeTests.xml \
+		-className org.lamport.tla.toolbox.SmokeTests \
+		-data workspace$(date +%s) \
+		-clean
+
+		cp *.xml ${WORKSPACE}/
+       '''
+      }
+   }
+
+   stage ('RecordTestP2UpdateManager') {
+       // Collect junit output for p2 smoke tests
+       junit 'toolbox/org.lamport.tla.toolbox.tool.tlc.ui.uitest.SmokeTests.xml'
+   }
+   
+   stage('CreateRPMFile') {
+       sh '''
+        cd org.lamport.tla.toolbox.product.product/target/
+        fakeroot alien --to-rpm --scripts TLAToolbox-?.?.?-linux.gtk.amd64.deb
+        cp TLA*.rpm products/
+       '''
+   }
+   
+   stage('CreateAPTRepo') {
+       sh '''
+        chmod -x org.lamport.tla.toolbox.product.product/createAptRepo.sh
+        cp org.lamport.tla.toolbox.product.product/target/*.deb org.lamport.tla.toolbox.product.product/target/repository/
+        cd org.lamport.tla.toolbox.product.product/target/repository/
+        bash -x ../../createAptRepo.sh .
+       '''
+   }
+   
+   stage('RenderChangelog') { // Render the github flavord markdown to html
+       sh 'grip --context=tlaplus/tlaplus --export ${WORKSPACE}/general/docs/changelogs/ch1_6_1.md ${WORKSPACE}/general/docs/changelogs/changelog.html'
+   }
+}
+
+node ('macos') {
+    stage('SignToolbox') {
+        sh 'rm -rf *'
+        unstash 'toolbox'
+        sh 'ls -lah'
+        sh 'unzip org.lamport.tla.toolbox.product.product/target/products/TLAToolbox-1.6.1-macosx.cocoa.x86_64.zip'
+        sh 'codesign -f -s "Developer ID Application: M K (3PCM4M3RWK)" -v "TLA+ Toolbox.app" --deep'
+        sh 'ditto -ck --sequesterRsrc --keepParent "TLA+ Toolbox.app" TLAToolbox-1.6.1-macosx.cocoa.x86_64.zip'
+        sh 'mv TLAToolbox-1.6.1-macosx.cocoa.x86_64.zip org.lamport.tla.toolbox.product.product/target/products/'
+        stash includes: 'org.lamport.tla.toolbox.product.product/target/products/TLAToolbox-1.6.1-macosx.cocoa.x86_64.zip', name: 'signed'
+    }
+}
+
+node ('master') {
+   stage('Archive') {
+      unstash 'signed'
+      fingerprint '**/org.lamport.tla.toolbox.product.product/target/repository/, **/org.lamport.tla.toolbox.product.product/target/products/*.zip, **/org.lamport.tla.toolbox.product.product/target/products/*.deb, **/tlatools/dist/, **/org.lamport.tla.toolbox.doc/html/'
+
+      archiveArtifacts '**/general/docs/changelogs/changelog.html, **/org.lamport.tla.toolbox.product.product/target/org.lamport.tla.toolbox.product.product-1.4.0-SNAPSHOT.zip, **/org.lamport.tla.toolbox.p2repository/target/repository/, **/org.lamport.tla.toolbox.product.product/target/repository/, **/org.lamport.tla.toolbox.product.product/target/products/*.zip, **/org.lamport.tla.toolbox.product.product/target/products/*.deb, **/org.lamport.tla.toolbox.product.product/target/products/*.rpm, **/org.lamport.tla.toolbox.product.product/target/products/32bit_x86/*, **/tlatools/dist/, **/org.lamport.tla.toolbox.doc/html/'
+   }
+}
+
+node ('master') {
+   stage ('DraftGithubRelease') {
+	if (env.JOB_NAME == 'Release-HEAD-master-Toolbox') {
+         sh '''
+           #!/bin/bash
+
+           cd ${WORKSPACE}/general/docs/changelogs
+
+           ## Append sha1 sum to changelog (last line of changelog has the table header).
+           echo "$(sha1sum ${WORKSPACE}/tlatools/dist/tla2tools.jar | cut -f 1 -d " ")|tla2tools.jar"  >> ch1_6_1.md
+           echo "$(sha1sum ${WORKSPACE}/org.lamport.tla.toolbox.product.product/target/products/TLAToolbox-1.6.1-win32.win32.x86_64.zip | cut -f 1 -d " ")|TLAToolbox-1.6.1-win32.win32.x86_64.zip" >> ch1_6_1.md
+           echo "$(sha1sum ${WORKSPACE}/org.lamport.tla.toolbox.product.product/target/products/TLAToolbox-1.6.1-macosx.cocoa.x86_64.zip | cut -f 1 -d " ")|TLAToolbox-1.6.1-macosx.cocoa.x86_64.zip" >> ch1_6_1.md     
+           echo "$(sha1sum ${WORKSPACE}/org.lamport.tla.toolbox.product.product/target/products/TLAToolbox-1.6.1-linux.gtk.x86_64.zip | cut -f 1 -d " ")|TLAToolbox-1.6.1-linux.gtk.x86_64.zip" >> ch1_6_1.md
+           
+           ## Two above as one-liner without intermediate file.
+           $(jq -n --argjson changelog "$(cat ch1_6_1.md | jq  --raw-input --slurp .)" -f gh-1_6_1.jq > gh-1_6_1.json)
+
+           ## Get id of existing draft release with given name.
+           DRAFT_RELEASE=$(curl -sS -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/repos/tlaplus/tlaplus/releases --header "Content-Type: application/json" | jq '.[]| select(.draft==true and .name=="The Aristotle release") | .id')
+           echo $DRAFT_RELEASE
+
+           ## Update draft release with latest changelog in case it changed.
+           ## https://developer.github.com/v3/repos/releases/#edit-a-release
+           curl -sS -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/repos/tlaplus/tlaplus/releases/$DRAFT_RELEASE -d @gh-1_6_1.json -X PATCH --header "Content-Type: application/json"
+
+           ## Remove old assets otherwise upload below will error.
+           ASSETS=$(curl -sS -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/repos/tlaplus/tlaplus/releases/$DRAFT_RELEASE/assets --header "Content-Type: application/json" | jq '.[]| .id')
+           for id in $(echo "$ASSETS"); do
+              ## DELETE /repos/:owner/:repo/releases/assets/:asset_id
+              curl -sS -X DELETE -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/repos/tlaplus/tlaplus/releases/assets/$id
+           done
+           
+            ## p2 repository
+            #curl -s -X POST -H "Content-Type: application/zip" -H "Authorization: token ${GITHUB_TOKEN}" https://uploads.github.com/repos/tlaplus/tlaplus/releases/$DRAFT_RELEASE/assets?name=repository.zip --upload-file ${WORKSPACE}/org.lamport.tla.toolbox.p2repository/target/repository/repository.zip
+            ## tla2tools.jar
+            curl -s -X POST -H "Content-Type: application/zip" -H "Authorization: token ${GITHUB_TOKEN}" https://uploads.github.com/repos/tlaplus/tlaplus/releases/$DRAFT_RELEASE/assets?name=tla2tools.jar --upload-file ${WORKSPACE}/tlatools/dist/tla2tools.jar
+            ## macOS
+            curl -s -X POST -H "Content-Type: application/zip" -H "Authorization: token ${GITHUB_TOKEN}" https://uploads.github.com/repos/tlaplus/tlaplus/releases/$DRAFT_RELEASE/assets?name=TLAToolbox-1.6.1-macosx.cocoa.x86_64.zip --upload-file ${WORKSPACE}/org.lamport.tla.toolbox.product.product/target/products/TLAToolbox-1.6.1-macosx.cocoa.x86_64.zip
+            ## win32
+            curl -s -X POST -H "Content-Type: application/zip" -H "Authorization: token ${GITHUB_TOKEN}" https://uploads.github.com/repos/tlaplus/tlaplus/releases/$DRAFT_RELEASE/assets?name=TLAToolbox-1.6.1-win32.win32.x86_64.zip --upload-file ${WORKSPACE}/org.lamport.tla.toolbox.product.product/target/products/TLAToolbox-1.6.1-win32.win32.x86_64.zip
+            ## Linux
+            curl -s -X POST -H "Content-Type: application/zip" -H "Authorization: token ${GITHUB_TOKEN}" https://uploads.github.com/repos/tlaplus/tlaplus/releases/$DRAFT_RELEASE/assets?name=TLAToolbox-1.6.1-linux.gtk.x86_64.zip --upload-file ${WORKSPACE}/org.lamport.tla.toolbox.product.product/target/products/TLAToolbox-1.6.1-linux.gtk.x86_64.zip
+            ## deb
+            #curl -s -X POST -H "Content-Type: application/zip" -H "Authorization: token ${GITHUB_TOKEN}" https://uploads.github.com/repos/tlaplus/tlaplus/releases/$DRAFT_RELEASE/assets?name=TLAToolbox-1.6.1-linux.gtk.amd64.deb --upload-file ${WORKSPACE}/org.lamport.tla.toolbox.product.product/target/repository/TLAToolbox-1.6.1-linux.gtk.amd64.deb
+            ## RPM
+            #curl -s -X POST -H "Content-Type: application/zip" -H "Authorization: token ${GITHUB_TOKEN}" https://uploads.github.com/repos/tlaplus/tlaplus/releases/$DRAFT_RELEASE/assets?name=TLAToolbox-1.6.1-linux.gtk.amd64.rpm --upload-file ${WORKSPACE}/org.lamport.tla.toolbox.product.product/target/products/TLA\\+Toolbox-1.6.1~*.x86_64.rpm
+         '''
+        }
+   }
+}
+
+
+
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index bf1254715d67626b6d7bd44bf486d99855782ced..54e0962c72add72a009547851f11dfc66ab2dff0 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -6,6 +6,33 @@ Generally, we welcome contributions from volunteers. A number of [improvements w
 
 Except for [TLAPS](https://tla.msr-inria.inria.fr/tlaps/content/Home.html), the TLA<sup>+</sup> tools are maintained in Eclipse. [For instructions on how to setup the Eclipse IDE, please go to general/ide/README.md.](https://github.com/tlaplus/tlaplus/tree/master/general/ide).
 
+Nightly Builds
+--------------
+
+Nightly builds of the [Toolbox](https://nightly.tlapl.us/products/) and [tla2tools](https://nightly.tlapl.us/dist/) are found at https://nightly.tlapl.us/products/ and https://nightly.tlapl.us/dist/, the [up-to-date changelog](https://nightly.tlapl.us/changelog.html) is at https://nightly.tlapl.us/changelog.html.  The Toolbox contains the latest version of tla2tools.jar for command-line usage in its root directory.
+
+It is also possible to configure the Toolbox to [automatically update to nightly (experimental) builds](https://nightly.tlapl.us/doc/update/update-preferences.html).  
+
+Note that it is called nightly for historical reasons, but builds are actually triggered by commits.
+
+#### Linux
+
+For dpkg-based Linux derivates such as Debian and Ubuntu, you can add the Toolbox's nightly package repository to your source list:
+
+```
+$ cat /etc/apt/sources.list.d/tlaplus.list
+deb https://nightly.tlapl.us/toolboxUpdate/ ./
+$ curl -fsSL https://tla.msr-inria.inria.fr/jenkins.pub | sudo apt-key add -
+```
+
+#### macOS
+
+The Toolbox's nightly builds are also made available as a [cask](https://github.com/Homebrew/homebrew-cask-versions/blob/master/Casks/tla-plus-toolbox-nightly.rb) through [homebrew versions](https://github.com/Homebrew/homebrew-cask-versions#usage):
+
+```bash
+$ brew tap homebrew/cask-versions
+$ brew install tlaplus-toolbox-nightly
+```
 
 Quality Metrics
 ---------------
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 8f6c7cadd20e066e539f8afbfaf2d6fde20889cb..5db18575eb41f80ab54107de493b16d0d6ed1f11 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -3,6 +3,12 @@
 # Add steps that analyze code, save build artifacts, deploy, and more:
 # https://docs.microsoft.com/azure/devops/pipelines/languages/java
 
+## https://docs.microsoft.com/en-us/azure/devops/pipelines/caching/?view=azure-devops#can-i-clear-a-cache
+variables:
+  MAVEN_CACHE_FOLDER: $(Pipeline.Workspace)/.m2/repository
+  MAVEN_OPTS: '-Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)'
+
+
 jobs:
 
 - job: Linux
@@ -29,7 +35,7 @@ jobs:
   timeoutInMinutes: 0
 
   pool:
-    vmImage: 'vs2017-win2016'
+    vmImage: 'windows-2019'
 
   steps:
   - task: Maven@3
@@ -49,13 +55,13 @@ jobs:
   timeoutInMinutes: 0
 
   pool:
-    vmImage: 'macOS-10.13'
+    vmImage: 'macOS-10.14'
 
   steps:
   - task: Maven@3
     inputs:
       mavenPomFile: 'pom.xml'
-      mavenOptions: '-Xmx3072m -Dmaven.test.skip=true -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn'
+      mavenOptions: '-Xmx3072m -Dtest.skip=true -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn'
       options: '-fae -B'
       javaHomeOption: 'JDKVersion'
       jdkVersionOption: '1.11'
diff --git a/general/docs/Notarization_in_macOS.md b/general/docs/Notarization_in_macOS.md
new file mode 100644
index 0000000000000000000000000000000000000000..54a9ad4449e160f3499986e84ee961db7d1f6f03
--- /dev/null
+++ b/general/docs/Notarization_in_macOS.md
@@ -0,0 +1,128 @@
+## Adventures In macOS Notarization
+
+Due to [Issue 280](https://github.com/tlaplus/tlaplus/issues/280) we have been code signing the application. Beginning in January, 2020, users of Catalina (macOS 10.15) and later will need have their applications also be 'notarized.'
+
+A Java Program Manager at Microsoft, [wrote a Dummies guide](https://medium.com/@gdams/dummies-guide-to-notarizing-your-runtime-a1e9105b2c21) to notarizing which i attempted to apply to the Toolbox application, all from a Catalina install with XCode 11. Notes from following this, plus "insights" discovered from going wrong in the following and then Googling elsewhere, are below.
+
+### The Results, first
+
+I was able to get the .app notarized successfully with Apple; even after that, inquiring as to its signed status using `spctl` would still state that the app was rejected.
+
+In addition, after running the Toolbox the first time, subsequent queries using `spctl` would then tell me:
+```
+TLA+ Toolbox.app: a sealed resource is missing or invalid
+```
+
+The people at Eclipse are [successfully signing and notarizing 2019-09,](https://bugs.eclipse.org/bugs/show_bug.cgi?id=550135) so signing & notarizing RCPs are possible.
+
+### Signing certificates and passwords
+
+As done in 280, the signing certificates need be installed locally via XCode. Also make sure that you have logged into your account at developer.apple.com and have agreed to all of the latest AppConnect agreements, or you will get a message like
+```
+1 package(s) were not uploaded because they had problems:
+	/var/folders/fn/y4q2v5yx5fd0h7t20ss1qr780000gn/T/9C150E6E-4CD2-4C7C-828B-06B374C4A7ED/org.lamport.tla.toolbox.product.product.itmsp - Error Messages:
+		You must first sign the relevant contracts online. (1048)
+```
+when trying to notarize.
+
+Also, notarizing with Apple requires authentication, of course, during the upload. However, authentication with Apple is now always 2FA; to that extent, you must [generate an app-specific password.](https://support.apple.com/en-us/HT204397)
+
+Once you have an app-specific password, cram it in your KeyChain by doing something like:
+```
+xcrun altool --store-password-in-keychain-item "AC_PASSWORD" -u "your@apple.id" -p abcd-efgh-ijkl-mnop
+```
+
+Now you can refer to it in the KeyChain using an appropriate scheme, which we'll see later.
+
+### The routine
+
+Assuming you have built the Toolbox application change directories to be sitting in the directory containing `TLA+ Toolbox.app`
+
+#### The 'entitlements' file
+
+I cribbed this content from the medium.com article and saved it as 'entitlements.plist'
+```
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+    <key>com.apple.security.cs.allow-jit</key>
+    <true/>
+    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
+    <true/>
+    <key>com.apple.security.cs.disable-executable-page-protection</key>
+    <true/>
+    <key>com.apple.security.cs.allow-dyld-environment-variables</key>
+    <true/>
+    <key>com.apple.security.cs.disable-library-validation</key>
+    <true/>
+</dict>
+</plist>
+```
+
+#### Signing the app
+
+Now i signed the app itself with:
+```
+codesign --entitlements entitlements.plist --options runtime --timestamp -f -s "Developer ID Application: My Company Name (XXXX)" -v "TLA+ Toolbox.app" --deep
+```
+verifying the signing at this point shows:
+```
+loki@apalina Desktop % spctl --verbose=4 --assess --type execute "TLA+ Toolbox.app"
+TLA+ Toolbox.app: rejected
+source=Unnotarized Developer ID
+loki@apalina Desktop % codesign --verify -vvvv "TLA+ Toolbox.app"
+TLA+ Toolbox.app: valid on disk
+TLA+ Toolbox.app: satisfies its Designated Requirement
+loki@apalina Desktop %
+```
+
+#### Having Apple notarize the thing
+
+I then ZIP'd up the .app and then handed it over to Apple with (this is where we reference the app-specific password we crammed in the KeyChain):
+```
+loki@apalina Desktop % xcrun altool --notarize-app --primary-bundle-id "org.lamport.tla.toolbox.product.product" --username "your@apple.id" --password "@keychain:AC_PASSWORD" --file "TLA+ Toolbox.app.zip"
+No errors uploading 'TLA+ Toolbox.app.zip'.
+RequestUUID = de01d0fe-a88e-44fa-802f-da62ec93e994
+loki@apalina Desktop %
+```
+
+You can check the status with:
+```
+loki@apalina Desktop % xcrun altool --notarization-info de01d0fe-a88e-44fa-802f-da62ec93e994 --username "your@apple.id" --password "@keychain:AC_PASSWORD"
+No errors getting notarization info.
+
+          Date: 2019-10-30 22:21:36 +0000
+          Hash: 18eafe5a64abeef722316df47fb5c1f7249a7943df5bc65dccb5d697d00ba55d
+    LogFileURL: https://osxapps-ssl.itunes.apple.com/itunes-assets/Enigma113/v4/72/43/75/72xxx05a68b8c/developer_log.json?accessKey=xxx%3D
+   RequestUUID: de01d0fe-a88e-44fa-802f-da62ec93e994
+        Status: success
+   Status Code: 0
+Status Message: Package Approved
+loki@apalina Desktop %
+```
+and the service also sends an email when the process has finished.
+
+#### Done?
+
+At this point, unpacking the ZIP i uploaded and then verifying the signature on the .app shows:
+```
+loki@apalina Desktop % spctl --verbose=4 --assess --type execute "TLA+ Toolbox.app"
+TLA+ Toolbox.app: rejected
+source=Notarized Developer ID
+loki@apalina Desktop %
+```
+the app is still rejected, whatever that means; though the submission has been notarized.
+
+There is the notion of stapling (so that this notarization can be seen on machines that have no internet access,) however doing this:
+```
+loki@apalina Desktop % xcrun stapler staple "TLA+ Toolbox.app"
+Processing: /Users/loki/Desktop/TLA+ Toolbox.app
+Processing: /Users/loki/Desktop/TLA+ Toolbox.app
+The staple and validate action worked!
+loki@apalina Desktop % spctl --verbose=4 --assess --type execute "TLA+ Toolbox.app"
+TLA+ Toolbox.app: rejected
+source=Notarized Developer ID
+loki@apalina Desktop %
+```
+affects nothing obvious concerning the rejection.
diff --git a/general/docs/changelogs/ch1_6_0.md b/general/docs/changelogs/ch1_6_0.md
index 5fa6e390fd2eb109ca4328cc1b85ebe32cac92c7..5a5dcace56353b5b511f9dfcfdf968466db4875e 100644
--- a/general/docs/changelogs/ch1_6_0.md
+++ b/general/docs/changelogs/ch1_6_0.md
@@ -108,3 +108,7 @@ Please check out the upcoming TLA+ conf at [http://conf.tlapl.us/](http://conf.t
 
 ### A note to macOS users
 Startup on macOS version 10.14 (Mojave) will fail with "TLA+ Toolbox can't be opened because Apple cannot check it for malicious software.".  Please make sure to follow the instructions outlined in [GitHub issue #320](https://github.com/tlaplus/tlaplus/issues/320) to address this problem.
+
+### Checksums
+sha1sum|file
+------------ | -------------
\ No newline at end of file
diff --git a/general/docs/changelogs/ch1_6_1.md b/general/docs/changelogs/ch1_6_1.md
new file mode 100644
index 0000000000000000000000000000000000000000..e1ce796d3be38b372d2585384e2214fa933b4932
--- /dev/null
+++ b/general/docs/changelogs/ch1_6_1.md
@@ -0,0 +1,82 @@
+### Changelog
+The high level changelog is available at http://research.microsoft.com/en-us/um/people/lamport/tla/toolbox.html#release. The [1.6.1 milestone](https://github.com/tlaplus/tlaplus/issues?q=is%3Aissue+milestone%3A1.6.1+is%3Aclosed) lists all completed issues.
+
+
+### Additional noteworthy changes
+
+#### TLC
+* Annotation-based loading of TLC module overrides for TLA+ operators. eb42f9ed462782c1577ec7433a993b770959437e
+* More powerful TLC module overrides that can programmatically manipulate a successor state. bb64cfd921c2e8846f47a5818d85cd0e8f2aa2c5
+* Write snapshots of state graph in dot/gv format after every new state. 305f38b1b7f68a0f4885615e7a148c3bf83aad95
+* A number of additions pertaining to working with trace expressions have been added to the command line tool `tlc2.TLC` and a new peer command line tool `tlc2.TraceExplorer` - see [GitHub Issue 393](https://github.com/tlaplus/tlaplus/issues/393) for an overview and background. Salient points include:
+ * Running TLC with both the `-generateSpecTE` flag will enable 'tool mode' output and, in the event that the model check encounters errors, generate a `SpecTE.tla` and `SpecTE.cfg` file pair that captures
+ the state trace reconstruction in an Init-Next relation spec.
+   * This `SpecTE.tla` will, by default, be a monolithic file, prefaced by the tool output, followed a the `SpecTE` MODULE definition which includes all extended non-StandardModule TLA code as well.
+     * To prevent the monolith inclusion of dependent TLA code, specify `nomonolith` after the `-generateSpecTE`
+ * Running TLC with `-h` now displays a usage page reminiscent of a standard man page.
+ * TraceExplorer exposes four capabilities:
+   * running the TraceExplorer with no spec name puts the TraceExplorer into a mode to receive input via stdin (e.g in order to pipe tool-mode output from TLC)
+   * pretty-printing: given an existing tool-mode output from a previous model check run (or piping in such output), pretty-printing will display an output stack to the terminal in basically the same format as one would see in the Toolbox's Error Viewer
+   * SpecTE generation: given an existing tool-mode output from a previous model check run (or piping in such output), create a `SpecTE.tla` and `SpecTE.cfg` file pair - this **will not** be a monolithic version.
+   * Expression exploration: given an existing tool-mode output from a previous model check run (or piping in such output), and file of expressions, one per line:
+     * create a `SpecTE.tla` and `SpecTE.cfg` file pair if one doesn't exist
+     * then create a `TE.tla` and `TE.cfg` file pair which extends SpecTE and contains appropriate conjunctions featuring the expressions
+     * then run model checking on this TE spec, both creating a `TE.out` and dumping the tool-mode output to stdout
+     * then do a courtesy pretty-print of the output. Pretty-printing in this scenario will ANSI-bold the expressions and their evaluated values
+   * Single expression exploration: as a sort of REPL-adjacent, any single TLA+ expression can be evaluated.
+   * running `tlc2.TraceExplorer` with no arguments, or `-h` will display helpful usage verbiage
+
+#### Toolbox
+
+##### Preferences
+* The Toolbox now supports selecting a Dark theme via `General → Appearance`.
+* The "Show Evaluate Constant Expression in its own tab" preference has been moved from `TLA+ Preferences → TLC Model Checker` to `TLA+ Preferences → Model Editor`.
+* The `TLA+ Preferences → TLAPS` preference subtree has been altered:
+ * the previous page at `TLA+ Preferences → TLAPS` is now at `TLA+ Preferences → TLAPS → Color Predicates`.
+ * The page previously at `TLA+ Preferences → TLAPS → Additional Preferences` is now renamed to `TLA+ Preferences → TLAPS → Other Preferences`.
+ * Non-color-predicate-related preferences from `TLA+ Preferences → TLAPS → Additional Preferences` have been moved into `TLA+ Preferences → TLAPS`.
+ * `TLA+ Preferences → TLAPS` now also features the ability to set a file system location for the `tlapm` executable should the Toolbox not be able to find it.
+* On macOS, you can now set the preference to have the operating system open PDFs with your default PDF viewer via `TLA+ Preferences → PDF Viewer`.
+
+##### Spec Editor
+* The spec editor now allows the collapsing of block comments, PlusCal code, and the TLA+ translation of PlusCal code. The first line of each of these types of runs should feature a minus icon in the line number gutter. Clicking on this icon will collapse the run; while in a collapsed state, holding the mouse over the, now: plus, icon will show the collapsed text as a tooltip.
+ * Please review the help page for the PlusCal translator in the Toolbox for guidance
+ as to how the comment block surround the PlusCal algorithm should be written.
+ * The preferences pane found at `TLA+ Preferences → Module Editor` allows for the setting of the default folding preferences (e.g 'always fold block comments when opening a specification in the editor.')
+* The spec editor also allows the collapsing of a contiguous run of two or more single line comments (where a single line comment is defined as a line starting with 0 or more spaces and or tabs, followed by a `\*`)
+* The translation of PlusCal code now generates a checksum of this code and the resulting TLA+ code; this checksum is calculated again when a model is executed and if it has changed, either a warning dialog will be displayed (if executed via the Toolbox) or a log warning will be emitted (if TLC is executed on the command line.)
+ * If you make a change to the generated TLA+ code, but do not want to be warned by the Toolbox of the divergence, you can delete only the TLA checksum (e.g `\** END TRANSLATION TLA-9b285153d0358878d62b88c9d4a6a047` → `\** END TRANSLATION`.) You will still be warned if the PlusCal code content is found to have changed without re-translating.
+* If attempting to generate a PDF of a spec fails because the `pdflatex` executable could not be found, a more informative warning dialog is now displayed for the user, including a way to directly open the Toolbox preference page specifying executable location.
+* The ability to user the prover against a spec will now be disabled while the spec fails to be successfully parsed.
+
+##### Model Editor
+* The style of the display of definitions in the "Definition Override" section in the Spec Options tab can be defined in the `TLA+ Preferences → Model Editor` preferences. There are two styles currently; given a `Definition` from a `Module Name` referenced in the primary spec like `InstanceName == INSTANCE ModuleName WITH ...`, then the two available styles are:
+ * `Definition [Module Name]`
+ * `InstanceName!Definition`
+* The Initial predicate / Next-state text areas were no longer interpreting a TAB as 'advance focus' due to a regression introduced when we moved to multi-line support for these text areas in 1.6.0. Both text areas now interpret a TAB as a focus advance; a TAB in the 'Init:' text area moves focus to the 'Next:' text area and a TAB in that text area advances the focus to the 'What is the model?' section.
+* New models now open a Model Editor instance with only a single tab - the Model Overview page. Running the model will open the Results tab, or should the user want to work immediately with evaluating constant expressions, there is a link at the bottom of the Model Overview page which will open the Results tab (as well as the Constant Expressions tab should the user have configured their preferences to show this in its own tab.)
+* Warn when checking liveness under action or state constraints (see [Specifying Systems](https://lamport.azurewebsites.net/tla/book.html) section 14.3.5 on page 247 for details).
+
+##### Spec Explorer
+* Right-clicking on model snapshots was incorrectly presenting the choice to rename the snapshot; this has been corrected.
+* Renaming specifications now correctly cleans up after itself [and should no longer prevent models from being opened.](https://github.com/tlaplus/tlaplus/issues/339)
+* Previously, opening a spec while the current spec had a dirty editor open, and to which the user chose to `Cancel` the offer to save the dirtied editor, resulted in the Toolbox continuing to open the new spec. This has been fixed - the opening process is halted and the original spec remains open.
+* Deleting a spec which has a currently dirty editor open for it, in which the user Cancel-s out of the dialog warning that the user is closing a dirty editor and asking whether they want to Don't Save, or Cancel, or Save, was continuing with the deletion of the spec. [It now stops the deletion process.](https://github.com/tlaplus/tlaplus/issues/375)
+
+##### Trace Explorer
+* The Error-Trace can now be filtered to omit one or more variables and/or expressions. Clicking on the filter icon, when filtering is not on, will display a dialog allowing the user to select from the set of variables and expressions found in the trace; alternatively, the user may ALT-click on a variable or expression in the Error-Trace tree view which will then omit that variable or expression. ([Screencast](https://raw.githubusercontent.com/tlaplus/tlaplus/master/general/docs/changelogs/screencasts/error-trace-filtering.gif))
+ * Also provided in the Error-Trace filtering dialog is the ability to hide variables whose values have not changed. For a variable that has changed at sometime during the trace, it may be displayed in either only the frames in which its value has changed, or in every frame of the trace. ([Screencast](https://raw.githubusercontent.com/tlaplus/tlaplus/master/general/docs/changelogs/screencasts/show_hide_changed_variables.gif))
+ * While filtering is enabled, a checkbox will be displayed above the variable value viewing text area allowing this area to display all the variables, or only the filtered variables, when a state is selected in the Error-Trace tree.
+* [Allow Trace-Explorer to extend additional TLA+ modules](https://github.com/tlaplus/tlaplus/issues/342) ([Screencast](https://raw.githubusercontent.com/tlaplus/tlaplus/master/general/docs/changelogs/screencasts/ExtendModulesForTraceExplorer.gif))
+* Export Error-Trace to system's clipboard ([Screencast](https://raw.githubusercontent.com/tlaplus/tlaplus/master/general/docs/changelogs/screencasts/ExportErrorTrace.gif))
+* Model checking can now be started using any given frame shown in the Error-Trace. Right-clicking on any location row will display a context menu giving the user the opportunity to run the model checking starting at that state. ([Screencast](https://raw.githubusercontent.com/tlaplus/tlaplus/master/general/docs/changelogs/screencasts/model_check_from_error_trace_state.gif))
+
+### Running checking in Ad Hoc mode
+* We have ended support for launching workers via JNLP; more information can be found on the master server's web page when running in this mode (e.g http://localhost:10996)
+
+### A note to macOS users
+Startup on macOS version 10.14 (Mojave) will fail with "TLA+ Toolbox can't be opened because Apple cannot check it for malicious software.".  Please make sure to follow the instructions outlined in [GitHub issue #320](https://github.com/tlaplus/tlaplus/issues/320) to address this problem.
+
+### Checksums
+sha1sum|file
+------------ | -------------
diff --git a/general/docs/changelogs/gh-1_6_1.jq b/general/docs/changelogs/gh-1_6_1.jq
new file mode 100644
index 0000000000000000000000000000000000000000..ced92374429863edfa08a73f38f1f8b88b3b1825
--- /dev/null
+++ b/general/docs/changelogs/gh-1_6_1.jq
@@ -0,0 +1,7 @@
+{
+  "tag_name": "v1.6.1",
+  "name": "The Aristotle release",
+  "draft": true,
+  "prerelease": false,
+  "body": $changelog
+}
\ No newline at end of file
diff --git a/general/docs/changelogs/screencasts/ExportErrorTrace.gif b/general/docs/changelogs/screencasts/ExportErrorTrace.gif
new file mode 100644
index 0000000000000000000000000000000000000000..9de6f1796d6933852351cef7bb1dbc14de75a0b0
Binary files /dev/null and b/general/docs/changelogs/screencasts/ExportErrorTrace.gif differ
diff --git a/general/docs/changelogs/screencasts/ExtendModulesForTraceExplorer.gif b/general/docs/changelogs/screencasts/ExtendModulesForTraceExplorer.gif
new file mode 100644
index 0000000000000000000000000000000000000000..c708b8881c102999d5d7e2833c1db891f439ce27
Binary files /dev/null and b/general/docs/changelogs/screencasts/ExtendModulesForTraceExplorer.gif differ
diff --git a/general/docs/changelogs/screencasts/error-trace-filtering.gif b/general/docs/changelogs/screencasts/error-trace-filtering.gif
new file mode 100644
index 0000000000000000000000000000000000000000..046251825757193635f1ebf912913b755e26da6c
Binary files /dev/null and b/general/docs/changelogs/screencasts/error-trace-filtering.gif differ
diff --git a/general/docs/changelogs/screencasts/model_check_from_error_trace_state.gif b/general/docs/changelogs/screencasts/model_check_from_error_trace_state.gif
new file mode 100644
index 0000000000000000000000000000000000000000..1dc4bc02ad66aa031bb70d04ecc7a162f7404f03
Binary files /dev/null and b/general/docs/changelogs/screencasts/model_check_from_error_trace_state.gif differ
diff --git a/general/docs/changelogs/screencasts/show_hide_changed_variables.gif b/general/docs/changelogs/screencasts/show_hide_changed_variables.gif
new file mode 100644
index 0000000000000000000000000000000000000000..b82cf58026789a645fc51cf79f5d4f948c1e10ff
Binary files /dev/null and b/general/docs/changelogs/screencasts/show_hide_changed_variables.gif differ
diff --git a/general/docs/contributions.md b/general/docs/contributions.md
index e8e5adfc1a8dd28ea1874c774a3cee440b614702..46c2b4203275b8af1aec917b52d799236c8f5a7c 100644
--- a/general/docs/contributions.md
+++ b/general/docs/contributions.md
@@ -53,3 +53,8 @@ We raised an [enhancement request for the jclouds toolkit](https://issues.apache
 
 #### Finish Unicode support (difficulty: easy) (skills: Eclipse, SANY)
 A few [outstanding issues](https://github.com/tlaplus/tlaplus/issues?q=is%3Aissue+is%3Aopen+label%3AUnicode) prevent the integration of the Unicode support into the Toolbox. In addition to the open issues, adding unit tests would be welcomed. A [nightly/ci Jenkins build](https://tla.msr-inria.inria.fr/build/job/M-HEAD-pron-unicode-Toolbox.product.standalone/) is available.
+
+TLA+ Tools
+----------
+#### Pretty Print to HTML (difficulty: easy) (skills: Java, HTML)
+TLA+ has a great pretty-printer to TeX (`tla2tex`), but HTML is becoming a de-facto document standard, especially for content shared online. HTML also has other advantages, such as the ability to automatically add hyperlinks from symbols to their definitions, and allow for collapsing and expanding proofs. The existing `tla2tex` code already contains most of the necessary parsing and typesetting pre-processing (like alignment), and could serve as a basis for an HTML pretty-printer. A [prototype already exists](https://github.com/tlaplus/tlaplus/issues/146).
diff --git a/general/ide/README.md b/general/ide/README.md
index bb1e1dcbc520cb8af927cc66819f7d70c534d69c..4b131f0cb5b4889ed1f70346cf894f8161acde5a 100644
--- a/general/ide/README.md
+++ b/general/ide/README.md
@@ -2,12 +2,13 @@ Eclipse Oomph is a tool to simplify and automate the setup of Eclipse developmen
 
 [A screencast is available that captures the written instructions below.](https://vimeo.com/190224035)
 
-0. Requires a recent - at the time of writing this is 11 - JDK (Java Development Environment) - OpenJDK is recommended.
-1. Install the Oomph Eclipse installer from https://wiki.eclipse.org/Eclipse_Installer
+0. Requires a recent - at the time of writing this is 13 - JDK (Java Development Environment) - AdoptOpenJDK is recommended.
+1. Install the Oomph Eclipse installer from [https://wiki.eclipse.org/Eclipse_Installer](https://wiki.eclipse.org/Eclipse_Installer)
 2. Start the downloaded Oomph installer
 3. Switch to "Advanced Mode" by clicking the button in the right upper corner depicted with three horizontal lines
 4. Select "Eclipse Platform" on the Product list (expand "Eclipse.org" node)
-  1. Choose "2018-12" as the product version at the bottom ![Chose Platform](https://raw.githubusercontent.com/lemmy/tlaplus/master/general/ide/images/00_PlatformSelection.png)
+  1. Choose "2019-09" from the Product Version combobox at the bottom ![Choose Platform](https://raw.githubusercontent.com/lemmy/tlaplus/master/general/ide/images/00_PlatformSelection.png)
+     1. You can try to use a more recent version of Eclipse, however if you run into troubles during the installation and set-up, choose "2019-09" instead.
 5. On the next screen, expand "Github Project" in the tree and select the check-box left to "TLA+" 
   1. Verify that "TLA+" shows up under "Project" at the bottom table and that the "Master" stream is selected ![Chose Project](https://raw.githubusercontent.com/lemmy/tlaplus/master/general/ide/images/01_ProjectSelection.png)
 6. On the next page, select whether to use anonymous Github access (read-only) from the "TLA+ Github Repository" dropdown list ![Chose anonymous access](https://raw.githubusercontent.com/lemmy/tlaplus/master/general/ide/images/02_Variables.png)
diff --git a/general/ide/TLA.setup b/general/ide/TLA.setup
index 0174e1d053971b46bd1a86e984c9a774c0b2542c..ab94371f5e86ded713abafa362c359114632652a 100644
--- a/general/ide/TLA.setup
+++ b/general/ide/TLA.setup
@@ -80,7 +80,7 @@
     <repository
         url="http://download.eclipse.org/technology/swtbot/releases/latest/"/>
     <repository
-        url="http://download.eclipse.org/tools/ajdt/47/dev/update/"/>
+        url="http://download.eclipse.org/tools/ajdt/48/dev/update/"/>
     <repository
         url="http://download.eclipse.org/technology/m2e/releases/"/>
     <repository
@@ -88,7 +88,7 @@
     <repository
         url="jar:https://dl.bintray.com/abstratt-oss/abstratt-oss/com/abstratt/eclipsegraphviz/com.abstratt.eclipsegraphviz.repository/2.5.201812/com.abstratt.eclipsegraphviz.repository-2.5.201812.zip!/"/>
     <repository
-        url="https://download.eclipse.org/rcptt/release/2.4.1/repository/"/>
+        url="https://download.eclipse.org/rcptt/release/2.4.3/repository/"/>
     <repository
         url="http://andrei.gmxhome.de/eclipse/"/>
     <description>Install the tools needed in the IDE to work with the source code for ${scope.project.label}</description>
@@ -185,7 +185,4 @@
       xsi:type="setup:ProjectCatalog"
       href="index:/org.eclipse.setup#//@projectCatalogs[name='com.github']"/>
   <description>TLA+ provides the tlatools and the TLA+Toolbox</description>
-  <setup:PreferenceTask
-      key="/instance/org.eclipse.ui/defaultPerspectiveId"
-      value="org.eclipse.jdt.ui.JavaPerspective"/>
 </setup:Project>
diff --git a/org.lamport.tla.toolbox.doc/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.doc/META-INF/MANIFEST.MF
index a5742ae4f249b81a93337cbe8ee153aeefadebf2..295f69de8b811a0dba9ca6c7320e24ac53dd025a 100644
--- a/org.lamport.tla.toolbox.doc/META-INF/MANIFEST.MF
+++ b/org.lamport.tla.toolbox.doc/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: TLA+ Toolbox Help
 Bundle-SymbolicName: org.lamport.tla.toolbox.doc; singleton:=true
-Bundle-Version: 1.5.4.qualifier
+Bundle-Version: 1.6.1.qualifier
 Bundle-RequiredExecutionEnvironment: J2SE-1.4
 Bundle-Vendor: Simon Zambrovski, Leslie Lamport
 Bundle-ActivationPolicy: lazy
diff --git a/org.lamport.tla.toolbox.doc/html/gettingstarted/preferences.html b/org.lamport.tla.toolbox.doc/html/gettingstarted/preferences.html
index 43b035b883868b9fafa40abc448fec7a2686640b..a5d60e488cc8d2b48f5b7da0d6d388e1c1c16355 100644
--- a/org.lamport.tla.toolbox.doc/html/gettingstarted/preferences.html
+++ b/org.lamport.tla.toolbox.doc/html/gettingstarted/preferences.html
@@ -80,6 +80,7 @@ Click on the appropriate item in the following list to see what options
 these preference pages provide you with.
 </P>
 <ul>
+<li> <A href="../model/model-editor-preferences.html"> Model Editor Preferences</A></li>
 <li> <A href="module-editor-preferences.html"> Module Editor Preferences</A></li>
 <li> <A href="../spec/pretty-printing.html"> PDF Viewer Preferences</A></li>
 <li> <A href="../spec/parsing.html"> TLA+ Parser Preferences </A></li>
diff --git a/org.lamport.tla.toolbox.doc/html/help-us/help-us.html b/org.lamport.tla.toolbox.doc/html/help-us/help-us.html
index eb3c398d94c3cebc2632d10b2ee3236f2c1c1b30..a7b30dc6271c5ac5e947be87a66a22e10b183be8 100644
--- a/org.lamport.tla.toolbox.doc/html/help-us/help-us.html
+++ b/org.lamport.tla.toolbox.doc/html/help-us/help-us.html
@@ -1,7 +1,7 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
 <!-- This is file org.lamport.tla.toobox.doc/html/help-us/help-us.html  -->
 
- 
+
 <html>
 <head>
 	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
@@ -14,33 +14,25 @@
 <body>
 <h1>Please Help Us</h1>
 
- <P> 
-The initial version of the
-TLA<sup>+</sup> Toolbox was designed and programmed almost entirely by
-Simon Zambrovski in less than a year.&nbsp;  The Toolbox is now being maintained and developed 
-by Daniel Ricketts.&nbsp;   Leslie Lamport has acted as mentor.
- </P>
+<p>
+Leslie Lamport has mentored the development of the TLA<sup>+</sup> Toolbox continually,
+while it has been developed by a small number of people over the years. The initial
+version was designed and implemented almost entirely by Simon Zambrovski in less
+than a year; followed by work done by Daniel Ricketts; followed by Markus Kuppe and
+others.
+</p>
 
 <p>
 The Toolbox is written as an Eclipse RCP (Rich Client Platform)
 application.&nbsp;  This has made it possible to implement a great deal of functionality
 in a fairly short time.&nbsp;  It has also led to compromises.&nbsp;  There are things
 we would like the Toolbox to do that it doesn't.&nbsp;  Some of the inadequacies
-are due to a lack of time; others are because we have been unable to 
+are due to a lack of time; others are because we have been unable to
 figure out how to implement them in Eclipse--either because Eclipse
 lacks the necessary functionality, or because we don't know how to do them
 in Eclipse.
 </p>
 
-<p>
-Another problem we have faced is the difficulty of debugging this kind
-of interactive application.&nbsp;  We have not had the time to do the kind
-of exhaustive testing that's needed to find and eliminate bugs.&nbsp;  
-In particular, we have not done much testing on platforms other than
-Windows.&nbsp;  We expect there to be many bugs that show up only on other
-platforms.
-</p>
-
 <p>
 We can use your help.&nbsp;  Let us know about problems you encounter
 or about any aspect
@@ -49,9 +41,10 @@ what important features you feel the Toolbox lacks.&nbsp;  Below is
 a list of some of the features we are thinking of adding.&nbsp;
 We probably won't have time to add them all, so we want
 to know which of them you would most like.&nbsp;  And we would
-love your help in debugging and developing the Toolbox.&nbsp;  
-Contact <a href="http://lamport.org" target="_blank">Leslie Lamport</a>
-with your feedback.
+love your help in debugging and developing the Toolbox.&nbsp;
+Contact us on the <a href="https://groups.google.com/forum/#!forum/tlaplus">Google
+Groups forum</a> or open a new issue <a href="https://github.com/tlaplus/tlaplus/issues">at
+GitHub.</a>
 </p>
 
 <h2>Some Features We May Add</h2>
@@ -60,7 +53,7 @@ with your feedback.
 
 A tutorial on specifying systems with TLA<sup>+</sup>
 and checking the specifications with the TLA<sup>+</sup> tools is being written.&nbsp;
-It is based on the Toolbox.&nbsp;  The current, highly incomplete version, is available;
+It is based on the Toolbox.&nbsp;  The current, incomplete version, is available;
 see the <a href="http://research.microsoft.com/en-us/um/people/lamport/tla/tla.html">TLA+ web site</a>.
 We do not know whether
 the tutorial will be incorporated within the Toolbox itself.
@@ -80,21 +73,13 @@ it to.</p>
 
 <h3>Support for the TLA<sup>+</sup> Proof System</h3>
 
-A TLA<sup>+</sup> proof checker is under development at the 
+A TLA<sup>+</sup> proof checker is under development at the
 <a href="http://www.msr-inria.inria.fr/Projects/tools-for-formal-specs">Microsoft Research-Inria Joint Centre</a>.&nbsp;
 We expect to add at least a basic level of support for writing and checking proofs within the Toolbox.
 
-<!-- delete rest of line to comment out 
-<dl>
-<dt><b><font color=#0000c0>Subtopics</font></b></dt>
-<dd> <A href=""> TOPIC </A></dd>
-<dd> <A href=""> TOPIC </A></dd>
-</dl>
- --> 
-<!-- delete rest of line to comment out -->  
-<hr> 
+<hr>
 <a href = "../contents.html">&uarr; TLA+ Toolbox User's Guide</a>
 </hr>
 
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/org.lamport.tla.toolbox.doc/html/model/creating-model.html b/org.lamport.tla.toolbox.doc/html/model/creating-model.html
index 40773dd549bc49b69ad2d6a425aaa255c4de0996..ecdfda6548d0052b0dfc239f049815bc82c63e75 100644
--- a/org.lamport.tla.toolbox.doc/html/model/creating-model.html
+++ b/org.lamport.tla.toolbox.doc/html/model/creating-model.html
@@ -1,7 +1,7 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
 <!-- This is file org.lamport.tla.toobox.doc/html/model/creating-model.html  -->
 
- 
+
 <html>
 <head>
 	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
@@ -14,15 +14,17 @@
 <body>
 <h1>Creating a Model</h1>
 
-<P> 
+<P>
 When you open a model, you open it in a <em>model editor</em>.&nbsp;  The model editor then
-shows two pages:  The  <A href="overview-page.html"> Model Overview Page</A> and
-the <A href="results-page.html"> Model Checking Results Page</A> that shows you either what 
-the model checker is doing while it runs, or what it did the last time it was
-run.&nbsp; The Model Overview Page contains links that open two other pages, 
-the  <A href="spec-options-page.html">Spec Options</A> and 
-<A href="tlc-options-page.html">TLC Options</A> pages that allow you to specify
-additional parameters for running TLC.&nbsp;
+shows only one page if the model has never been run before, and if it has been opened before,
+no other pages were kept open: &mdash; the  <A href="overview-page.html"> Model Overview Page.</A>
+<br/>
+If the model has been run before, the <A href="results-page.html"> Model Checking Results Page</A> will
+be opened showing what the checker did the last time it was
+run.&nbsp; The Model Overview Page contains links that open three other pages,
+the <A href="spec-options-page.html">Spec Options</A> page, the
+<A href="tlc-options-page.html">TLC Options</A> page, and the Results / Constant Expressions page(s)
+should you want to work with Constant Expressions having not yet run the model a first time.
 
 You can switch between the pages using the tabs at the upper-left of the
 model editor <a href="../gettingstarted/views.html">view</a>, or with the&nbsp;
@@ -33,22 +35,22 @@ model editor <a href="../gettingstarted/views.html">view</a>, or with the&nbsp;
 <p>You edit these pages in the usual way.&nbsp;  Sections can be opened or closed by clicking
 the&nbsp;
 <samp>+</samp>&nbsp; or&nbsp;
-<samp>-</samp>&nbsp;.  When entering text in fields, you can use your system's 
-standard editing commands.  
+<samp>-</samp>&nbsp;.  When entering text in fields, you can use your system's
+standard editing commands.
 </p>
 
 
 <p>Whenever you enter a TLA<sup>+</sup> expression as part of the model,
 that expression can use any
-symbols that you could use in a new definition placed at the end of the spec's root module.&nbsp;  
+symbols that you could use in a new definition placed at the end of the spec's root module.&nbsp;
 It can also contain any <a href="model-values.html">model values</a> that are declared
-in the model, as well as additional definitions entered in the  
-<a href="spec-options-page.html#additional">Additional Definitions</a> section 
+in the model, as well as additional definitions entered in the
+<a href="spec-options-page.html#additional">Additional Definitions</a> section
 of the Spec Options page.
 </p>
 
-<hr> 
-<!-- delete rest of line to comment out --> 
+<hr>
+<!-- delete rest of line to comment out -->
 <dl>
 <dt><b><font color=#0000c0>Subtopics</font></b></dt>
 <dd> <A href="overview-page.html"> Model Overview Page</A></dd>
@@ -57,11 +59,11 @@ of the Spec Options page.
 <dd> <A href="tlc-options-page.html">TLC Options Page</A></dd>
 
 </dl>
-<!-- --> 
-<!-- delete rest of line to comment out -->  
+<!-- -->
+<!-- delete rest of line to comment out -->
 <a href = "model.html">&uarr; Model Checking</a>
-<!-- --> 
+<!-- -->
 </hr>
 
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/org.lamport.tla.toolbox.doc/html/model/distributed-mode.html b/org.lamport.tla.toolbox.doc/html/model/distributed-mode.html
index 7daa46ff50c85153ead071abb48e94fb8a9d05e0..01e2148f189fc7fb2ffd205fb60b71ad16650537 100644
--- a/org.lamport.tla.toolbox.doc/html/model/distributed-mode.html
+++ b/org.lamport.tla.toolbox.doc/html/model/distributed-mode.html
@@ -1,7 +1,7 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
 <!-- This is file org.lamport.tla.toobox.doc/html/model/overview-page.html  -->
 
- 
+
 <html>
 <head>
     <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
@@ -29,7 +29,7 @@ Contents
 
 The TLA+ Toolbox has support to run distributed TLC in different modes (<i>ad hoc</i>, <i>Azure</i>, <i>aws-ec2</i>), which can be
 generalized into <i>ad hoc</i> mode and <i>Cloud Distributed TLC</i>. The former (ad hoc) runs
-TLC on a set of your own computers. It is up to you to install all necessary 
+TLC on a set of your own computers. It is up to you to install all necessary
 prerequisites (<a href="#how-it-works">see below</a>) on each of the computers. The latter mode (Cloud Distributed TLC)
 on the other hand, moves Distributed TLC into the <a href="https://en.wikipedia.org/wiki/Cloud_computing">cloud</a>
 and thus can automate all the install steps of ad hoc mode for you. It comes at the price service charges by the cloud compute providers.
@@ -45,15 +45,15 @@ and check invariants and other safety properties.&nbsp; There is also
 a master thread that coordinates the worker threads.&nbsp; In ordinary
 (non-distributed) mode, these threads all run on the same Java Virtual
 Machine (JVM) on the same computer as the Toolbox.&nbsp; In
-distributed mode, the threads can be run on multiple computers.&nbsp; 
+distributed mode, the threads can be run on multiple computers.&nbsp;
 The master thread runs on the same computer
-as the Toolbox--a computer we call here the <i>master computer</i>.&nbsp; 
+as the Toolbox--a computer we call here the <i>master computer</i>.&nbsp;
 The threads are run on a collection of <i>slave computers</i>.&nbsp;  Each
 slave computer can run multiple threads--the default is to run as many threads
 as it has processors (cores).
 
 <p>
-TLC keeps fingerprints of all states that it has found, which it uses to 
+TLC keeps fingerprints of all states that it has found, which it uses to
 determine if a newly computed state has already been examined.
 &nbsp;
 
@@ -65,9 +65,9 @@ on the master computer).
 
 </p>
 
-<p> 
+<p>
 Unless you're just trying it out, you're running TLC in
-distributed mode because your model is quite large.&nbsp;  
+distributed mode because your model is quite large.&nbsp;
 
 For any large model, it's a good idea to give TLC as much of the computer's memory
 as is not needed by the operating system and other programs that will
@@ -79,10 +79,10 @@ and on the master if slave fingerprint servers are not used.&nbsp;
 <a name="running-master"></a><h2>Running the Master</h2>
 
 <p>
-TLC is run on a <a href="creating-model.html">model</a>.&nbsp;  
+TLC is run on a <a href="creating-model.html">model</a>.&nbsp;
 
 To specify that it is to be run in distributed mode, select "ad hoc"
-in the <i>Run in distributed mode</i> drop down list in the 
+in the <i>Run in distributed mode</i> drop down list in the
 <a href="overview-page.html#how-to-run">How to run?</a>  section
 of the Model Overview Page.  That section also allows you to adjust
 the amount of memory allocated to the master.
@@ -112,8 +112,8 @@ that one or more workers have registered with the master.
 If you want TLC to store the fingerprint set among slave computers,
 you must run a (single) <i>fingerprint server</i> on each of them.&nbsp;
 Your model must tell TLC how many fingerprint servers it will use.&nbsp;  If you
-want fingerprints stored on 5 fingerprint servers (5 slave computers), you increase 
-the <i>Number of distributed fingerprint sets</i> spinner to 5. Setting it to 0, means 
+want fingerprints stored on 5 fingerprint servers (5 slave computers), you increase
+the <i>Number of distributed fingerprint sets</i> spinner to 5. Setting it to 0, means
 that the master will store the fingerprints. The master uses more memory in this mode.
 </p>
 
@@ -144,12 +144,12 @@ and <code>model-path</code> is is the complete pathname of the directory
 <pre>
    java  -cp tool-path  tlc2.tool.distributed.TLCServer  model-path/MC
 </pre>
-Like the  JVM argument <code>-cp tool-path</code>, other JVM arguments can come between <code>java</code> 
-and <code>tlc2.tool.distributed.TLCServer</code> in this command. TLC options follow 
+Like the  JVM argument <code>-cp tool-path</code>, other JVM arguments can come between <code>java</code>
+and <code>tlc2.tool.distributed.TLCServer</code> in this command. TLC options follow
 <code>model-path/MC</code>.
-<!-- 
- E.g. with the 
-<a href="executing-tlc.html#MC">model's subdirectory of the <code>.toolbox</code> directory</a> 
+<!--
+ E.g. with the
+<a href="executing-tlc.html#MC">model's subdirectory of the <code>.toolbox</code> directory</a>
 and the Toolbox's installation directory in /opt, the command line will look like:
 <pre>
    java -cp /opt/toolbox/plugins/org.lamport.tlatools_1.0.0.201211261208 -Dtlc2.tool.distributed.TLCServer.expectedFPSetCount=5 tlc2.tool.distributed.TLCServer /home/user/DieHard/DieHard.toolbox/Model_1/MC
@@ -179,92 +179,60 @@ or later, must also be installed on the machines.&nbsp;
 </p>
 
 <p>
-There are two basic ways to run a slave computer computer.&nbsp;  In the following instructions,
-<code>master-computer</code> is the name (or IP address) of the master computer.
-</p>
-
-<dl>
-<dt><b>Method 1</b></dt>
-<dd>
-Start the Toolbox on the master computer, and then run a Web browser
-on the worker computer.&nbsp;  In that web browser, enter the URL
-<pre>
-    http://master-computer:10996
-</pre> This will display a Web page containing  buttons to launch
-worker threads, a fingerprint server, or both on the slave.
-
-<p>
-You can launch the slaves with additional system properties and VM arguments
-by adding them to the URL.&nbsp; (When you launch a slave from a command line, 
-system properties [which begin with <code>-D</code>] and VM arguments are specified separately.)&nbsp; For example, the URL
-<pre>
-   http://localhost:10996/worker.jnlp?sysprops=-Diron.bar=5%20-Dfrob=2%20foo=&vmargs=-Xmx=512m%20-XX:MaxDirectMemorysize=512m
-</pre>
-causes the worker to be launched in a VM with VM arguments
-
-   <code>-XX:MaxDirectMemorysize=512m</code> and
-   <code>-Xmx=512m</code>
-   
-and system properties
-
-   <code>-Diron.bar=5</code> and
-   <code>-Dfrob=2</code>.
-
-
-</p> 
-
-<!-- COMMENTED OUT
-<i>Launch worker from browser</i>.&nbsp; Clicking on that will
-download the file <code>tla2tools.jar</code> and will execute it,
-starting the worker.  
-  END  COMMENTED OUT -->
-</dd> 
-<p> </P>
-<dt><b>Method 2</b></dt>
-
-<dd>
-Start the Toolbox on the master computer.&nbsp;  Then do the following on a
-shell on each slave computer:
-<pre>
-   wget http://master-computer:10996/files/tla2tools.jar
-</pre>   
-Then execute one of the following commands in that slave's shell:
-<ul>
-<li> To run just worker threads on the slave, execute:
-<pre>
-  java -cp tla2tools.jar tlc2.tool.distributed.TLCWorker master-computer
-</pre> 
-</li>
-
-<li> To run just a fingerprint server on the slave, execute:
-<pre>
-  java -cp tla2tools.jar tlc2.tool.distributed.fp.DistributedFPSet master-computer
-</pre>
-</li>
-
-<li> To run both worker threads and a fingerprint server on the slave, execute:
-<pre>
-  java -cp tla2tools.jar tlc2.tool.distributed.fp.TLCWorkerAndFPSet master-computer 
-</pre>
-</li>
-</ul>
-<p>
-The <code>wget</code> command downloads the file
-<code>tla2tools.jar</code> into the current directory on the worker
-machine, the <code>java</code> command actually starts the worker.&nbsp; The
-<code>wget</code> command therefore just has to be executed the first
-time you run a worker, and then whenever you install a new version of
-the Toolbox.&nbsp; The <code>wget</code> command is not part of
-Windows, but can be installed on Windows as part of Cygwin.  
-<p>
-
-<p>
-You can add JVM arguments to the <code>java</code> command, such as the argument 
-<code>-Xmx7G</code> that
-gives the slave 7 gigabytes of memory.  
+  Start the Toolbox on the master computer, and then open a web browser to the URL
+  <pre>
+      http://master-computer:10996
+  </pre>
+  where <code>master-computer</code> is the name (or IP address) of the master computer.
+  <br/>
+  <br/>
+  The resulting web page will have further instructions concerning running slaves, however the gist
+  of it is:
+  <br/>
+  <br/>
+  <dd>
+  Start the Toolbox on the master computer.&nbsp;  Then do the following on a
+  shell on each slave computer:
+  <pre>
+     wget http://master-computer:10996/files/tla2tools.jar
+  </pre>
+  Then execute one of the following commands in that slave's shell:
+  <ul>
+  <li> To run just worker threads on the slave, execute:
+  <pre>
+    java -cp tla2tools.jar tlc2.tool.distributed.TLCWorker master-computer
+  </pre>
+  </li>
+
+  <li> To run just a fingerprint server on the slave, execute:
+  <pre>
+    java -cp tla2tools.jar tlc2.tool.distributed.fp.DistributedFPSet master-computer
+  </pre>
+  </li>
+
+  <li> To run both worker threads and a fingerprint server on the slave, execute:
+  <pre>
+    java -cp tla2tools.jar tlc2.tool.distributed.fp.TLCWorkerAndFPSet master-computer
+  </pre>
+  </li>
+  </ul>
+  <p>
+  The <code>wget</code> command downloads the file
+  <code>tla2tools.jar</code> into the current directory on the worker
+  machine, the <code>java</code> command actually starts the worker.&nbsp; The
+  <code>wget</code> command therefore just has to be executed the first
+  time you run a worker, and then whenever you install a new version of
+  the Toolbox.&nbsp; The <code>wget</code> command is not part of
+  Windows, but can be installed on Windows as part of Cygwin.
+  <p>
+
+  <p>
+  You can add JVM arguments to the <code>java</code> command, such as the argument
+  <code>-Xmx7G</code> that
+  gives the slave 7 gigabytes of memory.
+  </p>
+  </dd>
 </p>
-</dd>
-</dl>
 
 <p>
 By default, each slave that runs workers runs as many worker threads
@@ -326,23 +294,23 @@ not practical.&nbsp; It is possible to implement scripts that can
 automate the installation of the JRE and one of the two methods
 described above for copying the <code>tla2tools.jar</code> file and
 starting the workers.&nbsp; How this is done will depend on the
-operating system and network configuration.&nbsp; 
-If you need help, try going to 
+operating system and network configuration.&nbsp;
+If you need help, try going to
 the <A href="https://groups.google.com/forum/?fromgroups#!forum/tlaplus">TLA+ Google group</a>.
- 
+
 If you have successfully run TLC in distributed mode, please use that
 Forum to tell others how you did it on your system.
-<hr> 
-<!-- delete rest of line to comment out 
+<hr>
+<!-- delete rest of line to comment out
 <dl>
 <dt><b><font color=#0000c0>Subtopics</font></b></dt>
 <dd> <A href="model-values.html"> Model Values and Symmetry </A></dd>
 <dd> <a href="distributed-mode.html">Running TLC in Distributed Mode</a></dd>
 </dl>
---> 
-<!-- delete rest of line to comment out -->  
+-->
+<!-- delete rest of line to comment out -->
 <a href = "overview-page.html">&uarr; Model Overview Page</a>
-<!-- --> 
+<!-- -->
 </hr>
 
 </body>
diff --git a/org.lamport.tla.toolbox.doc/html/model/executing-tlc.html b/org.lamport.tla.toolbox.doc/html/model/executing-tlc.html
index 1f68e2a256c769df6e46654f1c4904da5f29165a..12b5cc1daf059a55c3a15ed6b8e763cdde2b6c0f 100644
--- a/org.lamport.tla.toolbox.doc/html/model/executing-tlc.html
+++ b/org.lamport.tla.toolbox.doc/html/model/executing-tlc.html
@@ -159,6 +159,34 @@ be disabled until the user clicks on the "Restore" button.<br/>
 Additionally, formulas may be drag-reordered in the list.
 </p>
 
+<p>
+The error-trace explorer allows you to view the values of expressions in each step
+of the trace.&nbsp;  You just enter one or more expressions, which can contain
+primed as well as unprimed variables, and click on <samp>Explore</samp>.&nbsp;  The values
+of the expressions will then be shown in the error trace.&nbsp;  Clicking on
+<samp>Restore</samp> restores the original error trace. An error-trace expression may be
+given the name "id" by preceding it with "id ==".  This defines id to equal that expression
+in subsequent error-trace explorer expressions.
+</p>
+
+<p>
+The error-trace explorer allows you to form expressions from two built-in operators:
+The operators <code>_TETrace</code> and <code>_TEPosition</code> in an error-trace expression are defined
+as follows. When the expression is evaluated, <code>_TETrace</code> equals the sequence of records such that
+for every spec variable <code>v</code>, the value of <code>_TETrace[N].v</code> equals the value of v in
+state number <code>N</code> of the trace.  When the expression is evaluated in state number <code>N</code>,
+the operator <code>_TEPosition</code> equals <code>N</code>.
+</p>
+
+<p>
+The error-trace explorer works by running TLC on a file called&nbsp; <code>TE.tla</code>&nbsp;
+If there is an error in an expression that you entered in the error-trace
+explorer, then the Toolbox may report an error in that file.&nbsp;  The file is in the
+same folder as the file&nbsp; <code>MC.tla</code>&nbsp; described
+<a href="#MC">above</a>.&nbsp;  You may want to examine file&nbsp; <code>TE.tla</code>&nbsp;
+if you can't figure out what the error in the expression is.
+</p>
+
 <img src="ete_add_edit_explore.gif" style="max-width: 100%; height: auto;" />
 
 <p>
@@ -190,40 +218,59 @@ You can reverse the order, so the initial state appears last, by clicking on eit
 two column headings in the error trace display.&nbsp;  Clicking again restores the
 normal order.
 </p>
-<p>The trace viewer uses colors to indicate changes in the values of variables and in
+
+<p>
+The trace viewer uses colors to indicate changes in the values of variables and in
 the values of their subexpressions from one state to the next.&nbsp;  The color code is:
 </p>
-<dl>
-<dt><IMG SRC="changed.gif" Align="bottom"/> &nbsp; Value changed in this state.</dt><br></br>
 
-<dt><IMG SRC="added.gif" Align="bottom"/> &nbsp; Value added in this state.</dt><br></br>
+<p>
+The error trace can be filtered to omit variables and expressions from the displayed states,
+as well as hiding variables which have not had their values changed. By clicking on the filter button
+found to the left of the expand-hide all button, the user is presented with a a dialog allowing them
+to select from the set of variables and expressions found in the trace; alternatively, the user may
+ALT-click on a variable or expression in the Error-Trace tree view which will then omit that
+variable or expression.
+<br/>
+On this dialog, the user may also select the visibility of the variables:
+<ul>
+	<li><b>Show all variables:</b> will show all variables, changed and unchanged</li>
+	<li><b>Show only changed variables:</b> will show all variables that have changed at some
+		point during the trace, in each frame even if the value has not changed in that particular
+	  frame.</li>
+	<li><b>Show only changed variables in changed frames:</b> will show only variables that have
+		changed, and only in the frames in which they have changed. If that results in some frames
+	  that have no variables to display, those frames will not be displayed.</li>
+</ul>
+While variables are being filtered, a checkbox will be displayed above the variable
+value viewing text area allowing this area to display all the variables, or only the filtered
+variables, when a state is selected in the Error-Trace tree.
+<br/>
+Clicking on the filter button again will turn off the filtering.
+</p>
+
+<p>
+The background colors of the variables in this view change for the following cases:
+<dl>
+	<dt><IMG SRC="changed.gif"/></dt>
+	<dd style="margin-bottom: 9px;">Value changed in this state.</dd>
 
-<dt><IMG SRC="removed.gif" Align="bottom"/> &nbsp; Value removed from the next state.</dt>
+	<dt><IMG SRC="added.gif"/></dt>
+	<dd style="margin-bottom: 9px;">Value added in this state.</dd>
 
+	<dt><IMG SRC="removed.gif"/></dt>
+	<dd style="margin-bottom: 9px;">Value removed from the next state.</dd>
 </dl>
+</p>
 
 <p>
 The top line of a state's display in the error trace gives the location of the sub-action of the next-state
 relation that generated the state (except for the first state, which is generated by the
 initial predicate).&nbsp;
 Double-clicking on that line takes you to the indicated location.
-</p>
-
-<p>
-The error-trace explorer allows you to view the values of expressions in each step
-of the trace.&nbsp;  You just enter one or more expressions, which can contain
-primed as well as unprimed variables, and click on <samp>Explore</samp>.&nbsp;  The values
-of the expressions will then be shown in the error trace.&nbsp;  Clicking on
-<samp>Restore</samp> restores the original error trace.
-</p>
-
-<p>
-The error-trace explorer works by running TLC on a file called&nbsp; <code>TE.tla</code>&nbsp;
-If there is an error in an expression that you entered in the error-trace
-explorer, then the Toolbox may report an error in that file.&nbsp;  The file is in the
-same folder as the file&nbsp; <code>MC.tla</code>&nbsp; described
-<a href="#MC">above</a>.&nbsp;  You may want to examine file&nbsp; <code>TE.tla</code>&nbsp;
-if you can't figure out what the error in the expression is.
+<br/>
+Right-clicking on that line displays a context menu which allows the user to run model checking commencing
+from that described state.
 </p>
 
 <h2><a name="preferences">TLC Model Checker Preferences</a></h2>
@@ -249,13 +296,6 @@ The model is automatically saved when you run or validate it, so you will
 probably have no reason to save it explicitly.
 </p>
 
-<h3>Show Evaluate Constant Expression in its own tab</h3>
-<p>
-By default, the user can enter constant expressions to evaluate in a section on the Model Checking
-Results page; by selecting this option, this section will be moved to its own page
-within the Model Editor.
-</p>
-
 <h3>Number of model snapshots to keep</h3>
 <p>
 Re-running a model erases the corresponding model checking results if any. With snapshots
diff --git a/org.lamport.tla.toolbox.doc/html/model/model-editor-preferences.html b/org.lamport.tla.toolbox.doc/html/model/model-editor-preferences.html
new file mode 100644
index 0000000000000000000000000000000000000000..9ee3c27d067d634a63b72ac52d8a5683ca82091b
--- /dev/null
+++ b/org.lamport.tla.toolbox.doc/html/model/model-editor-preferences.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<!-- This is file org.lamport.tla.toobox.doc/html/model/model-editor-preferences.html  -->
+
+
+<html>
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <LINK href="../style.css" rel="stylesheet" type="text/css">
+
+<title>Model Editor Preferences</title>
+</head>
+
+<body>
+<h1>Model Editor Preferences</h1>
+
+<h3>Show Evaluate Constant Expression in its own tab</h3>
+<p>
+By default, the user can enter constant expressions to evaluate in a section on the Model Checking
+Results page; by selecting this option, this section will be moved to its own page
+within the Model Editor.
+</p>
+
+<h3>Definition Override display style</h3>
+<p>
+The Definition Override display on the Spec Options tab of the model editor can display definitions
+referenced from the primary specification in either the display format of:
+<ul>
+	<li style="font-family: monospace;">Definition [Module Name]</li>
+	<li style="font-family: monospace;">InstanceVariable!Definition</li>
+</ul>
+where, in the latter, <span style="font-family: monospace;">InstanceVariable</span>
+is defined in specification such as
+<span style="font-family: monospace;">InstanceVariable == INSTANCE ModuleName WITH ...</span>
+<br/>
+This style definition also carries over to the display shown when adding a new override in
+this section.
+</p>
+
+<hr>
+<a href = "model.html">&uarr; Model Checking</a>
+</hr>
+
+</body>
+</html>
diff --git a/org.lamport.tla.toolbox.doc/html/model/profiling.html b/org.lamport.tla.toolbox.doc/html/model/profiling.html
index 1dcc46ed239658a191c27ff4703afa8b428fef3c..0baaa1216542b6b127c84d35465a69b704157b6a 100644
--- a/org.lamport.tla.toolbox.doc/html/model/profiling.html
+++ b/org.lamport.tla.toolbox.doc/html/model/profiling.html
@@ -44,7 +44,7 @@ More concretely, its cost equals the number of operations
 required by the model checker to enumerate the powerset of S. 
 Users can override such  operators with more efficient variants. 
 Specifically, TLC allows  operators to be overridden with Java 
-code which can usually be evaluated orders of magnitudes faster.
+code which can often be evaluated orders of magnitudes faster.
 </p>
 <p>
 Evaluation metrics are captured globally and at the call-chain 
@@ -52,7 +52,7 @@ level. In other words, the metrics for an expression such as a
 operator, that occurs in two or more expressions, will be 
 reported individually for each occurrence. Metrics are 
 furthermore sensitive to constants such that the change of a 
-constant value — across model checker runs — will be detectable 
+constant value - across model checker runs - will be detectable 
 in the metrics unless the constant has no influence at all.
 </p>
 <p>
@@ -99,7 +99,7 @@ selects the corresponding expression." height="600" width="700" class="center">
 </ul>
 
 <hr> 
-<a href = "overview-page.html">&uarr; Model Overview Page</a>
+<a href = "tlc-options-page.html">&uarr; TLC Options Page</a>
 </hr>
 
 </body>
diff --git a/org.lamport.tla.toolbox.doc/html/model/results-page.html b/org.lamport.tla.toolbox.doc/html/model/results-page.html
index 14a03a6959d6a1c2f0b7c905dd41f09f5be2026c..69dcf422111f2949b0199d6012558db032aaab4e 100644
--- a/org.lamport.tla.toolbox.doc/html/model/results-page.html
+++ b/org.lamport.tla.toolbox.doc/html/model/results-page.html
@@ -88,24 +88,24 @@ of the reachable states.&nbsp;  For most behavior specs, the graph of the queue
 is a convex curve that grows to a maximum and then decreases. 
 </p>
 
-<h3>Coverage</h3>
+<h3>Sub-Actions of next-state</h3>
 <p>
 A common error in writing a behavior spec is for an action not to be enabled when
 it should be, so the spec cannot reach states that represent reachable states of
 the actual system being specified.&nbsp;  This kind of error leads to a violation of desired
-liveness properties, but does not cause any violation of safety.&nbsp;  The coverage
+liveness properties, but does not cause any violation of safety.&nbsp;  The action
 statistics give you a way of catching such an error even if you're not
 checking liveness.&nbsp;
 </p>
 
-<p>Coverage shows the number of times each sub-action of the next-state relation
-has been used to compute a successor state.&nbsp;
-Don't worry about how TLC decides
-what a sub-action is; just look at the values reported and the corresponding parts of
-the specification to which they refer.&nbsp;  A sub-action that is executed zero times
-- emphasized by yellow background coloring of the table row - usually indicates an
-error in the spec. &nbsp; Left-clicking on an entry takes you to the indicated
-location.
+<p>Sub-Actions of next-state shows the number of states generated by each sub-action of 
+the next-state relation.  Don't worry about how TLC decides what a 
+sub-action is; just look at the values reported and the corresponding 
+parts of the specification to which they refer.  A sub-action that
+generates no states - emphasized by yellow background coloring of the
+table row - usually indicates an error in the spec.&nbsp; 
+Double-clicking on an entry takes you to the indicated location.  The time shown 
+above the table indicates the execution time the numbers were recorded.
 </p>
 
 <h2><a name="evaluate">Evaluate Constant Expression</a> </h2>
diff --git a/org.lamport.tla.toolbox.doc/html/pluscal/pluscal.html b/org.lamport.tla.toolbox.doc/html/pluscal/pluscal.html
index dc6caab6538d63fc769a5c4b1e34d6bfcd753144..aec109d10a3bfc969679b9803de27b11e9ac4525 100644
--- a/org.lamport.tla.toolbox.doc/html/pluscal/pluscal.html
+++ b/org.lamport.tla.toolbox.doc/html/pluscal/pluscal.html
@@ -7,81 +7,101 @@
 
 <title>The PlusCal Translator</title>
 </head>
-<!-- a comment -->
 
 <body>
 <h1>The PlusCal Translator</h1>
 
- <P> 
+ <P>
 PlusCal is an algorithm language based on TLA<sup>+</sup>.&nbsp;  A PlusCal algorithm is written as a comment
-in a TLA<sup>+</sup> module.&nbsp;  The PlusCal translator writes the TLA<sup>+</sup> translation of the algorithm into
+in a TLA<sup>+</sup> module.
+<br/>
+<b>Please note:</b> In order to have the editor provide code folding for your PlusCal algorithm,
+the <samp>--algorithm</samp> or <samp>--fair</samp> must be preceded by a <samp>(*</samp> starting
+in column 0 on the same or a previous line. If you attempt to insert other comment blocks before the
+algorithm keyword, but after what you intend to be the start of your PlusCal algorithm 'block', make
+sure they do not start in column 0. Additionally, the closing
+comment of the PlusCal algorithm block should be one or more <samp>*</samp> starting in column 0 and
+terminating the line with a <samp>)</samp>.
+</br>
+The PlusCal translator writes the TLA<sup>+</sup> translation of the algorithm into
 the module.&nbsp;  See the <a href="http://research.microsoft.com/en-us/um/people/lamport/tla/pluscal.html" target="_blank"> PlusCal
 web page</a> for more information about PlusCal, including a language manual.&nbsp;  An overview of the
-language is provided by the paper 
-<a href="http://research.microsoft.com/en-us/um/people/lamport/pubs/pubs.html#pluscal" target="_blank">The 
-PlusCal Algorithm Language</a>.  
+language is provided by the paper
+<a href="http://research.microsoft.com/en-us/um/people/lamport/pubs/pubs.html#pluscal" target="_blank">The
+PlusCal Algorithm Language</a>.
  </P>
- 
+
  <p>
  You run the PlusCal translator on the module in the currently selected
- module editor by clicking 
-  on&nbsp; <samp>File/Translate PlusCal Algorithm</samp> or typing  <samp>Control+t</samp>&nbsp;
- Translation errors are displayed in  
-    the same&nbsp; <samp>Parsing Error</samp>&nbsp; view where <a href="../spec/parsing.html">TLA<sup>+</sup> parsing
-    errors</a> are displayed.&nbsp;  Some errors in a PlusCal algorithm are not found by the translator, but
-    instead produce parsing errors in the TLA<sup>+</sup> module.&nbsp;  Those are displayed as ordinary TLA<sup>+</sup> parsing errors.
+ module editor by clicking on&nbsp; <samp>File/Translate PlusCal Algorithm</samp>
+ or typing <samp>CTRL t</samp> / <samp>&#8984; t</samp>&nbsp;
+ <br/>
+ Translation errors are displayed in the same&nbsp; <samp>Parsing Error</samp>&nbsp; view where
+ <a href="../spec/parsing.html">TLA<sup>+</sup> parsing errors</a> are displayed.&nbsp; Some errors
+ in a PlusCal algorithm are not found by the translator, but instead produce parsing errors in the
+ TLA<sup>+</sup> module.&nbsp;  Those are displayed as ordinary TLA<sup>+</sup> parsing errors.
+ <br/>
+ The translation produces two checksums which are included in the translation comment delimiters, for example:
+ <ul>
+	 <li><samp>\** BEGIN TRANSLATION PCal-5cc64096184dcd2bcb0741a5056a664a</samp></li>
+	 <li><samp>\** END TRANSLATION TLA-6aeb9b3874fd3c001211b4a5b3da8249</samp></li>
+ </ul>
+ If changes are made to the PlusCal code, or generated TLA code, after translation, the user
+ will receive a warning dialog when they attempt to run model checking.  If the user would like
+ to make a change to the TLA code and not be warned, they can remove the <samp>TLA-...</samp>
+ checksum comment text from their spec.
  </p>
- 
+
  <p>
  The <a href="../spec/editing-modules.html#finding-pcal"><em>Goto PCal Source</em></a> command allows you to jump
  from a region in the TLA<sup>+</sup> translation to the PlusCal code that generated it.&nbsp;  This makes it
  easy to find the source in the algorithm of an error found in its translation.
 
  </p>
- 
+
  <p>The current version of Pluscal allows you to specify most translator options in an
  <samp>options</samp> statement within the module's <code>.tla</code> file.&nbsp;
- 
+
  You can also set translator options by opening the&nbsp;
- <samp>Spec Explorer</samp>&nbsp; view (see the 
+ <samp>Spec Explorer</samp>&nbsp; view (see the
  <a href="../spec/opening-closing.html"><em>Manipulating Specs</em></a>  help page), right-clicking on the spec,
  choosing&nbsp; <samp>Properties</samp>, and entering the desired options in
- the&nbsp; <samp>PlusCal call arguments</samp>&nbsp; field.&nbsp;  
- 
+ the&nbsp; <samp>PlusCal call arguments</samp>&nbsp; field.&nbsp;
+
  This is the only way to specify translator options that cannot be put in
  the <samp>options</samp> statement.&nbsp;  (However, you are unlikely to want
  to use those options.)
  </p>
- <!--  
+ <!--
  <p>
  The Toolbox now provides only one PlusCal translator preference.&nbsp;  You can have the translator
  automatically called when you modify and then save a module containing a PlusCal algorithm.&nbsp;
  (More precisely, it is called if the module contains the text &nbsp; <code>--algorithm</code>&nbsp;
  anywhere within it.)&nbsp;  You can set it by selecting
- the&nbsp; <samp>PlusCal Translator Preferences</samp>&nbsp; page 
- from among the 
- TLA<sup>+</sup> Preferences.&nbsp; (See the 
+ the&nbsp; <samp>PlusCal Translator Preferences</samp>&nbsp; page
+ from among the
+ TLA<sup>+</sup> Preferences.&nbsp; (See the
  <a href="../gettingstarted/preferences.html"><em>Preferences</em></a> help page.)&nbsp;
  The default is not to translate on save.
  </p> -->
-<!--  
-<hr> 
+<!--
+<hr>
 -->
-<!-- delete rest of line to comment out 
+<!-- delete rest of line to comment out
 <dl>
 <dt><b><font color=#0000c0>Subtopics</font></b></dt>
 <dd> <A href=""> TOPIC </A></dd>
 <dd> <A href=""> TOPIC </A></dd>
 </dl>
- --> 
-<!-- delete rest of line to comment out 
+ -->
+<!-- delete rest of line to comment out
 <a href = ".html">&uarr; HIGHER_LEVEL_TOPIC</a>
---> 
-<!--  
+-->
+<!--
 </hr>
 -->
 <hr>
 <a href = "../contents.html">&uarr; TLA+ Toolbox User's Guide</a>
 </hr>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/org.lamport.tla.toolbox.doc/html/prover/no_tlapm.png b/org.lamport.tla.toolbox.doc/html/prover/no_tlapm.png
new file mode 100644
index 0000000000000000000000000000000000000000..9f2d6106c85a2895b011d16366cae54011101a77
Binary files /dev/null and b/org.lamport.tla.toolbox.doc/html/prover/no_tlapm.png differ
diff --git a/org.lamport.tla.toolbox.doc/html/prover/runningTlaps.html b/org.lamport.tla.toolbox.doc/html/prover/runningTlaps.html
index 8598fbe9f5f5f1922a76e6f0e0250a2bdef85c65..80ba6477bc4e1502d68067307490f6ef96c9a22e 100644
--- a/org.lamport.tla.toolbox.doc/html/prover/runningTlaps.html
+++ b/org.lamport.tla.toolbox.doc/html/prover/runningTlaps.html
@@ -31,26 +31,26 @@ Contents
 <h2><a name="works">How TLAPS Works</a></h2>
 
 <p>
-TLAPS consists of a <i>Proof Manager</i> (PM) and various 
+TLAPS consists of a <i>Proof Manager</i> (PM) and various
 <i>back-end provers</i>.&nbsp;
 
-In TLA+, a proof of a theorem or proof step is either a leaf proof or a 
+In TLA+, a proof of a theorem or proof step is either a leaf proof or a
 sequence of steps, each of which may have a proof.&nbsp;
 
 
-The PM translates a proof into a collection of 
+The PM translates a proof into a collection of
 <i>obligations</i> whose correctness implies
-the correctness of the proof.&nbsp;  
+the correctness of the proof.&nbsp;
 
 A proof's obligations include the obligations of each subproof.&nbsp;
 
 The PM calls one or more back-end provers to prove the obligations.&nbsp;
-It then displays with colors the proof status of of each theorem or 
+It then displays with colors the proof status of of each theorem or
 proof step whose
 proof it has checked.&nbsp;
 
 The proof status of a step or theorem is determined by which of its proof's
-obligations the back-end provers succeeded in proving.&nbsp;  
+obligations the back-end provers succeeded in proving.&nbsp;
 
 The section titled <a href="#status-display">How the Toolbox Displays the Status of Proofs</a>
 explains how you can completely customize the colors and their significance.
@@ -62,6 +62,20 @@ explains how you can completely customize the colors and their significance.
 
 <h2><a name="running">Running the Proof Manager</a></h2>
 
+<p>
+Foremost, see the TLA+ Preferences &rarr; TLAPS preference page and assure that the Toolbox knows
+where your tlapm has been installed; if it doesn't, you will see a notification like:
+<br/>
+<img src="no_tlapm.png" style="max-width: 100%; width: auto; height: auto;"/>
+<br/>
+If this is the case, click on the Browse... button and locate your executable.
+</p>
+
+<p>
+	<b>Note:</b> if the spec currently has syntax or other problems which prevent it from being
+	successfully parsed, the abilty to use the proof manager will remain disabled until the
+	spec is correct and successfully parsed.
+</p>
 
 <p>
 To tell the PM to check the proof of a theorem or step,
@@ -79,7 +93,7 @@ The PM can be executed with various options.&nbsp;
 You will probably want to use only the default options.&nbsp;
 
 Some that you might want to change for regular use can be set with
-prefences, as described in the 
+prefences, as described in the
 <a href="#advanced">Advanced Execution Preferences</a> subsection below.&nbsp;
 
 Even more esoteric PM options can be invoked using the <i>Launch Prover</i>
@@ -91,7 +105,7 @@ The PM remembers the outcome of the back-end provers' attempts to prove
 each obligation.&nbsp;
 
 If the PM finds that an obligation has already been proved, its default
-behavior is to 
+behavior is to
 accept it as true and not send it again to a back-end prover.&nbsp;
 
 Checking if an obligation has already been proved is fast, so there is no
@@ -101,7 +115,7 @@ harm telling the PM to prove something it has already proved.&nbsp;
 <p>
 If something mysterious happens when running the PM and you think
 something has gone wrong, you can try looking at the TLAPM
-console, which you can display by using the 
+console, which you can display by using the
 &nbsp;<samp>TLA Proof Manager</samp>&nbsp; menu at the top
 of the Toolbox window.&nbsp;  It shows the output that
 the PM sends to the Toolbox.
@@ -116,13 +130,13 @@ As explained <a href="#interesting">below</a>, the Toolbox shows obligations tha
 prover has been trying to prove for a while.&nbsp;
 
 You can tell PM to stop proving that obligation by clicking on the <i>Stop Proving</i>
-button at the top of the obligation.&nbsp;  
+button at the top of the obligation.&nbsp;
 
 You can stop the entire execution by clicking on the <i>Cancel</i> button of the
 <i>Prover Launch</i> dialog.
 </p>
 <p>Note: If you check <i>Always run in background</i> on the <i>Prover Launch</i> dialog,
-that dialog will stop popping up when you run the PM.&nbsp;  
+that dialog will stop popping up when you run the PM.&nbsp;
 
 To get it back, go to <code>File/Preferences/General</code> and uncheck the
 <i>Always run in background</i> preference.</p>
@@ -132,10 +146,10 @@ To get it back, go to <code>File/Preferences/General</code> and uncheck the
 <h3><a name="obligations">The Status of Obligations</a></h3>
 <p>
 The PM displays with colors the proof status of steps and theorems
-whose proofs it checks.&nbsp; 
+whose proofs it checks.&nbsp;
 
 The status of a step or theorem depends on the results of checking its
-proof obligations.&nbsp;  
+proof obligations.&nbsp;
 
 For each back-end prover and each obligation, there are five possible
 statuses of the checking of that obligation by that prover:
@@ -165,12 +179,12 @@ TLA+ allows the leaf "proof":
    OMITTED
 </pre>
 which indicates that the user has explicitly chosen to omit the proof.&nbsp;
- 
+
 In this case, the step is considered to have a dummy obligation whose status
-is <b>omitted</b>.&nbsp;  
+is <b>omitted</b>.&nbsp;
 
 TLA+ also allows incomplete proofs in which some proofs are
-missing, usually because they have yet to be written.&nbsp; 
+missing, usually because they have yet to be written.&nbsp;
 
 In this case, the step is considered to have a dummy obligation whose
 status is <b>missing</b>.&nbsp;
@@ -188,15 +202,15 @@ true or false, depending on the statuses of the step's proof obligations.&nbsp;
 The step is colored with the lowest-numbered color whose color predicate
 is true, or is left uncolored if all the color predicates are false.&nbsp;
 
-Here is a picture of the main TLAPS preference page showing the 12 
+Here is a picture of the the TLAPS &rarr; Color Predicates preference page showing the 12
 colors and their default color predicates:
 </p>
 <pre>
-     <IMG SRC=color-predicates.gif Align=bottom> 
+     <IMG SRC=color-predicates.gif Align=bottom>
 </pre>
 <p>
 The predicate for color 4 is true if and only if the user stopped
-a back-end prover while it was proving one of the 
+a back-end prover while it was proving one of the
 proof's obligations.&nbsp;
 
 The predicate for color 7 is true if and only if every obligation of the
@@ -225,7 +239,7 @@ leaf steps (or theorems)--ones with no substeps--by checking the
 &nbsp;<samp>Applies to Leaf Steps Only</samp>&nbsp; field.&nbsp;
 
 The &nbsp;<samp>Show Leaf Steps in Side Bar</samp>&nbsp; field indicates if leaf steps
-colored with that logical color should be highlighted by a mark on the 
+colored with that logical color should be highlighted by a mark on the
 right-hand side of the
 module editor, next to the appropriate point in the vertical scroll bar.&nbsp;
 
@@ -245,12 +259,12 @@ on the preference page.&nbsp;
 <h3><a name="interesting">Interesting Obligations</a></h3>
 
 <p>
-When checking a proof, the Toolbox displays <i>interesting obligations</i> 
-in a separate window.&nbsp;  
+When checking a proof, the Toolbox displays <i>interesting obligations</i>
+in a separate window.&nbsp;
 
 Here is what can make an obligation interesting:
 <ul>
-<li>Some prover has failed to prove it.&nbsp;  
+<li>Some prover has failed to prove it.&nbsp;
 
 The obligation can stop being interesting (and no longer displayed)
 if the PM starts another prover to try proving it.&nbsp;
@@ -259,13 +273,13 @@ if the PM starts another prover to try proving it.&nbsp;
 <br></br>
 
 <li>Some prover has been proving it for some period of time (by default,
-about 15 seconds).&nbsp;  
+about 15 seconds).&nbsp;
 
 In this case, you can stop the prover's attempt to prove
 that obligation by clicking on the <samp>Stop Proving</samp> button
 at the top of the obligation.&nbsp;
 
-The obligation stops being interesting if the prover succeeds in 
+The obligation stops being interesting if the prover succeeds in
 proving it.
 </li>
 </ul>
@@ -275,9 +289,9 @@ that generated the obligation.&nbsp;
 
 <p>
 The obligation is a TLA+ representation of the exact mathematical fact
-that the back-end prover is required to prove.&nbsp;  
+that the back-end prover is required to prove.&nbsp;
 
-The back-end prover sees nothing except what the displayed obligation 
+The back-end prover sees nothing except what the displayed obligation
 contains.&nbsp;
 
 For example, suppose your specification defines <code>Two</code> by
@@ -287,8 +301,8 @@ For example, suppose your specification defines <code>Two</code> by
 A back-end prover will have no way of proving the obligation
 <pre>
    1+1 = Two
-</pre> 
-because it has no idea what <code>Two</code> means.&nbsp;  
+</pre>
+because it has no idea what <code>Two</code> means.&nbsp;
 
 A proof that generates this obligation is incorrect because it fails
 to indicate that the definition of <code>Two</code> must be used.&nbsp;
@@ -302,7 +316,7 @@ to be checked or you have canceled the command from the <i>Prover Launch</i>
 dialog, the colors shown in the module editor reflect the correct status
 of the proof(s) that were checked.&nbsp;
 
-Making a change to the module can change the obligations the PM 
+Making a change to the module can change the obligations the PM
 generates for a proof, changing the proof status of steps.&nbsp;
 
 For example, changing the definition of a symbol is likely to change
@@ -311,13 +325,13 @@ the obligations for the proof of any formula containing that symbol.&nbsp;
 A step's color is not changed to reflect changes to the module.&nbsp;
 
 You can edit the module while running a proof, but the proof is performed
-on the module as it was when TLAPS was launched.&nbsp; 
+on the module as it was when TLAPS was launched.&nbsp;
 
 
 </p>
 <p>
 Calling the PM to check the proof of a step (or a proof containing that
-step)  causes the step's color to be updated appropriately.&nbsp; 
+step)  causes the step's color to be updated appropriately.&nbsp;
 
 (Remember that this entails no further proving if the proof's obligations
 have not changed.)&nbsp;
@@ -337,13 +351,13 @@ status of its obligations obtained from proofs it has already attempted.&nbsp;
 
 <p>
 You can edit the module while the <i>Check Status</i> command is
-running.&nbsp;  
+running.&nbsp;
 
 You can therefore issue the command to update the status of all the module's
 proofs and let it run while you continue editing a proof.&nbsp;
 
 A step's color will be determined by the module's contents when the
-command was issued.&nbsp;  
+command was issued.&nbsp;
 
 </p>
 
@@ -353,9 +367,9 @@ There are some errors in a proof that are detected by the PM before sending a pr
 to the back-end provers.&nbsp;
 
 These can be actual mistakes in the proof--for example, using a <code>TAKE</code> step when the
-current goal is not a universally quantified formula.&nbsp;  
+current goal is not a universally quantified formula.&nbsp;
 
-They can also be TLA+ features not supported by TLAPS, such as quantification over tuples, as in 
+They can also be TLA+ features not supported by TLAPS, such as quantification over tuples, as in
 &nbsp;<code> \A &lt;&lt;x, y, z&gt;&gt; \in S : ...</x></code>&nbsp;.
 </p>
 
@@ -370,8 +384,7 @@ which can be displayed from the <em>TLA Proof Manager</em> menu.
 
 <h2><a name="advanced-topics">Advanced Topics</a></h2>
 <h3><a name="advanced">Advanced Execution Preferences</a></h3>
-The <i>Additional Preferences</i> subpage of the main <i>TLAPS</i>
-preference page allows you to specify the following Proof Manager
+The <i>TLAPS &rarr; Other Preferences</i> preference page allows you to specify the following Proof Manager
 options.
 
 <dl>
@@ -391,11 +404,11 @@ prover.&nbsp;
 
 This option tells the PM what SMT solver to use.&nbsp;
 
-See the  
+See the
 <a href=
   "https://tla.msr-inria.inria.fr/tlaps/content/Documentation/Tutorial/Tactics.html#solvers"
  target="_blank">SMT solvers</a>
-section of the 
+section of the
 <a href=
   "https://tla.msr-inria.inria.fr/tlaps/content/Documentation/Tutorial/Tactics.html"
  target="_blank">Tactics page</a>.&nbsp;
@@ -407,20 +420,20 @@ option.)
 
 <dt>Do not trust previous results from earlier versions of provers</dt>
 
-<dd>Selecting this option causes the PM to forget about previous results 
+<dd>Selecting this option causes the PM to forget about previous results
 of checking obligations obtained by
 earlier versions of back-end provers.&nbsp;
 
 You would select this option and redo your proofs if you are afraid that
-bugs in an earlier version of one of the back-end provers could have 
-caused it to report that it had proved an incorrect obligation. 
+bugs in an earlier version of one of the back-end provers could have
+caused it to report that it had proved an incorrect obligation.
 </dd>
 </dl>
 <h3><a name="launch">The Launch Prover Command</a></h3>
 
-The <i>Launch Prover Command</i> (<code>Ctl+G Ctl+P</code>) can be 
+The <i>Launch Prover Command</i> (<code>Ctl+G Ctl+P</code>) can be
 used to execute the PM with options that cannot be specified by using
-the ordinary <i>Prove Step Or Module</i> command with appropriate preference 
+the ordinary <i>Prove Step Or Module</i> command with appropriate preference
 settings.&nbsp;
 
 Issuing this command raises a dialog with which you choose the PM options
@@ -428,14 +441,14 @@ from the following selections.&nbsp;
 
 <h4>Launch in Toolbox Mode</h4>
 
-This is the normal option.&nbsp;  It causes the PM to determine 
+This is the normal option.&nbsp;  It causes the PM to determine
 what proof(s) it checks just as it does for the ordinary
 <i>Prove Step or Module</i> command.&nbsp;
 
 Without it (or appropriate options provided in the
 <i>Enter additional tlapm command-line arguments</i> field),
 the PM will check the entire module and will uncolor all proof
-steps. 
+steps.
 
 <h4>Chose prover(s) to use</h4>
 You must choose one of these options:
@@ -456,7 +469,7 @@ by Zenon.</dd>
 <br></br>
 
 <dt>Do not use Isabelle</dt>
-<dd>The PM will use Zenon or any other backend prover it should 
+<dd>The PM will use Zenon or any other backend prover it should
 except Isabelle.&nbsp;
 
 It will not use Isabelle even if the proof specifies that an
@@ -476,7 +489,7 @@ Accept the results previously obtained by back-end provers.&nbsp;
 This means that a back-end prover will not be called to prove
 an obligation if it already succeeded or failed when trying to
 prove the obligation.&nbsp;
- 
+
 This is the normal option.&nbsp;</dd>
 <br></br>
 
@@ -494,17 +507,17 @@ results of all previous attempts by back-end
 provers to prove obligations of the currently-selected
 proof(s).&nbsp;
 
-If you think that the PM has gotten confused about 
+If you think that the PM has gotten confused about
 the proof status of an obligation, use this option together with
 the <i>No proving</i>
-option to get it to forget the status and do nothing else. 
+option to get it to forget the status and do nothing else.
 
 </dd>
 </dl>
 
 <h4>Paranoid checking</h4>
 
-This tells the PM to call Isabelle to prove 
+This tells the PM to call Isabelle to prove
 obligations that the PM believes are trivially true and don't need
 to be proved.
 
@@ -516,7 +529,7 @@ Do not even think of using this field unless you know what
 command-line options tlapm accepts.&nbsp;
 
 The field allows you to write additional
-options exactly 
+options exactly
 the way they are written as command-line
 options for tlapm.&nbsp;
 
@@ -528,7 +541,7 @@ made in the rest of the dialog.&nbsp;
 If you are thinking about using this field,
 you can probably figure out what those options are.&nbsp;
 
-However, you will probably want to specify all the options yourself in 
+However, you will probably want to specify all the options yourself in
 this field.&nbsp;
 
 To cause the preference page to generate no options, use the default
@@ -544,10 +557,9 @@ select only &nbsp;<samp>Do not use Isabelle</samp>&nbsp; and
 <h3><a name="user-defined">User-Defined Color Predicates</a></h3>
 
 <p>
-The <i>Additional Preferences</i> subpage of the main <i>TLAPS</i>
-preference page allows you to define color predicates.&nbsp; 
+The <i>TLAPS &rarr; Other Preferences</i> preference page allows you to define color predicates.&nbsp;
 
-You can define almost any color predicate you might want.&nbsp; 
+You can define almost any color predicate you might want.&nbsp;
 
 Here is a complete explanation of how.&nbsp;
 
@@ -560,13 +572,13 @@ you want.
 
 </p>
 <p>
-At any time, an obligation has a <i>state</i>.&nbsp; 
+At any time, an obligation has a <i>state</i>.&nbsp;
 For the dummy obligation representing a missing proof or
 the proof <code>OMITTED</code>,
-its state 
+its state
 is either <code>missing</code> or <code>omitted</code>.&nbsp; An ordinary proof
 obligation's state consists of a status for each prover.&nbsp;
-We consider there to be three provers: 
+We consider there to be three provers:
 <ul>
  <li>Isabelle</li>
 
@@ -575,11 +587,11 @@ any SMT backend prover</li>
  <li>The PM itself, which is considered to prove
      obligations that it finds trivial.
  </li>
-</ul> 
+</ul>
 
-The possible statuses of these provers are: 
+The possible statuses of these provers are:
 
-<ul> 
+<ul>
 
 <li>Isabelle: <code>untried</code>, <code>proving</code>,
 <code>proved</code>, <code>failed</code>, <code>stopped</code> </li>
@@ -590,7 +602,7 @@ The possible statuses of these provers are:
 
 </ul>
 The state of an ordinary obligation is written as a triple
-such as <code>(proving</code>, <code>failed</code>, <code>none)</code>, 
+such as <code>(proving</code>, <code>failed</code>, <code>none)</code>,
 where the value of the <i>i</i><sup>th</sup> element
 is the obligation's proof status for the <i>i</i><sup>th</sup> prover.
 </p>
@@ -613,17 +625,17 @@ A color predicate is specified by a string with the following syntax
 <pre>
    &lt;color-predicate&gt; ::=  ["every" | "some"] &lt;state-set&gt;*
 
-   &lt;state-set&gt; ::= "missing" | "omitted" 
+   &lt;state-set&gt; ::= "missing" | "omitted"
                      | "(" &lt;statuses&gt; "," &lt;statuses&gt; "," &lt;statuses&gt; ")"
 
-   &lt;statuses&gt; ::=  &lt;status&gt;* | "-" &lt;status&gt;+ 
+   &lt;statuses&gt; ::=  &lt;status&gt;* | "-" &lt;status&gt;+
 </pre>
 
 Each <code>&lt;state-set&gt;</code> specifies a set of states, and a
 sequence of <code>&lt;state-set&gt;</code>s specifies their union.&nbsp;
 
 The <code>&lt;state-set&gt;</code>s <code>"missing"</code> and <code>"omitted"</code>
-specify the obvious singleton sets of dummy-obligation states.&nbsp;  
+specify the obvious singleton sets of dummy-obligation states.&nbsp;
 
 A <code>&lt;statuses&gt;</code> specifies a set of possible prover statuses
 as a list, where <code>"-"</code>, means <i>all statuses
@@ -632,18 +644,18 @@ except</i> and the empty list means all possible statuses.&nbsp;
 A triple of sequences of statuses specifies the set of all states in
 which the proof status of the <i>i</i><sup>th</sup> prover is one of
 the statuses in the <i>i</i><sup>th</sup> component of the
-triple.&nbsp; 
+triple.&nbsp;
 
 An empty sequence of statuses is an abbreviation for all possible
 statuses.&nbsp; For example, the <code>&lt;state-set&gt;</code>
 <pre>
-   (proving proved, untried, ) 
+   (proving proved, untried, )
 </pre>
 
 is the set of all obligation states in which Isabelle's proof status
 is either <code>proving</code> or <code>proved</code>, the Other
 prover's status is <code>untried</code>, and the PM's prover status is either
-<code>none</code> or <code>trivial</code>.&nbsp; 
+<code>none</code> or <code>trivial</code>.&nbsp;
 
 We can write a color predicate that is always true as: <pre>
    every missing omitted ( , , )
@@ -660,7 +672,7 @@ is true iff every obligation is either omitted, is proved by Isabelle
 or the Other prover, or is found trivial by the PM.&nbsp; The predicate
 <pre>
   some (failed, - proved, none) (- proved, failed, none)
-</pre> 
+</pre>
 
 is true for a proof iff, for at least one of its obligations, either
 Isabelle's status is <code>failed</code> and the Other prover's status
@@ -668,14 +680,14 @@ is not <code>proved</code>, or vice-versa, and the PM has not found it
 to be trivial.&nbsp;
 
 <hr>
-<!-- 
+<!--
 <dl>
 <dt><b><font color=#0000c0>Subtopics</font></b></dt>
 <dd> <A href="reading.html">Using Color Predicates</A></dd>
 <dd> <A href="runningTlaps.html">Defining New Color Predicates</A></dd>
-</dl> 
+</dl>
 -->
 <a href = "prover.html">&uarr; Proofs</a>
 </hr>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/org.lamport.tla.toolbox.doc/html/spec/pretty-printing.html b/org.lamport.tla.toolbox.doc/html/spec/pretty-printing.html
index ee63a0c0252819198410a9f671cca1f21ec71fef..0652e61fd930501ce1f1f24cba607f80befd5e5d 100644
--- a/org.lamport.tla.toolbox.doc/html/spec/pretty-printing.html
+++ b/org.lamport.tla.toolbox.doc/html/spec/pretty-printing.html
@@ -1,7 +1,7 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
 <!-- This is file org.lamport.tla.toobox.doc/html/spec/pretty-printing.html  -->
 
- 
+
 <html>
 <head>
 	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
@@ -14,13 +14,13 @@
 <body>
 <h1>Pretty-Printing Modules</h1>
 
- <P> 
-You can create and view a pretty-printed 
+ <P>
+You can create and view a pretty-printed
 <a href="http://www.adobe.com/products/acrobat/adobepdf.html"  target="_blank">PDF (Portable
 Document Format)</a> version of a module.&nbsp;  Just view the module
 in a module editor and select&nbsp; <samp>File/Produce PDF Version</samp>.&nbsp;  However,
 to do this, you must have the&nbsp; <samp>pdflatex</samp>&nbsp; program installed.&nbsp;
-This program is distributed with most versions of&nbsp; 
+This program is distributed with most versions of&nbsp;
 <a href="http://www.latex-project.org/"  target="_blank"><samp>LaTeX</samp></a>&nbsp;
 and&nbsp; <a href="http://www.tug.org/"  target="_blank"><samp>TeX</samp></a>.&nbsp;  A popular source
 of TeX for PCs is&nbsp; <samp><a href="http://www.miktex.org/"  target="_blank">MiKTeX</a></samp>.
@@ -30,7 +30,7 @@ of TeX for PCs is&nbsp; <samp><a href="http://www.miktex.org/"  target="_blank">
 same name as the module, but with the extension&nbsp; <code>.pdf</code>.&nbsp;  It displays this
 file in a separate page of the module editor, using your computer's default browser
 to display the PDF file.&nbsp;  (If the browser doesn't have a plug-in that displays PDF files,
-you can 
+you can
 <a href="http://get.adobe.com/reader/otherversions/"  target="_blank">find one on the web.</a>)&nbsp;
 
 You can switch between the editable
@@ -50,7 +50,7 @@ a new pretty-printed version.&nbsp; We have not yet figured out how to solve thi
 -->
 
 <p>There are things you can do to help the pretty printer
-produce better output.&nbsp;  They are described in the  
+produce better output.&nbsp;  They are described in the
 <a href="help-print.html">Helping the Pretty-Printer</a>
 help page.
 </p>
@@ -58,24 +58,24 @@ help page.
 <p>
 A version of the program that does the pretty-printing can be used to add TLA+ and/or
 PlusCal code to a LaTeX document.&nbsp;
-See the section on the TLATeX Pretty-Printer on 
+See the section on the TLATeX Pretty-Printer on
 <a href="https://lamport.azurewebsites.net/tla/tools.html#tlatex?unhideBut=hide-tlatex&unhideDiv=tlatex">this page</a>
 of the TLA+ Web site.
- 
+
 </p>
 
 <h3>Preferences</h3>
 
-<p> 
-The&nbsp; <samp>PDF Viewer Preferences</samp>&nbsp; page on 
+<p>
+The&nbsp; <samp>PDF Viewer Preferences</samp>&nbsp; page on
 the&nbsp; <samp>File/Preferences</samp>&nbsp; menu provides the following options:
 
-<h4>Use built-in PDF viewer</h4>
+<h4>'Have your OS open PDFs' (macOS) or 'Use built-in PDF viewer' (Windows &amp; Linux)</h4>
 
-By default, the PDF file is displayed using your system's default
-PDF viewer.&nbsp;
+By default, the PDF file is displayed using your system's default PDF viewer.&nbsp;
 
-This option causes the Toolbox instead to use its own built-in viewer.&nbsp;
+This option causes the Toolbox to instead either have the operating system open the PDF
+using the user's default PDF viewing application (in macOS) or to use its own built-in viewer (in Windows and Linux.)&nbsp;
 
 On some systems, the default viewer displays the PDF file in a
 separate window that you must close before you can generate a new
@@ -139,16 +139,16 @@ of the program's directory.
 
 See the <b>Shade comments</b> option above.
 </p>
-<hr> 
-<!-- delete rest of line to comment out --> 
+<hr>
+<!-- delete rest of line to comment out -->
 <dl>
 <dt><b><font color=#0000c0>Subtopics</font></b></dt>
 <dd> <A href="help-print.html"> Helping the Pretty-Printer </A></dd>
 </dl>
-<!-- --> 
-<!-- delete rest of line to comment out -->  
+<!-- -->
+<!-- delete rest of line to comment out -->
 <a href = "spec.html">&uarr; Managing Your Specifications</a>
-<!-- --> 
+<!-- -->
 </hr>
 
 </body>
diff --git a/org.lamport.tla.toolbox.doc/html/trouble/trouble.html b/org.lamport.tla.toolbox.doc/html/trouble/trouble.html
index dcfcc823900bdb094509673624884cd70abafc30..bd02b125aa41619835b5e2f30c5d8fcc1e18bb09 100644
--- a/org.lamport.tla.toolbox.doc/html/trouble/trouble.html
+++ b/org.lamport.tla.toolbox.doc/html/trouble/trouble.html
@@ -148,7 +148,7 @@ The &nbsp; <samp>.log</samp>&nbsp; file is in the
 directory.&nbsp; 
 
 On Windows, you can find out where your home directory is located, by 
-by entering the command <code>echo %SYSTEMDRIVE%%HOMEPATH%</code> in 
+entering the command <code>echo %SYSTEMDRIVE%%HOMEPATH%</code> in 
 Command Prompt.&nbsp; On Linux and Mac, check the $HOME variable.&nbsp;
 
 (The log contains enough timestamped entries for you to figure out
diff --git a/org.lamport.tla.toolbox.doc/pom.xml b/org.lamport.tla.toolbox.doc/pom.xml
index 0f81f09d0326469a6d0d3f72759294acb3c1c633..e0ce78191a55234c9e1cda561549d96c0ce4164b 100644
--- a/org.lamport.tla.toolbox.doc/pom.xml
+++ b/org.lamport.tla.toolbox.doc/pom.xml
@@ -11,7 +11,7 @@
   </parent>
   <groupId>tlatoolbox</groupId>
   <artifactId>org.lamport.tla.toolbox.doc</artifactId>
-  <version>1.5.4-SNAPSHOT</version>
+  <version>1.6.1-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
   <properties>
       <!-- Do not include non-code project in Sonar reporting. -->
diff --git a/org.lamport.tla.toolbox.doc/src/org/lamport/tla/toolbox/doc/handler/HelpPDFHandler.java b/org.lamport.tla.toolbox.doc/src/org/lamport/tla/toolbox/doc/handler/HelpPDFHandler.java
index ca322aec9aa577e27a346e1fa7bca942fb9b563d..659fb599bf102e754d9df0136e79d9d9b986c1e4 100644
--- a/org.lamport.tla.toolbox.doc/src/org/lamport/tla/toolbox/doc/handler/HelpPDFHandler.java
+++ b/org.lamport.tla.toolbox.doc/src/org/lamport/tla/toolbox/doc/handler/HelpPDFHandler.java
@@ -55,15 +55,22 @@ public class HelpPDFHandler extends AbstractHandler implements IHandler {
 		// constants to not introduce a plugin dependency.
 		// org.lamport.tla.toolbox.tool.tla2tex.TLA2TeXActivator.PLUGIN_ID
 		// org.lamport.tla.toolbox.tool.tla2tex.preference.ITLA2TeXPreferenceConstants.EMBEDDED_VIEWER
+		// org.lamport.tla.toolbox.tool.tla2tex.preference.ITLA2TeXPreferenceConstants.HAVE_OS_OPEN_PDF
 		final boolean useEmbeddedViewer = Platform.getPreferencesService()
 				.getBoolean("org.lamport.tla.toolbox.tool.tla2tex", "embeddedViewer", false, null);
-		
+		final boolean osOpensPDF = Platform.getPreferencesService()
+				.getBoolean("org.lamport.tla.toolbox.tool.tla2tex", "osHandlesPDF", false, null);
+
 		// Show a sandglass while loading (large) pdfs.
 		BusyIndicator.showWhile(Display.getCurrent(), new Runnable() {
 			public void run() {
 				try {
 					final File pdfFile = getDocFile("/pdfs/" + pdf);
-					if (useEmbeddedViewer) {
+					if (osOpensPDF) {
+						final String[] openCommand = { "open", pdfFile.getAbsolutePath() };
+						
+						Runtime.getRuntime().exec(openCommand);
+					} else if (useEmbeddedViewer) {
 						UIHelper.openEditorUnchecked(
 								// Referencing de.vonloesch...
 								// creates an _implicit_
diff --git a/org.lamport.tla.toolbox.editor.basic/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.editor.basic/META-INF/MANIFEST.MF
index 0ecf06ce0e307743000811f6cfd0054aa68b2ee9..612abb25e16ed9631b6bc60cf710df5569210bdf 100644
--- a/org.lamport.tla.toolbox.editor.basic/META-INF/MANIFEST.MF
+++ b/org.lamport.tla.toolbox.editor.basic/META-INF/MANIFEST.MF
@@ -15,10 +15,12 @@ Require-Bundle: org.eclipse.ui,
  org.eclipse.ui.workbench.texteditor,
  org.eclipse.ui.views,
  org.eclipse.ui.forms,
- org.eclipse.core.filesystem
+ org.eclipse.core.filesystem,
+ org.eclipse.e4.ui.css.swt.theme;bundle-version="0.12.100"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-ActivationPolicy: lazy
-Import-Package: org.eclipse.e4.core.di.annotations;version="1.6.0",
+Import-Package: javax.inject;version="1.0.0",
+ org.eclipse.e4.core.di.annotations;version="1.6.0",
  org.eclipse.e4.core.services.events,
  org.eclipse.ui.forms,
  org.osgi.service.event;version="1.3.1"
diff --git a/org.lamport.tla.toolbox.editor.basic/plugin.xml b/org.lamport.tla.toolbox.editor.basic/plugin.xml
index 17378f3ca4e58492f8802216d06bc4fd56df0c93..896ae356b7ff341ff25cfd42bb19dc19e15b2c66 100644
--- a/org.lamport.tla.toolbox.editor.basic/plugin.xml
+++ b/org.lamport.tla.toolbox.editor.basic/plugin.xml
@@ -77,6 +77,20 @@
             id="org.lamport.tla.toolbox.editor.basic.FocusOnStep"
             name="Focus On Step">
       </command>
+      <command
+            categoryId="org.eclipse.ui.category.textEditor"
+            defaultHandler="org.lamport.tla.toolbox.editor.basic.handlers.ExpandAllRegionsHandler"
+            description="Expand all regions in the editor."
+            id="org.lamport.tla.toolbox.editor.basic.ExpandAllRegionsHandler"
+            name="Expand All Regions">
+      </command>
+      <command
+            categoryId="org.eclipse.ui.category.textEditor"
+            defaultHandler="org.lamport.tla.toolbox.editor.basic.handlers.FoldAllRegionsHandler"
+            description="Fold all regions in the editor."
+            id="org.lamport.tla.toolbox.editor.basic.FoldAllRegionsHandler"
+            name="Fold All Regions">
+      </command>
       <command
             categoryId="org.eclipse.ui.category.textEditor"
             defaultHandler="org.lamport.tla.toolbox.editor.basic.handlers.HideAllProofsHandler"
@@ -583,6 +597,19 @@
                     commandId="org.eclipse.ui.edit.text.contentAssist.proposals">
               </command>
            </menuContribution>
+           <menuContribution
+                 locationURI="popup:#AbstractTextEditorRulerContext?after=additions">
+              <separator
+                    name="org.lamport.tla.toolbox.editor.basic.commentseparatorBeginning"
+                    visible="true"/>
+              <command
+                    commandId="org.lamport.tla.toolbox.editor.basic.FoldAllRegionsHandler"/>
+              <command
+                    commandId="org.lamport.tla.toolbox.editor.basic.ExpandAllRegionsHandler"/>
+              <separator
+                    name="org.lamport.tla.toolbox.editor.basic.commentseparatorEnd"
+                    visible="true"/>
+           </menuContribution>
            <menuContribution
                  locationURI="popup:#TextEditorContext?after=foldCommands">
               <menu
@@ -592,37 +619,21 @@
                        name="additions">
                  </separator>
                  <command
-                    commandId="org.lamport.tla.toolbox.editor.basic.ExpandAllProofs"
-                       style="push">
-                 </command>
+                    commandId="org.lamport.tla.toolbox.editor.basic.ExpandAllProofs"/>
                  <command
-                    commandId="org.lamport.tla.toolbox.editor.basic.FoldAllProofs"
-                       style="push">
-                 </command>
+                    commandId="org.lamport.tla.toolbox.editor.basic.FoldAllProofs"/>
                  <command
-                    commandId="org.lamport.tla.toolbox.editor.basic.ExpandSubtree"
-                       style="push">
-                 </command>
+                    commandId="org.lamport.tla.toolbox.editor.basic.ExpandSubtree"/>
                  <command
-                    commandId="org.lamport.tla.toolbox.editor.basic.CollapseSubtree"
-                       style="push">
-                 </command>
+                    commandId="org.lamport.tla.toolbox.editor.basic.CollapseSubtree"/>
                  <command
-                       commandId="org.lamport.tla.toolbox.editor.basic.ShowImmediate"
-                       style="push">
-                 </command>
+                       commandId="org.lamport.tla.toolbox.editor.basic.ShowImmediate"/>
                  <command
-                    commandId="org.lamport.tla.toolbox.editor.basic.FocusOnStep"
-                       style="push">
-                 </command>
+                    commandId="org.lamport.tla.toolbox.editor.basic.FocusOnStep"/>
                  <command
-                    commandId="org.lamport.tla.toolbox.editor.basic.renumberProof"
-                       style="push">
-                 </command>
+                    commandId="org.lamport.tla.toolbox.editor.basic.renumberProof"/>
                  <command
-                    commandId="org.lamport.tla.toolbox.editor.basic.DecomposeProof"
-                       style="push">
-                 </command>
+                    commandId="org.lamport.tla.toolbox.editor.basic.DecomposeProof"/>
               </menu>
               <separator
                     name="org.lamport.tla.toolbox.editor.basic.commentseparator"
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/eclipse/jdt/internal/ui/actions/FoldingMessages.java b/org.lamport.tla.toolbox.editor.basic/src/org/eclipse/jdt/internal/ui/actions/FoldingMessages.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ad9229697ebc23668674f7d6f9f1f315f3a1eff
--- /dev/null
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/eclipse/jdt/internal/ui/actions/FoldingMessages.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.actions;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * Class that gives access to the folding messages resource bundle.
+ */
+public class FoldingMessages {
+
+	private static final String BUNDLE_NAME= "org.eclipse.jdt.internal.ui.actions.FoldingMessages"; //$NON-NLS-1$
+
+	private static final ResourceBundle RESOURCE_BUNDLE= ResourceBundle.getBundle(BUNDLE_NAME);
+
+	private FoldingMessages() {
+		// no instance
+	}
+
+	/**
+	 * Returns the resource string associated with the given key in the resource bundle. If there isn't
+	 * any value under the given key, the key is returned.
+	 *
+	 * @param key the resource key
+	 * @return the string
+	 */
+	public static String getString(String key) {
+		try {
+			return RESOURCE_BUNDLE.getString(key);
+		} catch (MissingResourceException e) {
+			return '!' + key + '!';
+		}
+	}
+
+	/**
+	 * Returns the resource bundle managed by the receiver.
+	 *
+	 * @return the resource bundle
+	 * @since 3.0
+	 */
+	public static ResourceBundle getResourceBundle() {
+		return RESOURCE_BUNDLE;
+	}
+}
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/eclipse/jdt/internal/ui/actions/FoldingMessages.properties b/org.lamport.tla.toolbox.editor.basic/src/org/eclipse/jdt/internal/ui/actions/FoldingMessages.properties
new file mode 100644
index 0000000000000000000000000000000000000000..7fd5464f8a2d620c375a1c42c3c82f9edcd29ec0
--- /dev/null
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/eclipse/jdt/internal/ui/actions/FoldingMessages.properties
@@ -0,0 +1,52 @@
+###############################################################################
+# Copyright (c) 2005, 2006 IBM Corporation and others.
+#
+# This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License 2.0
+# which accompanies this distribution, and is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+#
+# Contributors:
+#     IBM Corporation - initial API and implementation
+###############################################################################
+Projection.Toggle.label= &Enable Folding
+Projection.Toggle.tooltip= Toggles Folding
+Projection.Toggle.description= Toggles folding for the current editor
+Projection.Toggle.image=
+
+Projection.ExpandAll.label= Expand &All
+Projection.ExpandAll.tooltip= Expands All Collapsed Regions
+Projection.ExpandAll.description= Expands any collapsed regions in the current editor
+Projection.ExpandAll.image=
+
+Projection.Expand.label= E&xpand
+Projection.Expand.tooltip= Expands the Current Collapsed Region
+Projection.Expand.description= Expands the collapsed region at the current selection
+Projection.Expand.image=
+
+Projection.CollapseAll.label= Collapse A&ll
+Projection.CollapseAll.tooltip= Collapses All Expanded Regions
+Projection.CollapseAll.description= Collapse any expanded regions in the current editor
+Projection.CollapseAll.image=
+
+Projection.Collapse.label= Colla&pse
+Projection.Collapse.tooltip= Collapses the Current Region
+Projection.Collapse.description= Collapses the Current Region
+Projection.Collapse.image=
+
+Projection.Restore.label= &Reset Structure
+Projection.Restore.tooltip= Restore the Original Folding Structure
+Projection.Restore.description= Restores the original folding structure
+Projection.Restore.image=
+
+Projection.CollapseComments.label= Collapse &Comments
+Projection.CollapseComments.tooltip= Collapses All Comments
+Projection.CollapseComments.description= Collapses all comments
+Projection.CollapseComments.image=
+
+Projection.CollapseMembers.label= Collapse &Members
+Projection.CollapseMembers.tooltip= Collapses All Members
+Projection.CollapseMembers.description= Collapses all members
+Projection.CollapseMembers.image=
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAColorProvider.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAColorProvider.java
index 5885aa779934bb751658e062710482dd14324b2b..a419ed1d42cc84e4ebc9c896cff2f76ec81cf270 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAColorProvider.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAColorProvider.java
@@ -11,52 +11,95 @@ import org.eclipse.swt.widgets.Display;
 /**
  * Color provider
  * @author Simon Zambrovski
- * @version $Id$
  */
-public class TLAColorProvider
-{
+public class TLAColorProvider {
+	public static final String CONTENT_ASSIST_BACKGROUND_KEY = "content_assist.background";
+	public static final String DEFAULT_TEXT_KEY = "all.default";
+	public static final String PCAL_KEYWORD_KEY = "pcal.keyword";
+	public static final String TLA_KEYWORD_KEY = "tla.keyword";
+	public static final String TLA_MULTI_LINE_COMMENT_KEY = "tla.comment.multiline";
+	public static final String TLA_SINGLE_LINE_COMMENT_KEY = "tla.comment.single";
+	public static final String TLA_VALUE_KEY = "tla.value";
+	
+	
+	/** Colors for a light theme **/
+    private static final RGB CONTENT_ASSIST_BACKGROUND_RGB = new RGB(150, 150, 0);
+    private static final RGB DEFAULT_RGB = new RGB(0, 0, 0);
+    private static final RGB PCAL_KEYWORD_RGB = new RGB(175, 40, 10);
+    private static final RGB TLA_KEYWORD_RGB = new RGB(128, 0, 128); 
+	private static final RGB TLA_MULTI_LINE_COMMENT_RGB = new RGB(64, 64, 255);
+    private static final RGB TLA_SINGLE_LINE_COMMENT_RGB = new RGB(0, 128, 64);
+    private static final RGB TLA_VALUE_RGB = new RGB(0, 0, 255); 
 
-    public static final RGB TLA_MULTI_LINE_COMMENT = new RGB(64, 64, 255);
-    public static final RGB TLA_SINGLE_LINE_COMMENT = new RGB(0, 128, 64);
+	/** Colors for a dark theme **/
+    private static final RGB CONTENT_ASSIST_BACKGROUND_DARK_RGB = new RGB(150, 150, 0);
+    private static final RGB DEFAULT_DARK_RGB = new RGB(3, 167, 226);
+    private static final RGB PCAL_KEYWORD_DARK_RGB = new RGB(245, 115, 67);
+    private static final RGB TLA_KEYWORD_DARK_RGB = new RGB(172, 226, 156); 
+	private static final RGB TLA_MULTI_LINE_COMMENT_DARK_RGB = new RGB(245, 235, 191);
+    private static final RGB TLA_SINGLE_LINE_COMMENT_DARK_RGB = new RGB(0, 207, 104);
+    private static final RGB TLA_VALUE_DARK_RGB = new RGB(226, 200, 99); 
     
-    // Added for PlusCal
-    public static final RGB PCAL_KEYWORD = new RGB(175, 40, 10);
-
-
-    public static final RGB TLA_KEYWORD = new RGB(128, 0, 128); 
-    public static final RGB TLA_VALUE = new RGB(0, 0, 255); 
-    public static final RGB TLA_DEFAULT = new RGB(0, 0, 0);
-    public static final RGB CONTENT_ASSIST_BACKGROUNG = new RGB(150, 150, 0);
+    private static final Map<String, RGB> COLOR_KEY_RGB_MAP;
+    
+    static {
+    	COLOR_KEY_RGB_MAP = new HashMap<>();
+    	
+    	COLOR_KEY_RGB_MAP.put(getThemeContextualizedKey(CONTENT_ASSIST_BACKGROUND_KEY, false), CONTENT_ASSIST_BACKGROUND_RGB);
+    	COLOR_KEY_RGB_MAP.put(getThemeContextualizedKey(DEFAULT_TEXT_KEY, false), DEFAULT_RGB);
+    	COLOR_KEY_RGB_MAP.put(getThemeContextualizedKey(PCAL_KEYWORD_KEY, false), PCAL_KEYWORD_RGB);
+    	COLOR_KEY_RGB_MAP.put(getThemeContextualizedKey(TLA_KEYWORD_KEY, false), TLA_KEYWORD_RGB);
+    	COLOR_KEY_RGB_MAP.put(getThemeContextualizedKey(TLA_MULTI_LINE_COMMENT_KEY, false), TLA_MULTI_LINE_COMMENT_RGB);
+    	COLOR_KEY_RGB_MAP.put(getThemeContextualizedKey(TLA_SINGLE_LINE_COMMENT_KEY, false), TLA_SINGLE_LINE_COMMENT_RGB);
+    	COLOR_KEY_RGB_MAP.put(getThemeContextualizedKey(TLA_VALUE_KEY, false), TLA_VALUE_RGB);
+    	
+    	COLOR_KEY_RGB_MAP.put(getThemeContextualizedKey(CONTENT_ASSIST_BACKGROUND_KEY, true), CONTENT_ASSIST_BACKGROUND_DARK_RGB);
+    	COLOR_KEY_RGB_MAP.put(getThemeContextualizedKey(DEFAULT_TEXT_KEY, true), DEFAULT_DARK_RGB);
+    	COLOR_KEY_RGB_MAP.put(getThemeContextualizedKey(PCAL_KEYWORD_KEY, true), PCAL_KEYWORD_DARK_RGB);
+    	COLOR_KEY_RGB_MAP.put(getThemeContextualizedKey(TLA_KEYWORD_KEY, true), TLA_KEYWORD_DARK_RGB);
+    	COLOR_KEY_RGB_MAP.put(getThemeContextualizedKey(TLA_MULTI_LINE_COMMENT_KEY, true), TLA_MULTI_LINE_COMMENT_DARK_RGB);
+    	COLOR_KEY_RGB_MAP.put(getThemeContextualizedKey(TLA_SINGLE_LINE_COMMENT_KEY, true), TLA_SINGLE_LINE_COMMENT_DARK_RGB);
+    	COLOR_KEY_RGB_MAP.put(getThemeContextualizedKey(TLA_VALUE_KEY, true), TLA_VALUE_DARK_RGB);
+    }
+    
+    private static String getThemeContextualizedKey(final String key, final boolean themeIsDark) {
+    	return key + "_" + (themeIsDark ? "dunkel" : "hell");
+    }
     
     
-    protected Map fColorTable = new HashMap(10);
+    private final Map<String, Color> keyColorMap;
     
+    public TLAColorProvider() {
+    	keyColorMap = new HashMap<>();
+    }
 
     /**
      * Release all of the color resources held onto by the receiver.
      */
-    public void dispose()
-    {
-        Iterator e = fColorTable.values().iterator();
-        while (e.hasNext())
-            ((Color) e.next()).dispose();
+	public void dispose() {
+		final Iterator<Color> e = keyColorMap.values().iterator();
+        while (e.hasNext()) {
+            e.next().dispose();
+        }
     }
-
+    
     /**
-     * Return the color that is stored in the color table under the given RGB
-     * value.
+     * Return the color that is stored in the color table under, referenced by the supplied key, and the current
+     * Toolbox theme (dark v. light.)
      * 
-     * @param rgb the RGB value
-     * @return the color stored in the color table for the given RGB value
+     * @param colorKey one of the public static String keys defined in this class
+     * @return the color, adjusted for current theme, or null if the key provided is unknown to this class
      */
-    public Color getColor(RGB rgb)
-    {
-        Color color = (Color) fColorTable.get(rgb);
-        if (color == null)
-        {
-            color = new Color(Display.getCurrent(), rgb);
-            fColorTable.put(rgb, color);
-        }
-        return color;
-    }
+	public Color getColor(final String colorKey) {
+		final String key = getThemeContextualizedKey(colorKey, TLAEditorActivator.getDefault().isCurrentThemeDark());
+		Color color = keyColorMap.get(key);
+		if (color == null) {
+			final RGB rgb = COLOR_KEY_RGB_MAP.get(key);
+			if (rgb != null) {
+				color = new Color(Display.getCurrent(), rgb);
+				keyColorMap.put(key, color);
+			}
+		}
+		return color;
+	}
 }
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditor.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditor.java
index fdc577c3596658f06ebd915787c31c17252a9dc9..77cc282ffc4e21bbba93875d684c3447c6b49829 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditor.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditor.java
@@ -5,7 +5,6 @@ import java.io.IOException;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -31,6 +30,7 @@ import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.e4.core.services.events.IEventBroker;
+import org.eclipse.jface.action.ContributionManager;
 import org.eclipse.jface.action.IAction;
 import org.eclipse.jface.action.IContributionItem;
 import org.eclipse.jface.action.IMenuManager;
@@ -62,7 +62,10 @@ import org.eclipse.jface.viewers.ISelectionProvider;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.IEditorPart;
@@ -72,12 +75,12 @@ import org.eclipse.ui.IURIEditorInput;
 import org.eclipse.ui.IWorkbenchActionConstants;
 import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.actions.ContributionItemFactory;
 import org.eclipse.ui.contexts.IContextActivation;
 import org.eclipse.ui.contexts.IContextService;
 import org.eclipse.ui.editors.text.EditorsUI;
 import org.eclipse.ui.editors.text.TextEditor;
 import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.ide.FileStoreEditorInput;
 import org.eclipse.ui.part.FileEditorInput;
 import org.eclipse.ui.texteditor.ChainedPreferenceStore;
 import org.eclipse.ui.texteditor.IDocumentProvider;
@@ -88,18 +91,19 @@ import org.lamport.tla.toolbox.editor.basic.actions.ToggleCommentAction;
 import org.lamport.tla.toolbox.editor.basic.pcal.IPCalReservedWords;
 import org.lamport.tla.toolbox.editor.basic.proof.IProofFoldCommandIds;
 import org.lamport.tla.toolbox.editor.basic.proof.TLAProofFoldingStructureProvider;
-import org.lamport.tla.toolbox.editor.basic.proof.TLAProofPosition;
 import org.lamport.tla.toolbox.editor.basic.util.EditorUtil;
 import org.lamport.tla.toolbox.editor.basic.util.ElementStateAdapter;
 import org.lamport.tla.toolbox.spec.Spec;
 import org.lamport.tla.toolbox.tool.ToolboxHandle;
 import org.lamport.tla.toolbox.util.ResourceHelper;
-import org.lamport.tla.toolbox.util.StringHelper;
 import org.lamport.tla.toolbox.util.TLAtoPCalMarker;
 import org.lamport.tla.toolbox.util.UIHelper;
 
 import pcal.PCalLocation;
 import pcal.TLAtoPCalMapping;
+import tlc2.output.SpecWriterUtilities;
+import util.StringHelper;
+import util.TLAConstants;
 
 /**
  * Basic editor for TLA+
@@ -129,8 +133,6 @@ public class TLAEditor extends TextEditor
     private Image rootImage = TLAEditorActivator.imageDescriptorFromPlugin(TLAEditorActivator.PLUGIN_ID,
             "/icons/root_file.gif").createImage();
 
-    // currently installed annotations
-    private Annotation[] oldAnnotations;
     // annotation model
     private ProjectionAnnotationModel annotationModel;
     // proof structure provider
@@ -195,8 +197,8 @@ public class TLAEditor extends TextEditor
         }
     }
 
-    protected TLASourceViewerConfiguration getTLASourceViewerConfiguration(IPreferenceStore preferenceStore) {
-    	return new TLASourceViewerConfiguration(preferenceStore, this); 
+    protected TLASourceViewerConfiguration getTLASourceViewerConfiguration(final IPreferenceStore preferenceStore) {
+    	return new TLASourceViewerConfiguration(preferenceStore, this);
     }
     
     /*
@@ -240,16 +242,27 @@ public class TLAEditor extends TextEditor
 
                 for (int i = 0; i < markerChanges.length; i++)
                 {
-                    if (markerChanges[i].getResource().equals(((IFileEditorInput) getEditorInput()).getFile()))
-                    {
-                        UIHelper.runUIAsync(new Runnable() {
-
-                            public void run()
-                            {
-                                refresh();
-                            }
-                        });
-                    }
+                	if (getEditorInput() instanceof IFileEditorInput) {
+                		final IFileEditorInput iFileEditorInput = (IFileEditorInput) getEditorInput();
+                		if (markerChanges[i].getResource().equals(iFileEditorInput.getFile())) {
+                			UIHelper.runUIAsync(new Runnable() {
+                				public void run() {
+                					refresh();
+                				}
+                			});
+                		}
+                	} else if (getEditorInput() instanceof FileStoreEditorInput) {
+						// Leslie reported a ClassCastException triggered by clicking the “Goto
+						// Obligation” button on a failed proof obligation.
+                		final FileStoreEditorInput fsei = (FileStoreEditorInput) getEditorInput();
+                		if (markerChanges[i].getResource().getLocationURI().equals(fsei.getURI())) {
+                			UIHelper.runUIAsync(new Runnable() {
+                				public void run() {
+                					refresh();
+                				}
+                			});
+                		}
+                	}
                 }
             }
         };
@@ -316,26 +329,30 @@ public class TLAEditor extends TextEditor
         return viewer;
     }
 
-    public void createPartControl(Composite parent)
+    @Override
+    public void createPartControl(final Composite parent)
     {
         super.createPartControl(parent);
         /*
-         * Add projection support (e.G. for folding) 
+         * Add projection support (i.e. for folding) 
          */
-        ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();
+        final ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();
         projectionSupport = new ProjectionSupport(viewer, getAnnotationAccess(), getSharedColors());
         projectionSupport.addSummarizableAnnotationType("org.eclipse.ui.workbench.texteditor.error"); //$NON-NLS-1$
         projectionSupport.addSummarizableAnnotationType("org.eclipse.ui.workbench.texteditor.warning"); //$NON-NLS-1$
         projectionSupport.install();
-        viewer.doOperation(ProjectionViewer.TOGGLE);
+        
+		if (viewer.canDoOperation(ProjectionViewer.TOGGLE)) {
+			viewer.doOperation(ProjectionViewer.TOGGLE);
+		}
 
         // model for adding projections (folds)
-        this.annotationModel = viewer.getProjectionAnnotationModel();
+        annotationModel = viewer.getProjectionAnnotationModel();
 
         // this must be instantiated after annotationModel so that it does
         // not call methods that use annotation model when the model is still null
-        this.proofStructureProvider = new TLAProofFoldingStructureProvider(this);
-
+        proofStructureProvider = new TLAProofFoldingStructureProvider(this);
+        
         // refresh the editor in case it should be
         // read only
         refresh();
@@ -407,8 +424,8 @@ public class TLAEditor extends TextEditor
      * We use this to remove unwanted items from the menu
      * that eclipse plug-ins contribute.
      */
-    protected void editorContextMenuAboutToShow(IMenuManager menuManager)
-    {
+    @Override
+	protected void editorContextMenuAboutToShow(final IMenuManager menuManager) {
         super.editorContextMenuAboutToShow(menuManager);
         // The following adds an extra section for the fold commands.
         // First, try to find the additions group.
@@ -423,6 +440,55 @@ public class TLAEditor extends TextEditor
             menuManager.add(new Separator("foldCommands"));
         }
 
+        // It would be nice if we had all of that "Run As", etc nonsense populated by the time we get here,
+        //		but that gets added later, after us.. so, we will do something fairly hacky below.
+        if (menuManager instanceof ContributionManager) {
+        	final ContributionManager cm = (ContributionManager)menuManager;
+        	
+        	removeTopLevelMenuWithDisplayText("Open W&ith", cm);
+        	removeTopLevelMenuWithDisplayText("Sho&w In", cm);
+
+        	if (menuManager instanceof MenuManager) {
+        		
+        	}
+        	final Runnable r = () -> {
+        		final MenuManager mm = (MenuManager)cm;
+        		final ArrayList<Integer> menuCountFerry = new ArrayList<>();
+        		final Display d = PlatformUI.getWorkbench().getDisplay();
+        		
+        		d.syncExec(() -> {
+        			menuCountFerry.clear();
+        			
+        			final Menu m = mm.getMenu();
+        			menuCountFerry.add(Integer.valueOf((m != null) ? m.getItemCount() : 0));
+        		});
+        		while (menuCountFerry.get(0).intValue() == 0) {
+            		try {
+            			Thread.sleep(40);
+            		} catch (final Exception e) { }
+            		
+            		d.syncExec(() -> {
+            			menuCountFerry.clear();
+            			
+            			final Menu m = mm.getMenu();
+            			menuCountFerry.add(Integer.valueOf((m != null) ? m.getItemCount() : 0));
+            		});
+        		}
+        		
+        		PlatformUI.getWorkbench().getDisplay().asyncExec(() -> {
+        			final Menu menu = mm.getMenu();
+        			
+                	removeMenuItemWithDisplayText("&Run As", menu);
+                	removeMenuItemWithDisplayText("&Debug As", menu);
+                	removeMenuItemWithDisplayText("Import SWTBot", menu);
+                	removeMenuItemWithDisplayText("T&eam", menu);
+                	removeMenuItemWithDisplayText("Rep&lace With", menu);
+                	removeMenuItemWithDisplayText("Comp&are With", menu);
+        		});
+        	};
+        	(new Thread(r)).start();
+        }
+        
         /*
          * The following removes unwanted preference items.
          * 
@@ -432,36 +498,45 @@ public class TLAEditor extends TextEditor
          */
         menuManager.remove(ITextEditorActionConstants.SHIFT_RIGHT);
         menuManager.remove(ITextEditorActionConstants.SHIFT_LEFT);
-
-        /*
-         * The following is a bit of a hack to remove
-         * the "Show In" submenu that is contributed by
-         * AbstractDecoratedTextEditor in its implementation
-         * of this method. It is contributed without
-         * an id, so we have to check all items in the menu
-         * to check if a submenu contains an item with
-         * the id viewShowIn. Then we remove this submenu.
-         */
-        IContributionItem[] items = menuManager.getItems();
-        for (int i = 0; i < items.length; i++)
-        {
-            if (items[i] instanceof MenuManager)
-            {
-                MenuManager subMenu = (MenuManager) items[i];
-                if (subMenu.find(ContributionItemFactory.VIEWS_SHOW_IN.getId()) != null)
-                {
-                    menuManager.remove(subMenu);
-                    break;
-                }
-            }
+    }
+    
+    // Were there ever more than one menu with the same display text beginning, this would produce unexpected results.
+    private void removeMenuItemWithDisplayText(final String text, final Menu menu) {
+    	final MenuItem[] items = menu.getItems();
+    	
+    	for (final MenuItem item : items) {
+    		final String menuItemText = item.getText();
+    		
+    		if ((menuItemText != null) && menuItemText.startsWith(text)) {
+    			item.dispose();
+    			
+    			return;
+    		}
+    	}
+    }
+    
+    // Were there ever more than one menu with the same display text beginning, this would produce unexpected results.
+    private void removeTopLevelMenuWithDisplayText(final String text, final ContributionManager cm) {
+        final IContributionItem[] items = cm.getItems();
+    	
+        for (final IContributionItem item : items) {
+        	if (item instanceof MenuManager) {
+        		final MenuManager mm = (MenuManager)item;
+        		final String menuText = mm.getMenuText();
+        		
+        		if ((menuText != null) && menuText.startsWith(text)) {
+        			cm.remove(item);
+        			return;
+        		}
+        	}
         }
-
     }
 
     /*
      * We override this method to add information about who modified the file when. 
      * @see org.eclipse.ui.texteditor.AbstractTextEditor#doSave(org.eclipse.core.runtime.IProgressMonitor)
      */
+    @Override
     public void doSave(IProgressMonitor progressMonitor)
     {
         service.send(PRE_SAVE_EVENT, this);
@@ -473,17 +548,17 @@ public class TLAEditor extends TextEditor
         // Set historyStart to the offset at the start of the
         // modification history section, if there is one. And if there is,
         // we add the modification date and user.
-        int historyStart = text.indexOf(ResourceHelper.modificationHistory);
+        int historyStart = text.indexOf(SpecWriterUtilities.MODIFICATION_HISTORY);
 
         if (historyStart > -1)
         {
 
             // Set newEntryStart to the point at which the new modification
             // information is to be inserted.
-            int newEntryStart = historyStart + ResourceHelper.modificationHistory.length();
+            int newEntryStart = historyStart + SpecWriterUtilities.MODIFICATION_HISTORY.length();
 
             String user = System.getProperty("user.name");
-            String searchString = ResourceHelper.modifiedBy + user;
+            String searchString = SpecWriterUtilities.MODIFIED_BY + user;
             int searchStringLength = searchString.length();
 
             // Need to remove existing modification entry for user
@@ -501,14 +576,14 @@ public class TLAEditor extends TextEditor
             int endOfLine = -1; // initialization needed to make compiler happy.
             label: while (!found)
             {
-                nextEntry = text.indexOf(ResourceHelper.lastModified, nextEntry + 1);
+                nextEntry = text.indexOf(SpecWriterUtilities.LAST_MODIFIED, nextEntry + 1);
                 // It we don't find an entry, we eventually exit by
                 // nextEntry becoming -1.
                 if (nextEntry < 0)
                 {
                     break label;
                 }
-                endOfLine = text.indexOf(StringHelper.newline, nextEntry + 1);
+                endOfLine = text.indexOf(StringHelper.PLATFORM_NEWLINE, nextEntry + 1);
                 if (endOfLine < 0)
                 {
                     endOfLine = text.length();
@@ -539,7 +614,7 @@ public class TLAEditor extends TextEditor
                 {
                     doc.replace(nextEntry, endOfLine - nextEntry, "");
                 }
-                doc.replace(newEntryStart, 0, ResourceHelper.lastModified + (new Date()) + searchString);
+                doc.replace(newEntryStart, 0, SpecWriterUtilities.LAST_MODIFIED + (new Date()) + searchString);
                 
     			// Save the last one to two (depending on boolean "found")
     			// IUndoableOperations created by the previous two doc.replace(...)
@@ -578,40 +653,6 @@ public class TLAEditor extends TextEditor
         }
     }
 
-    /**
-     * Update the annotation structure in the editor.
-     * 
-     * This is only currently used by comment
-     * folding and should be removed because it
-     * is incorrect.
-     * 
-     * @param positions
-     * @deprecated
-     */
-    public void updateFoldingStructure(List<Position> positions)
-    {
-    	if (annotationModel == null) {
-    		return;
-    	}
-
-        Annotation[] annotations = new Annotation[positions.size()];
-
-        // this will hold the new annotations along
-        // with their corresponding positions
-        Map<ProjectionAnnotation, Position> newAnnotations = new HashMap<ProjectionAnnotation, Position>();
-
-        for (int i = 0; i < positions.size(); i++)
-        {
-            ProjectionAnnotation annotation = new ProjectionAnnotation();
-            newAnnotations.put(annotation, positions.get(i));
-            annotations[i] = annotation;
-        }
-        // If this method is called too early, then annotationModel
-        // can be null. This should obviously be addressed.
-        this.annotationModel.modifyAnnotations(oldAnnotations, newAnnotations, null);
-        oldAnnotations = annotations;
-    }
-
     /**
      * Calls {@link ProjectionAnnotationModel#modifyAnnotations(Annotation[], Map, Annotation[])} with the
      * arguments.
@@ -622,8 +663,8 @@ public class TLAEditor extends TextEditor
      * @param deletions
      * @param additions
      */
-    public void modifyProjectionAnnotations(Annotation[] deletions, Map<ProjectionAnnotation, TLAProofPosition> additions)
-    {
+	public void modifyProjectionAnnotations(final Annotation[] deletions,
+			final Map<? extends ProjectionAnnotation, ? extends Position> additions) {
         this.annotationModel.modifyAnnotations(deletions, additions, null);
     }
     
@@ -786,6 +827,11 @@ public class TLAEditor extends TextEditor
         // tlapmColoring.dispose();
         proofStructureProvider.dispose();
         rootImage.dispose();
+		final TLAReconcilingStrategy reconciler = (TLAReconcilingStrategy) getViewer()
+				.getData(TLAReconcilingStrategy.class.toString());
+		if (reconciler != null) {
+			reconciler.dispose();
+		}
         ResourcesPlugin.getWorkspace().removeResourceChangeListener(moduleFileChangeListener);
         super.dispose();
     }
@@ -817,7 +863,7 @@ public class TLAEditor extends TextEditor
 	 */
 	public TLAtoPCalMapping getTpMapping() {
         final Spec spec = ToolboxHandle.getCurrentSpec();
-        return spec.getTpMapping(getModuleName() + ".tla");
+        return spec.getTpMapping(getModuleName() + TLAConstants.Files.TLA_EXTENSION);
 	}
 	
 	/* (non-Javadoc)
@@ -843,8 +889,11 @@ public class TLAEditor extends TextEditor
 			}
 		}
 		
-		// fall back to original marker if the TLAtoPCalMarker didn't work or no
-		// TLAtoPCalMarker
+		// fall back to original marker if the TLAtoPCalMarker didn't work or no TLAtoPCalMarker
+		//  N.B even though this is marked deprecated, the recommended replacement of: 
+		//					((IGotoMarker)getAdapter(IGotoMarker.class)).gotoMarker(marker);
+		//	causes a stack overflow.
+		//		See: https://github.com/tlaplus/tlaplus/commit/28f6e2cf6328b84027762e828fb2f741b1a25377#r35904992
 		super.gotoMarker(marker);
 	}
 
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditorActivator.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditorActivator.java
index ea23a6f61b0b351c788627cab93ca680ad24bb3b..86dc52a2c896f5790581c07d0439cd1d74de165d 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditorActivator.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditorActivator.java
@@ -1,35 +1,62 @@
 package org.lamport.tla.toolbox.editor.basic;
 
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.eclipse.e4.ui.css.swt.theme.ITheme;
+import org.eclipse.e4.ui.css.swt.theme.IThemeEngine;
+import org.eclipse.e4.ui.css.swt.theme.IThemeManager;
+import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.text.rules.IPartitionTokenScanner;
 import org.eclipse.jface.text.rules.ITokenScanner;
+import org.eclipse.swt.widgets.Display;
 import org.lamport.tla.toolbox.AbstractTLCActivator;
+import org.lamport.tla.toolbox.Activator;
 import org.lamport.tla.toolbox.editor.basic.tla.PCALCodeScanner;
 import org.lamport.tla.toolbox.editor.basic.tla.TLACodeScanner;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.event.EventHandler;
 
 /**
  * The activator class controls the plug-in life cycle
  */
-public class TLAEditorActivator extends AbstractTLCActivator
-{
-
+@SuppressWarnings("restriction")
+public class TLAEditorActivator extends AbstractTLCActivator {
     // The plug-in ID
     public static final String PLUGIN_ID = "org.lamport.tla.toolbox.editor.basic";
 
     // The shared instance
     private static TLAEditorActivator plugin;
+    
+    private static final String DARK_THEME_ID_PREFIX = "org.eclipse.e4.ui.css.theme.e4_dark";
 
-    // token scanner
+    /**
+     * Returns the shared instance
+     *
+     * @return the shared instance
+     */
+	public static TLAEditorActivator getDefault() {
+        return plugin;
+    }
+
+    
     private TLAPartitionScanner partitionTokenScanner;
     private TLAColorProvider colorProvider;
     private TLACodeScanner tlaCodeScanner;
-    private PCALCodeScanner pcalCodeScanner;  // Added for PlusCal
+    private PCALCodeScanner pcalCodeScanner;
+
+    private ServiceRegistration<?> themeChangeEventRegistration;
+    
+    private Boolean currentThemeIsDark;
 
     /**
      * The constructor
      */
-    public TLAEditorActivator()
-    {
+	public TLAEditorActivator() {
     	super(PLUGIN_ID);
     }
 
@@ -37,31 +64,71 @@ public class TLAEditorActivator extends AbstractTLCActivator
      * (non-Javadoc)
      * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
      */
-    public void start(BundleContext context) throws Exception
-    {
+	public void start(final BundleContext context) throws Exception {
     	plugin = this;
+    	
         super.start(context);
+        
+    	final Dictionary<String, Object> serviceRegistrationProperties = new Hashtable<>();
+    	serviceRegistrationProperties.put(EventConstants.EVENT_TOPIC, IThemeEngine.Events.THEME_CHANGED);
+    	
+    	themeChangeEventRegistration = context.registerService(EventHandler.class.getName(), new EventHandler() {
+    		@Override
+    		public void handleEvent(final Event event) {
+    			tlaCodeScanner = null;
+    			pcalCodeScanner = null;
+    			setDarkThemeStatus();
+    		}
+    	}, serviceRegistrationProperties);
     }
 
     /*
      * (non-Javadoc)
      * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
      */
-    public void stop(BundleContext context) throws Exception
-    {
-        plugin = null;
-        super.stop(context);
-    }
+	public void stop(final BundleContext context) throws Exception {
+		themeChangeEventRegistration.unregister();
+		plugin = null;
+		super.stop(context);
+	}
 
-    /**
-     * Returns the shared instance
-     *
-     * @return the shared instance
-     */
-    public static TLAEditorActivator getDefault()
-    {
-        return plugin;
+    private void setDarkThemeStatus () {
+    	final BundleContext context = Activator.getDefault().getBundle().getBundleContext();
+    	final ServiceReference<IThemeManager> serviceReference = context.getServiceReference(IThemeManager.class);
+    	
+    	if (serviceReference != null) {
+            final IThemeManager manager = context.getService(serviceReference);
+
+            if (manager != null) {
+            	final Display d = Display.getDefault();
+            	final IThemeEngine engine = manager.getEngineForDisplay(d);
+            	final ITheme it = engine.getActiveTheme();
+            	
+            	if (it != null) {
+            		boolean newThemeStatus = it.getId().startsWith(DARK_THEME_ID_PREFIX);
+            		
+            		if ((currentThemeIsDark == null) || (currentThemeIsDark.booleanValue() != newThemeStatus)) {
+						if (currentThemeIsDark != null) {
+							d.asyncExec(() -> {
+								MessageDialog.openInformation(d.getActiveShell(), "Theme Change",
+										"You will need to close any open views and editors, then re-open them, to have "
+												+ "your theme change fully reflected (or restart the Toolbox.)");
+							});
+            			}
+						
+            			currentThemeIsDark = Boolean.valueOf(newThemeStatus);
+            		}
+            	}
+            }
+    	}
     }
+	
+	/**
+	 * @return true if the current UI theme is dark
+	 */
+	public boolean isCurrentThemeDark() {
+		return (currentThemeIsDark == null) ? false : currentThemeIsDark.booleanValue();
+	}
 
     /**
      * @return
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditorAndPDFViewer.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditorAndPDFViewer.java
index da27349fd29275bcc7e5850406f398f18819f07c..3d7597949431704395c890881888039838ce7c8d 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditorAndPDFViewer.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditorAndPDFViewer.java
@@ -24,6 +24,7 @@ import org.eclipse.ui.INavigationLocation;
 import org.eclipse.ui.INavigationLocationProvider;
 import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.forms.editor.FormEditor;
+import org.eclipse.ui.forms.editor.IFormPage;
 import org.eclipse.ui.part.FileEditorInput;
 import org.eclipse.ui.texteditor.IDocumentProvider;
 import org.eclipse.ui.texteditor.ITextEditor;
@@ -62,6 +63,7 @@ public class TLAEditorAndPDFViewer extends FormEditor implements INavigationLoca
     /* (non-Javadoc)
      * @see org.eclipse.ui.forms.editor.FormEditor#addPages()
      */
+    @Override
     protected void addPages()
     {
         try
@@ -71,7 +73,16 @@ public class TLAEditorAndPDFViewer extends FormEditor implements INavigationLoca
             // This makes them more obvious to the user.
             if (getContainer() instanceof CTabFolder)
             {
-                ((CTabFolder) getContainer()).setTabPosition(SWT.TOP);
+                final CTabFolder cTabFolder = (CTabFolder) getContainer();
+				cTabFolder.setTabPosition(SWT.TOP);
+				
+				// If there is only the editor but no PDF shown next to it, the tab bar of the
+				// ctabfolder just wastes screen estate.
+				if (cTabFolder.getItemCount() <= 1) {
+					cTabFolder.setTabHeight(0);
+				} else {
+					cTabFolder.setTabHeight(-1);
+				}
             }
 
             tlaEditor = new TLAEditor();
@@ -79,13 +90,45 @@ public class TLAEditorAndPDFViewer extends FormEditor implements INavigationLoca
             addPage(tlaEditorIndex, tlaEditor, tlaEditorInput);
             setPageText(tlaEditorIndex, "TLA Module");
 
-            setDescription();
-
         } catch (PartInitException e)
         {
+        	// I hope you don't choke swallowing all those exceptions...
             e.printStackTrace();
         }
     }
+    
+	
+	@Override
+	public int addPage(IFormPage page) throws PartInitException {
+		final int idx = super.addPage(page);
+		
+		if (getContainer() instanceof CTabFolder) {
+			final CTabFolder cTabFolder = (CTabFolder) getContainer();
+			// If there is only the editor but no PDF shown next to it, the tab bar of the
+			// ctabfolder just wastes screen estate.
+			if (cTabFolder.getItemCount() <= 1) {
+				cTabFolder.setTabHeight(0);
+			} else {
+				cTabFolder.setTabHeight(-1);
+			}
+		}
+		return idx;
+	}
+
+	@Override
+	public void removePage(int pageIndex) {
+		super.removePage(pageIndex);
+		if (getContainer() instanceof CTabFolder) {
+			final CTabFolder cTabFolder = (CTabFolder) getContainer();
+			// If there is only the editor but no PDF shown next to it, the tab bar of the
+			// ctabfolder just wastes screen estate.
+			if (cTabFolder.getItemCount() <= 1) {
+				cTabFolder.setTabHeight(0);
+			} else {
+				cTabFolder.setTabHeight(-1);
+			}
+		}
+	}
 
     /* (non-Javadoc)
      * @see org.eclipse.ui.forms.editor.FormEditor#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
@@ -105,7 +148,7 @@ public class TLAEditorAndPDFViewer extends FormEditor implements INavigationLoca
 					// MAK 04/2019: Strip off filename extension to align with Toolbox's Spec
 					// Explorer which doesn't show the extension either.  The Toolbox only has
 					// two editors (TLA+ specs and TLC models).  Showing the extension thus
-					// provides little value to users.  Aslo the editor description shows the
+					// provides little value to users.  Also, the editor description shows the
 					// full path to the actual file on disk right below where the part name
 					// is shown.
                     this.setPartName(file.getName().replaceFirst(".tla$", ""));
@@ -238,7 +281,6 @@ public class TLAEditorAndPDFViewer extends FormEditor implements INavigationLoca
                         {
                             FileEditorInput fin = (FileEditorInput) newInput;
                             setPartName(fin.getFile().getName());
-                            setDescription();
                         }
                     }
                 }
@@ -303,26 +345,24 @@ public class TLAEditorAndPDFViewer extends FormEditor implements INavigationLoca
     {
         return tlaEditor;
     }
-
-    /**
-     * Sets the text that appears above the text viewer.
-     * Currently, this is the full file path.
-     */
-    private void setDescription()
-    {
-        IEditorInput input = getEditorInput();
-        if (input != null)
-        {
-            if (input instanceof FileEditorInput)
-            {
-                FileEditorInput fin = (FileEditorInput) input;
-                setContentDescription(fin.getPath().toOSString());
-            } else
-            {
-                setContentDescription(input.getName());
-            }
-        }
-    }
+    
+	@Override
+	public void setFocus() {
+		super.setFocus();
+
+		// Show the OS's location of this spec in the Toolbox's status line (bottom
+		// left). Before, this was shown in this editor's content description but this
+		// wastes too much space.
+		final IEditorInput input = getEditorInput();
+		if (input != null) {
+			if (input instanceof FileEditorInput) {
+				FileEditorInput fin = (FileEditorInput) input;
+				tlaEditor.setStatusMessage(String.format("%s [ %s ]", getPartName(), fin.getPath().toOSString()));
+			} else {
+				tlaEditor.setStatusMessage(input.getName());
+			}
+		}
+	}
     
     /**
      * Sets the TLA module editor as the active
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAReconcilingStrategy.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAReconcilingStrategy.java
index bfdae3df3fecfd3aa57c6fe8e756a7f220e99e6e..48b1dfaef329f7e59c44118e38263273da1bb1f8 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAReconcilingStrategy.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAReconcilingStrategy.java
@@ -1,152 +1,396 @@
 package org.lamport.tla.toolbox.editor.basic;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.BadPartitioningException;
+import org.eclipse.jface.text.FindReplaceDocumentAdapter;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.IDocumentExtension3;
 import org.eclipse.jface.text.IRegion;
-import org.eclipse.jface.text.ITypedRegion;
 import org.eclipse.jface.text.Position;
 import org.eclipse.jface.text.reconciler.DirtyRegion;
 import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
 import org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension;
-import org.eclipse.swt.widgets.Display;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.projection.ProjectionAnnotation;
+import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel;
+import org.eclipse.jface.text.source.projection.ProjectionViewer;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.ui.PlatformUI;
+import org.lamport.tla.toolbox.editor.basic.pcal.IPCalReservedWords;
+import org.lamport.tla.toolbox.util.pref.IPreferenceConstants;
+import org.lamport.tla.toolbox.util.pref.PreferenceStoreHelper;
 
 /**
- * @author Simon Zambrovski
- * @version $Id$
+ * We create this reconciling strategy for at least two reasons:
+ * 	. having our custom source viewer configuration not use its super class' reconciler frees us from spell checking
+ * 		markup
+ * 	. to find fold locations for:
+ * 			. block commments
+ * 			. PlusCal code
  */
-public class TLAReconcilingStrategy implements IReconcilingStrategy, IReconcilingStrategyExtension
-{
-    /* document to reconciler */
+public class TLAReconcilingStrategy implements IPropertyChangeListener, IReconcilingStrategy, IReconcilingStrategyExtension {
+	// Per BoxedCommentHandler, a delimiter is "(" followed by three "*", then 0-N "*", and finally suffixed with ")"
+	private static final String BLOCK_COMMENT_DELIMITER_REGEX = "^[ \\t]*\\(\\*{3}\\**\\)\\s*$";
+	// 
+	private static final String SINGLE_LINE_COMMENT = "^[ \\t]*\\\\\\*";
+	
+	private static final String PCAL_TRANSLATION_PREFIX_REGEX = "^\\\\\\*+ BEGIN TRANSLATION.*$";
+	private static final String PCAL_TRANSLATION_SUFFIX_REGEX = "^\\\\\\*+ END TRANSLATION.*$";
+	
+	
     private IDocument document;
-    /* holds the calculated positions */
-    protected final List<Position> positions = new ArrayList<Position>();
-    /* editor to be updated */
+    /* the currently displayed projection annotations */
+    protected final List<TLCProjectionAnnotation> currentAnnotations;
+    /* the editor we're bound to */
     private TLAEditor editor;
+    /* the underlying source viewer */
+    private ProjectionViewer projectionViewer;
+    
+    private final AtomicBoolean foldBlockComments;
+    private final AtomicBoolean foldPlusCalAlgorithm;
+    private final AtomicBoolean foldTranslatedPlusCalBlock;
+	
+    public TLAReconcilingStrategy() {
+        final IPreferenceStore store = PreferenceStoreHelper.getInstancePreferenceStore();
 
-    /* (non-Javadoc)
-     * @see org.eclipse.jface.text.reconciler.IReconcilingStrategy#reconcile(org.eclipse.jface.text.IRegion)
-     */
-    public void reconcile(IRegion partition)
-    {
-        initialReconcile();
+        store.addPropertyChangeListener(this);
+        
+        currentAnnotations = new ArrayList<>();
+        
+        foldBlockComments = new AtomicBoolean(store.getBoolean(IPreferenceConstants.I_FOLDING_BLOCK_COMMENTS));
+        foldPlusCalAlgorithm = new AtomicBoolean(store.getBoolean(IPreferenceConstants.I_FOLDING_PCAL_ALGORITHM));
+        foldTranslatedPlusCalBlock = new AtomicBoolean(store.getBoolean(IPreferenceConstants.I_FOLDING_PCAL_TRANSLATED));
     }
-
-    /* (non-Javadoc)
-     * @see org.eclipse.jface.text.reconciler.IReconcilingStrategy#reconcile(org.eclipse.jface.text.reconciler.DirtyRegion, org.eclipse.jface.text.IRegion)
-     */
-    public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion)
-    {
-        initialReconcile();
+    
+    public void dispose() {
+        final IPreferenceStore store = PreferenceStoreHelper.getInstancePreferenceStore();
+        store.removePropertyChangeListener(this);
     }
+    
+	/**
+     * {@inheritDoc}
+     */
+    @Override
+	public void propertyChange(final PropertyChangeEvent event) {
+    	final boolean reconcile;
+    	
+		if (IPreferenceConstants.I_FOLDING_BLOCK_COMMENTS.equals(event.getProperty())) {
+			foldBlockComments.set(((Boolean)event.getNewValue()).booleanValue());
+			reconcile = true;
+		} else if (IPreferenceConstants.I_FOLDING_PCAL_ALGORITHM.equals(event.getProperty())) {
+			foldPlusCalAlgorithm.set(((Boolean)event.getNewValue()).booleanValue());
+			reconcile = true;
+		} else if (IPreferenceConstants.I_FOLDING_PCAL_TRANSLATED.equals(event.getProperty())) {
+			foldTranslatedPlusCalBlock.set(((Boolean)event.getNewValue()).booleanValue());
+			reconcile = true;
+		} else {
+			reconcile = false;
+		}
+		
+		if (reconcile) {
+			reconcile(null, null, null);
+		}
+	}
 
-    /* (non-Javadoc)
-     * @see org.eclipse.jface.text.reconciler.IReconcilingStrategy#setDocument(org.eclipse.jface.text.IDocument)
+	/**
+     * {@inheritDoc}
      */
-    public void setDocument(IDocument document)
-    {
-        this.document = document;
-    }
+    @Override
+	public void reconcile(final IRegion partition) {
+    	reconcile(partition, null, null);
+	}
 
-    /* (non-Javadoc)
-     * @see org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension#initialReconcile()
+    /**
+     * {@inheritDoc}
      */
-    public void initialReconcile()
-    {
-        // delete existing
-        positions.clear();
-
-        // calculate new partitions
-        calculatePositions();
-
-        // update the editor
-        if (editor != null) {
-        	Display.getDefault().asyncExec(new Runnable() {
-        		public void run()
-        		{
-        			editor.updateFoldingStructure(positions);
-        		}
-        	});
-        }
-    }
+    @Override
+	public void reconcile(final DirtyRegion dirtyRegion, final IRegion subRegion) {
+    	reconcile(null, dirtyRegion, subRegion);
+	}
 
-    /* (non-Javadoc)
-     * @see org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension#setProgressMonitor(org.eclipse.core.runtime.IProgressMonitor)
+    /**
+     * {@inheritDoc}
      */
-    public void setProgressMonitor(IProgressMonitor monitor)
-    {
+    @Override
+	public void setDocument(final IDocument id) {
+		document = id;
+	}
 
-    }
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+	public void initialReconcile() {
+    	reconcile(null, null, null);
+	}
 
     /**
-     * @return Returns the editor.
+     * {@inheritDoc}
      */
-    public TLAEditor getEditor()
-    {
-        return this.editor;
-    }
+    @Override
+    public void setProgressMonitor(final IProgressMonitor monitor) { }
 
     /**
-     * Sets the editor
+     * Sets the editor to which we're bound; this is required for communicating folding projections.
+     * 
      * @param editor
      */
-    public void setEditor(TLAEditor editor)
-    {
-        this.editor = editor;
-    }
+	public void setEditor(final TLAEditor tlaEditor) {
+		editor = tlaEditor;
+	}
+	
+	/**
+	 * Sets the projection viewer for which we're reconciling.
+	 * 
+	 * @param viewer
+	 */
+	public void setProjectionViewer(final ProjectionViewer viewer) {
+		projectionViewer = viewer;
+		projectionViewer.setData(getClass().toString(), this);
+	}
+	
+	private void reconcile(final IRegion partition, final DirtyRegion dirtyRegion, final IRegion subRegion) {
+		if (editor != null) {
+			final HashMap<TLCProjectionAnnotation, Position> regionMap
+													= determineFoldingRegions(partition, dirtyRegion, subRegion);
+			final Annotation[] deletions;
+			final HashMap<TLCProjectionAnnotation, Position> regionsToAdd = new HashMap<>();
+			synchronized (currentAnnotations) {
+				for (final Map.Entry<TLCProjectionAnnotation, Position> me : regionMap.entrySet()) {
+					if (!currentAnnotations.remove(me.getKey())) {
+						regionsToAdd.put(me.getKey(), me.getValue());
+					}
+				}
+				
+				deletions = currentAnnotations.toArray(new Annotation[currentAnnotations.size()]);
+				currentAnnotations.clear();
+				currentAnnotations.addAll(regionMap.keySet());
+			}
+			PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+				public void run() {
+					editor.modifyProjectionAnnotations(deletions, regionsToAdd);
+					
+					if (projectionViewer != null) {
+						final ProjectionAnnotationModel model = projectionViewer.getProjectionAnnotationModel();
+						final boolean block = foldBlockComments.get();
+						final boolean pcal = foldPlusCalAlgorithm.get();
+						final boolean translated = foldTranslatedPlusCalBlock.get();
+
+						// We could do even more optimization than this, but this is better than none.
+						if (block || pcal || translated) {
+							for (final TLCProjectionAnnotation annotation : currentAnnotations) {
+								final boolean collapse;
 
+								switch (annotation.getTLCType()) {
+									case BLOCK_COMMENT:
+										collapse = block;
+										break;
+									case PCAL_BLOCK:
+										collapse = pcal;
+										break;
+									default:
+										collapse = translated;
+								}
+
+								if (collapse) {
+									model.collapse(annotation);
+								}
+							}
+						}
+					}
+				}
+			});
+		}
+	}
+	
     /**
-     * get partitions  
+     * Once upon a time (the original version of this,) document partitioning was performed via
+     * 	{@link IDocumentExtension3#computePartitioning(String, int, int, boolean)} and it did a
+     * 	terrible job. Now, instead, we're using the Eclipse {@link FindReplaceDocumentAdapter} class.
      */
-    protected void calculatePositions()
-    {
-        try
-        {
-            IDocumentExtension3 extension = (IDocumentExtension3) document;
-            // get partitions
-            ITypedRegion[] partitions = extension.computePartitioning(TLAPartitionScanner.TLA_PARTITIONING, 0, document
-                    .getLength(), false);
-            // install positions
-            for (int i = 0; i < partitions.length; i++)
-            {
-                IRegion lineOnPartitionStart = document.getLineInformationOfOffset(partitions[i].getOffset());
-
-                // if the multi-line comment contains multiple lines
-                // Added by LL on 16 Aug 2012:  I have no idea what this does.  Since the TLA_PCAL
-                // partitions added for PlusCal can also contain multiple lines,  I guessed that
-                // whatever is done for TLA_MULTI_LINE_COMMENT partitions should also be done for
-                // TLA_PCAL partitions.   However, I discovered that my original implementation
-                // added bogus foldings in the PlusCal algorithm.  Not adding the TLA_PCAL partitions
-                // solved this problem (except for a harmless folding of the starting comment if it occupies
-                // an entire line).  I have no idea if this is used for anything else, so it's
-                // possible that not adding them will break something else.   However, this method
-                // is called only by initialReconcile, which also calls TLAEditor.updateFoldingStructure.
-                // The latter method has a comment saying it's only used for comment folding (and it's
-                // incorrect).  So, there's a good chance that everything is OK.
-                // 
-                if (   (   partitions[i].getType().equals(TLAPartitionScanner.TLA_MULTI_LINE_COMMENT)
-                //   || partitions[i].getType().equals(TLAPartitionScanner.TLA_PCAL))   // This disjunct was added for PlusCal
-                   )
-                    && partitions[i].getLength() > lineOnPartitionStart.getLength())
-                {
-                    positions.add(new Position(partitions[i].getOffset(), partitions[i].getLength()));
-                }
-            }
-
-        } catch (BadLocationException e)
-        {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        } catch (BadPartitioningException e)
-        {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
+	private HashMap<TLCProjectionAnnotation, Position> determineFoldingRegions(final IRegion partition,
+			final DirtyRegion dirtyRegion, final IRegion subRegion) {
+    	// TODO use regions for tracking in optimizations on re-parses
+//		final boolean isInitialParse = ((partition == null) && (dirtyRegion == null) && (subRegion == null));
+		
+		final HashMap<TLCProjectionAnnotation, Position> additions = new HashMap<>();
+
+		final FindReplaceDocumentAdapter search = new FindReplaceDocumentAdapter(document);
+		
+		// PCal location
+		try {
+			IRegion find = search.find(0, IPCalReservedWords.ALGORITHM, true, true, false, false);
+			
+			if (find == null) {
+				find = search.find(0, "--" + IPCalReservedWords.FAIR, true, true, false, false);
+			}
+			
+			if (find != null) {
+				final int pcalStartLocation = find.getOffset();
+				
+				find = search.find(pcalStartLocation, "^\\(\\*", false, true, false, true);
+				if (find != null) {
+					final int startLocation = find.getOffset();
+					
+					find = search.find(pcalStartLocation, "^\\s?\\*+\\)$", true, true, false, true);
+					addProjectionAdditionToMap(additions, startLocation, find, AnnotationType.PCAL_BLOCK);
+				}
+			}
+		} catch (final BadLocationException ble) { }
+		
+		
+		// Translated PCal location
+		try {
+			IRegion find = search.find(0, PCAL_TRANSLATION_PREFIX_REGEX, true, true, false, true);
+			
+			if (find != null) {
+				final int translationStartLocation = find.getOffset();
+				
+				find = search.find(translationStartLocation, PCAL_TRANSLATION_SUFFIX_REGEX, true, true, false, true);
+				if (find != null) {
+					addProjectionAdditionToMap(additions, translationStartLocation, find,
+							AnnotationType.TRANSLATED_PCAL_BLOCK);
+				}
+			}
+		} catch (final BadLocationException ble) { }
+		
+		
+		// Block comment locations
+		try {
+			boolean inBlock = false;
+			int lastFoundIndex = 0; // TODO future optimizations based on DocumentEvents' locations
+			IRegion find = search.find(lastFoundIndex, BLOCK_COMMENT_DELIMITER_REGEX, true, true, false, true);
+			
+			while (find != null) {
+				if (inBlock) {
+					addProjectionAdditionToMap(additions, lastFoundIndex, find, AnnotationType.BLOCK_COMMENT);
+				}
+				
+				inBlock = !inBlock;
+				lastFoundIndex = find.getOffset();
+				find = search.find((lastFoundIndex + find.getLength()), BLOCK_COMMENT_DELIMITER_REGEX, true, true, false, true);
+			}
+		} catch (final BadLocationException ble) { }
+		
+		// 2 or more consecutive single line comments
+		try {
+			int lastFoundIndex = 0; // TODO future optimizations based on DocumentEvents' locations
+			IRegion find = search.find(lastFoundIndex, SINGLE_LINE_COMMENT, true, true, false, true);
+			
+			int contiguousLineCount = 1;
+			int firstMatchingOffset = -1;
+			while (find != null) {
+				if (firstMatchingOffset == -1) {
+					firstMatchingOffset = find.getOffset();
+				}
+				lastFoundIndex = find.getOffset();
+				final IRegion lineEnding = search.find((lastFoundIndex + find.getLength()), "\\n", true, true, false, true);
+				if (lineEnding != null) {
+					lastFoundIndex = lineEnding.getOffset();
+					find = search.find((lastFoundIndex + 1), SINGLE_LINE_COMMENT, true, true, false, true);
+				} else {
+					// In this case the document has ended without a newline (but with a comment)
+					lastFoundIndex += find.getLength();
+					find = null;
+				}
+				
+				boolean addProjection = (contiguousLineCount > 1);
+				boolean reset = true;
+				if ((find != null) && (find.getOffset() == (lastFoundIndex + 1))) {
+					contiguousLineCount++;
+					addProjection = false;
+					reset = false;
+				}
+				if (addProjection) {
+					addProjectionAdditionToMap(additions, firstMatchingOffset, lastFoundIndex,
+											   AnnotationType.MULTIPLE_SINGLE_LINE_COMMENT);
+				}
+				if (reset) {
+					contiguousLineCount = 1;
+					firstMatchingOffset = -1;
+				}
+			}
+		} catch (final BadLocationException ble) { }
+		
+		return additions;
     }
 
+	private void addProjectionAdditionToMap(final Map<TLCProjectionAnnotation, Position> additions, final int startLocation,
+										    final IRegion find, final AnnotationType type)
+			throws BadLocationException {
+		if (find != null) {
+			final int endLocation = find.getOffset() + find.getLength() + 1;
+			addProjectionAdditionToMap(additions, startLocation, endLocation, type);
+		}
+	}
+
+	private void addProjectionAdditionToMap(final Map<TLCProjectionAnnotation, Position> additions, final int startLocation,
+										    final int endLocation, final AnnotationType type)
+			throws BadLocationException {
+		final int length = endLocation - startLocation;
+		final int positionLength = length + ((document.getLength() > endLocation) ? 1 : 0);	// +1 to cover the newline
+		final Position position = new Position(startLocation, positionLength);
+
+		additions.put(new TLCProjectionAnnotation(document.get(startLocation, length), type), position);
+	}
+	
+	
+	private enum AnnotationType {
+		BLOCK_COMMENT,
+		MULTIPLE_SINGLE_LINE_COMMENT,
+		PCAL_BLOCK,
+		TRANSLATED_PCAL_BLOCK;
+	}
+	
+	// Nothing in the ProjectionAnnotation hierarchy implements equals/hashCode, we'd like such things to exist
+	//		for reconciliation; also we denote classifications of annotations for folding groups.
+	private static class TLCProjectionAnnotation extends ProjectionAnnotation {
+		private final AnnotationType type;
+		
+		TLCProjectionAnnotation(final String text, final AnnotationType annotationType) {
+			setText(text);
+			
+			type = annotationType;
+		}
+		
+		AnnotationType getTLCType() {
+			return type;
+		}
+		
+		@Override
+		public boolean equals(final Object other) {
+			if (other == null) {
+				return false;
+			}
+			
+			if (!Annotation.class.isAssignableFrom(other.getClass())) {
+				return false;
+			}
+			
+			final Annotation otherAnnotation = (Annotation)other;
+			final String otherText = otherAnnotation.getText();
+			
+			return Objects.equals(getText(), otherText);
+		}
+		
+		@Override
+		public int hashCode() {
+			final String text = getText();
+			
+			if (text == null) {
+				return 0;
+			}
+			
+			return text.hashCode();
+		}
+	}
 }
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLASourceViewerConfiguration.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLASourceViewerConfiguration.java
index 00b75ee62929785a81cca345c0b6aba3b2928e53..8a5679c02a61b870a5f258d76669c87b7327c1c7 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLASourceViewerConfiguration.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLASourceViewerConfiguration.java
@@ -23,6 +23,7 @@ import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
 import org.eclipse.jface.text.rules.Token;
 import org.eclipse.jface.text.source.IAnnotationHover;
 import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.projection.ProjectionViewer;
 import org.eclipse.swt.custom.StyledText;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Shell;
@@ -68,10 +69,9 @@ public class TLASourceViewerConfiguration extends TextSourceViewerConfiguration
      * The partitioner computes the partitions at the appropriate times and then the various
      * damager-repairers set in this method compute the coloring for the partitions.
      */
-    public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer)
-    {
-        TLAColorProvider provider = TLAEditorActivator.getDefault().getTLAColorProvider();
-        PresentationReconciler reconciler = new PresentationReconciler();
+	public IPresentationReconciler getPresentationReconciler(final ISourceViewer sourceViewer) {
+		final TLAColorProvider provider = TLAEditorActivator.getDefault().getTLAColorProvider();
+		final PresentationReconciler reconciler = new PresentationReconciler();
         reconciler.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer));
 
         DefaultDamagerRepairer dr = new DefaultDamagerRepairer(TLAEditorActivator.getDefault().getTLACodeScanner());
@@ -79,17 +79,17 @@ public class TLASourceViewerConfiguration extends TextSourceViewerConfiguration
         reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE);
 
         dr = new DefaultDamagerRepairer(new SingleTokenScanner(new TextAttribute(provider
-                .getColor(TLAColorProvider.TLA_MULTI_LINE_COMMENT))));
+                .getColor(TLAColorProvider.TLA_MULTI_LINE_COMMENT_KEY))));
         reconciler.setDamager(dr, TLAPartitionScanner.TLA_MULTI_LINE_COMMENT);
         reconciler.setRepairer(dr, TLAPartitionScanner.TLA_MULTI_LINE_COMMENT);
 
         dr = new DefaultDamagerRepairer(new SingleTokenScanner(new TextAttribute(provider
-                .getColor(TLAColorProvider.TLA_SINGLE_LINE_COMMENT))));
+                .getColor(TLAColorProvider.TLA_SINGLE_LINE_COMMENT_KEY))));
         reconciler.setDamager(dr, TLAPartitionScanner.TLA_SINGLE_LINE_COMMENT);
         reconciler.setRepairer(dr, TLAPartitionScanner.TLA_SINGLE_LINE_COMMENT);
 
         dr = new DefaultDamagerRepairer(new SingleTokenScanner(new TextAttribute(provider
-                .getColor(TLAColorProvider.TLA_VALUE))));
+                .getColor(TLAColorProvider.TLA_VALUE_KEY))));
         reconciler.setDamager(dr, TLAPartitionScanner.TLA_STRING);
         reconciler.setRepairer(dr, TLAPartitionScanner.TLA_STRING);
 
@@ -146,7 +146,7 @@ public class TLASourceViewerConfiguration extends TextSourceViewerConfiguration
         assistant.setProposalPopupOrientation(IContentAssistant.PROPOSAL_OVERLAY);
         assistant.setContextInformationPopupOrientation(IContentAssistant.CONTEXT_INFO_ABOVE);
         assistant.setContextInformationPopupBackground(TLAEditorActivator.getDefault().getTLAColorProvider().getColor(
-                TLAColorProvider.CONTENT_ASSIST_BACKGROUNG));
+                TLAColorProvider.CONTENT_ASSIST_BACKGROUND_KEY));
         return assistant;
     }
 
@@ -185,12 +185,14 @@ public class TLASourceViewerConfiguration extends TextSourceViewerConfiguration
     /**
      * 
      */
-    public IReconciler getReconciler(ISourceViewer sourceViewer)
-    {
-        TLAReconcilingStrategy strategy = new TLAReconcilingStrategy();
+    @Override
+	public IReconciler getReconciler(final ISourceViewer sourceViewer) {
+        final TLAReconcilingStrategy strategy = new TLAReconcilingStrategy();
         strategy.setEditor(editor);
-        MonoReconciler reconciler = new MonoReconciler(strategy, false);
-        return reconciler;
+        if (sourceViewer instanceof ProjectionViewer) {
+        	strategy.setProjectionViewer((ProjectionViewer)sourceViewer);
+        }
+        return new MonoReconciler(strategy, false);
     }
 
     /**
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/DefineFoldingRegionAction.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/DefineFoldingRegionAction.java
index 1e9a53d50ef6d8a13e84dc12a55614fb9773f443..a1925bbb2d607fee06dfa805ab25bcce7538db35 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/DefineFoldingRegionAction.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/DefineFoldingRegionAction.java
@@ -14,9 +14,12 @@ import org.eclipse.ui.texteditor.ITextEditor;
 import org.eclipse.ui.texteditor.TextEditorAction;
 
 /**
- * Define folding region action
+ * Define folding region action.
+ * 
+ * Deprecated in August 2019 as it is not being used in our codebase. (At one time is was in TLAEditor.createActions().)
+ * 
  * @author Simon Zambrovski
- * @version $Id$
+ * @deprecated
  */
 public class DefineFoldingRegionAction extends TextEditorAction
 {
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/BoxedCommentHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/BoxedCommentHandler.java
index 7ff154f23517a6c34ac407774dc595df27d6cbaf..79248844147bff9ff80930d12cbcea0aee523545 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/BoxedCommentHandler.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/BoxedCommentHandler.java
@@ -17,9 +17,10 @@ import org.lamport.tla.toolbox.Activator;
 import org.lamport.tla.toolbox.editor.basic.TLAEditor;
 import org.lamport.tla.toolbox.editor.basic.util.EditorUtil;
 import org.lamport.tla.toolbox.ui.preference.EditorPreferencePage;
-import org.lamport.tla.toolbox.util.StringHelper;
 import org.lamport.tla.toolbox.util.UIHelper;
 
+import util.StringHelper;
+
 /**
  * This is the handler method for the following commands:
  * 
@@ -168,12 +169,12 @@ public class BoxedCommentHandler extends AbstractHandler implements IHandler {
 
 		String asterisks = StringHelper.copyString("*", Math.max(3, RightMargin
 				- indent - 1));
-		String newText = "(" + asterisks + StringHelper.newline
-				+ StringHelper.newline + StringHelper.copyString(" ", indent)
-				+ asterisks + ")" + (dontAddNewLine ? "" : StringHelper.newline);
+		String newText = "(" + asterisks + StringHelper.PLATFORM_NEWLINE
+				+ StringHelper.PLATFORM_NEWLINE + StringHelper.copyString(" ", indent)
+				+ asterisks + ")" + (dontAddNewLine ? "" : StringHelper.PLATFORM_NEWLINE);
 		doc.replace(selection.getOffset(), selection.getLength(), newText);
 		selectionProvider.setSelection(new TextSelection(offset + 1
-				+ asterisks.length() + StringHelper.newline.length(), 0));
+				+ asterisks.length() + StringHelper.PLATFORM_NEWLINE.length(), 0));
 	}
 
 	private void formatAndBoxComment()
@@ -262,7 +263,7 @@ public class BoxedCommentHandler extends AbstractHandler implements IHandler {
 
 		StringBuffer buffer = new StringBuffer(4 * margin);
 		buffer.append(makeCommentBoxStart());
-		buffer.append(StringHelper.newline);
+		buffer.append(StringHelper.PLATFORM_NEWLINE);
 
 		// Handle special case of entire comment on one line.
 		if (beginLine == endLine) {
@@ -273,7 +274,7 @@ public class BoxedCommentHandler extends AbstractHandler implements IHandler {
 			buffer
 					.append(makeCommentBoxLine(StringHelper
 							.trimFront(singleLine)));
-			buffer.append(StringHelper.newline);
+			buffer.append(StringHelper.PLATFORM_NEWLINE);
 		} else {
 
 			// Produce a first line for anything after the (* on its line.
@@ -285,13 +286,13 @@ public class BoxedCommentHandler extends AbstractHandler implements IHandler {
 			if (!StringHelper.onlySpaces(restOfLine)) {
 				buffer.append(makeCommentBoxLine(StringHelper
 						.trimFront(restOfLine)));
-				buffer.append(StringHelper.newline);
+				buffer.append(StringHelper.PLATFORM_NEWLINE);
 			}
 
 			for (int i = beginLine + 1; i < endLine; i++) {
 				buffer.append(makeCommentBoxLine(doc.get(doc.getLineOffset(i),
 						doc.getLineLength(i))));
-				buffer.append(StringHelper.newline);
+				buffer.append(StringHelper.PLATFORM_NEWLINE);
 			}
 
 			// Produce a last line for anything before the *) on its line.
@@ -300,7 +301,7 @@ public class BoxedCommentHandler extends AbstractHandler implements IHandler {
 					- endCommentLength - lineOffset);
 			if (!StringHelper.onlySpaces(startOfLine)) {
 				buffer.append(makeCommentBoxLine(startOfLine));
-				buffer.append(StringHelper.newline);
+				buffer.append(StringHelper.PLATFORM_NEWLINE);
 			}
 		}
 
@@ -311,7 +312,7 @@ public class BoxedCommentHandler extends AbstractHandler implements IHandler {
 		if (!StringHelper.onlySpaces(doc.get(endCommentOffset, doc
 				.getLineOffset(endLine)
 				- endCommentOffset + doc.getLineLength(endLine)))) {
-			buffer.append(StringHelper.newline);
+			buffer.append(StringHelper.PLATFORM_NEWLINE);
 		}
 
 		doc.replace(beginCommentOffset, endCommentOffset - beginCommentOffset,
@@ -379,7 +380,7 @@ public class BoxedCommentHandler extends AbstractHandler implements IHandler {
 		// and the ending ) . We must therefore begin
 		// with asterisks and a StringHelper.newline;
 		buffer.append(asterisks);
-		buffer.append(StringHelper.newline);
+		buffer.append(StringHelper.PLATFORM_NEWLINE);
 
 		// process the individual lines.
 		for (int i = beginLine + 1; i < endLine; i++) {
@@ -392,10 +393,10 @@ public class BoxedCommentHandler extends AbstractHandler implements IHandler {
 					&& (!(beginTokenIndex > endTokenIndex))) {
 				buffer.append(StringHelper.trimEnd(currentLine.substring(
 						beginTokenIndex + 3, endTokenIndex)));
-				buffer.append(StringHelper.newline);
+				buffer.append(StringHelper.PLATFORM_NEWLINE);
 			} else {
 				buffer.append(currentLine);
-				buffer.append(StringHelper.newline);
+				buffer.append(StringHelper.PLATFORM_NEWLINE);
 			}
 
 		}
@@ -463,12 +464,12 @@ public class BoxedCommentHandler extends AbstractHandler implements IHandler {
 				// Output a StringHelper.newline if there's an unfinished
 				// paragraph.
 				if (unfinishedLineWidth > 0) {
-					buffer.append(StringHelper.newline);
+					buffer.append(StringHelper.PLATFORM_NEWLINE);
 					unfinishedLineWidth = 0;
 				}
 				// Output the line and an endline
 				buffer.append(currentLine);
-				buffer.append(StringHelper.newline);
+				buffer.append(StringHelper.PLATFORM_NEWLINE);
 			} else {
 				// This line is part of a paragraph. Set the array words
 				// to the words on this line.
@@ -491,7 +492,7 @@ public class BoxedCommentHandler extends AbstractHandler implements IHandler {
 						int nextWidth = unfinishedLineWidth
 								+ (followsPeriod ? 2 : 1) + nextWord.length();
 						if (nextWidth > lineWidth) {
-							buffer.append(StringHelper.newline);
+							buffer.append(StringHelper.PLATFORM_NEWLINE);
 							buffer.append(nextWord);
 							unfinishedLineWidth = nextWord.length();
 						} else {
@@ -506,7 +507,7 @@ public class BoxedCommentHandler extends AbstractHandler implements IHandler {
 		} // end for
 		// Output a newline if there's an unfinished paragraph.
 		if (unfinishedLineWidth > 0) {
-			buffer.append(StringHelper.newline);
+			buffer.append(StringHelper.PLATFORM_NEWLINE);
 			unfinishedLineWidth = 0;
 		}
 		doc.replace(beginReplacementOffset, endReplacementOffset
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/CommandPrefixDigitHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/CommandPrefixDigitHandler.java
index a125190ff2538bed9cc437738c2c5a522b84b14e..bab0187b27d1ce173c9a53c3d5086f0893b7cb37 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/CommandPrefixDigitHandler.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/CommandPrefixDigitHandler.java
@@ -39,6 +39,7 @@ import org.lamport.tla.toolbox.util.ResourceHelper;
 import tla2sany.modanalyzer.SpecObj;
 import tla2sany.semantic.ModuleNode;
 import tla2sany.semantic.SemanticNode;
+import util.TLAConstants;
 
 /**
  * @author lamport
@@ -80,12 +81,12 @@ public class CommandPrefixDigitHandler extends AbstractHandler implements IHandl
 
         ParserDependencyStorage pds = Activator.getModuleDependencyStorage();     
         String moduleName = EditorUtil.getTLAEditorWithFocus().getModuleName();
-        List vec = pds.getListOfExtendedModules(moduleName + ".tla");
+        List vec = pds.getListOfExtendedModules(moduleName + TLAConstants.Files.TLA_EXTENSION);
         System.out.println("ExtendedModules");
         for (int i = 0; i < vec.size(); i++) {
             System.out.println((String) vec.get(i));
         }
-        vec = pds.getListOfModulesToReparse(moduleName + ".tla");
+        vec = pds.getListOfModulesToReparse(moduleName + TLAConstants.Files.TLA_EXTENSION);
         System.out.println("ModulesToReparse");
         for (int i = 0; i < vec.size(); i++) {
             System.out.println((String) vec.get(i));
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/DecomposeProofHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/DecomposeProofHandler.java
index 5b4f32858b2b35bb1631e2c8c7a98dd05be6ac22..b5ce66314a21a7c75966348b8280788a0a63d89a 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/DecomposeProofHandler.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/DecomposeProofHandler.java
@@ -5,7 +5,7 @@
  *   expands definitions from the instantiated module by replacing the parameter by
  *   the text of the INSTANCE statement.  The problem is manifest in a bad argument
  *   passed to substInNodeToInstanceSub, and that manifestation is explained in comments
- *   starting around line 5333.  (Search for "22 March 2019".)  There are also comments containing 
+ *   starting around line 5342.  (Search for "22 March 2019".)  There are also comments containing 
  *   and explaining an unsuccessful attempt to fix the problem.
  * 
  * CHANGE MADE BY LL on 18 March 2019
@@ -17,6 +17,16 @@
  *   the error.  I left a couple of NewDecompose... in comments that seemed to accompany
  *   commented-out code from that file.
  *     
+ * BUG DISCOVERED in August 2019 
+ *   If a definition in an instantiated module contains an expression like 2 ++ 2
+ *   and the command expands that definition, it produces an expansion that might
+ *   contain the expression 2 I!++ 2 which is illegal, instead of the correct
+ *   expansion I++(2, 2).  This may be difficult to fix.  However, it shouldn't
+ *   be hard to fix what will probably be the most common case:  If the expression
+ *   is 2 + 2, where + is the operator imported from the Standard Module Integers or
+ *   Naturals, and that same + is imported into the current module, then I!+ is
+ *   equivalent to +, so the current 2 I!+ 2 can be changed to 2 + 2.
+ * 
  * IN MIDDLE OF
  * Fixing bug on line 428 of Test.tla.  Will try the approach of adding
  * a global Renaming to the decomposition state to keep track of all renaming in
@@ -524,7 +534,6 @@ import org.lamport.tla.toolbox.spec.parser.ModuleParserLauncher;
 import org.lamport.tla.toolbox.spec.parser.ParseResult;
 import org.lamport.tla.toolbox.util.HelpButton;
 import org.lamport.tla.toolbox.util.ResourceHelper;
-import org.lamport.tla.toolbox.util.StringHelper;
 import org.lamport.tla.toolbox.util.StringSet;
 import org.lamport.tla.toolbox.util.UIHelper;
 
@@ -552,6 +561,8 @@ import tla2sany.semantic.SubstInNode;
 import tla2sany.semantic.SymbolNode;
 import tla2sany.semantic.TheoremNode;
 import tla2sany.st.Location;
+import util.StringHelper;
+import util.TLAConstants;
 import util.UniqueString;
 
 public class DecomposeProofHandler extends AbstractHandler implements
@@ -1952,6 +1963,16 @@ public class DecomposeProofHandler extends AbstractHandler implements
         return null;
     }
 
+    /**
+     * Enabled state is based upon whether the spec has been parsed. (https://github.com/tlaplus/tlaplus/issues/243)
+     */
+    @Override
+	public void setEnabled(Object context) {
+		final Spec spec = Activator.getSpecManager().getSpecLoaded();
+
+		setBaseEnabled(spec.getStatus() == IParseConstants.PARSED);
+	}
+
     /**
      * The Runnable class extension for running the realExecute() method.
      * 
@@ -8550,7 +8571,7 @@ public class DecomposeProofHandler extends AbstractHandler implements
                 try {
                     if (references[i].isDirty()
                             && references[i].getEditorInput().getName()
-                                    .endsWith(".tla")) {
+                                    .endsWith(TLAConstants.Files.TLA_EXTENSION)) {
                         dirtyEditors.add(references[i]);
                     }
                 } catch (PartInitException e) {
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/ExpandAllRegionsHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/ExpandAllRegionsHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..c4f241157320c1b136d1604d6bc0ae7ec0f050fa
--- /dev/null
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/ExpandAllRegionsHandler.java
@@ -0,0 +1,36 @@
+package org.lamport.tla.toolbox.editor.basic.handlers;
+
+import java.util.ResourceBundle;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.text.source.projection.ProjectionViewer;
+import org.eclipse.ui.editors.text.IFoldingCommandIds;
+import org.eclipse.ui.texteditor.TextOperationAction;
+import org.lamport.tla.toolbox.editor.basic.TLAEditor;
+import org.lamport.tla.toolbox.editor.basic.util.EditorUtil;
+
+/**
+ * Expand all foldable regions in the editor in focus.
+ */
+public class ExpandAllRegionsHandler extends AbstractHandler {
+	private static final String BUNDLE_NAME= "org.eclipse.jdt.internal.ui.actions.FoldingMessages";
+	private static final ResourceBundle RESOURCE_BUNDLE= ResourceBundle.getBundle(BUNDLE_NAME);
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+        final TLAEditor editor = EditorUtil.getTLAEditorWithFocus();
+
+		if (editor != null) {
+			final TextOperationAction action = new TextOperationAction(RESOURCE_BUNDLE, "Projection.ExpandAll.", editor,
+					ProjectionViewer.EXPAND_ALL, true);
+
+			action.setActionDefinitionId(IFoldingCommandIds.FOLDING_EXPAND_ALL);
+			action.run();
+        }
+
+        return null;
+	}
+
+}
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/FoldAllRegionsHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/FoldAllRegionsHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..961bda902d4a342737f7da44a454a9b5334053de
--- /dev/null
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/FoldAllRegionsHandler.java
@@ -0,0 +1,35 @@
+package org.lamport.tla.toolbox.editor.basic.handlers;
+
+import java.util.ResourceBundle;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.text.source.projection.ProjectionViewer;
+import org.eclipse.ui.editors.text.IFoldingCommandIds;
+import org.eclipse.ui.texteditor.TextOperationAction;
+import org.lamport.tla.toolbox.editor.basic.TLAEditor;
+import org.lamport.tla.toolbox.editor.basic.util.EditorUtil;
+
+/**
+ * Collapse all foldable regions in the editor in focus.
+ */
+public class FoldAllRegionsHandler extends AbstractHandler {
+	private static final String BUNDLE_NAME= "org.eclipse.jdt.internal.ui.actions.FoldingMessages";
+	private static final ResourceBundle RESOURCE_BUNDLE= ResourceBundle.getBundle(BUNDLE_NAME);
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+        final TLAEditor editor = EditorUtil.getTLAEditorWithFocus();
+
+		if (editor != null) {
+			final TextOperationAction action = new TextOperationAction(RESOURCE_BUNDLE, "Projection.CollapseAll.", editor,
+					ProjectionViewer.COLLAPSE_ALL, true);
+
+			action.setActionDefinitionId(IFoldingCommandIds.FOLDING_COLLAPSE_ALL);
+			action.run();
+        }
+
+        return null;
+	}
+}
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/GotoPCalSourceHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/GotoPCalSourceHandler.java
index 7c070cec10d501868f37c09ffd68a33a161569c3..1d6a91b306658f32059d6007fe25598da1c5e4fa 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/GotoPCalSourceHandler.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/GotoPCalSourceHandler.java
@@ -17,6 +17,8 @@ import org.lamport.tla.toolbox.spec.Spec;
 import org.lamport.tla.toolbox.tool.ToolboxHandle;
 import org.lamport.tla.toolbox.util.UIHelper;
 
+import util.TLAConstants;
+
 /**
  * @author lamport
  *
@@ -57,7 +59,7 @@ public class GotoPCalSourceHandler extends AbstractHandler implements IHandler {
         }
         String moduleName = tlaEditor.getModuleName();
        
-       return spec.getTpMapping(moduleName + ".tla") != null; 
+       return spec.getTpMapping(moduleName + TLAConstants.Files.TLA_EXTENSION) != null; 
     }
 
 }
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/OldDecomposeProofHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/OldDecomposeProofHandler.java
index 177298cfecaa5d2b251d153093779c6cdd7520c6..6ee27d20211a649873890dd0a0f22999961d1d63 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/OldDecomposeProofHandler.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/OldDecomposeProofHandler.java
@@ -287,7 +287,6 @@ import org.lamport.tla.toolbox.spec.parser.ModuleParserLauncher;
 import org.lamport.tla.toolbox.spec.parser.ParseResult;
 import org.lamport.tla.toolbox.util.HelpButton;
 import org.lamport.tla.toolbox.util.ResourceHelper;
-import org.lamport.tla.toolbox.util.StringHelper;
 import org.lamport.tla.toolbox.util.UIHelper;
 
 import tla2sany.parser.SyntaxTreeNode;
@@ -311,6 +310,8 @@ import tla2sany.semantic.SubstInNode;
 import tla2sany.semantic.SymbolNode;
 import tla2sany.semantic.TheoremNode;
 import tla2sany.st.Location;
+import util.StringHelper;
+import util.TLAConstants;
 import util.UniqueString;
 
 public class OldDecomposeProofHandler extends AbstractHandler implements IHandler {
@@ -5334,7 +5335,7 @@ public class OldDecomposeProofHandler extends AbstractHandler implements IHandle
                 try {
                     if (references[i].isDirty()
                             && references[i].getEditorInput().getName()
-                                    .endsWith(".tla")) {
+                                    .endsWith(TLAConstants.Files.TLA_EXTENSION)) {
                         dirtyEditors.add(references[i]);
                     }
                 } catch (PartInitException e) {
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/RenumberProofHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/RenumberProofHandler.java
index 0ed6c78c8ea872125c5612807ded2d4c067b55b3..1f0aa2b01001f23c96005f381237f21a55769b86 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/RenumberProofHandler.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/RenumberProofHandler.java
@@ -22,9 +22,10 @@ import org.eclipse.swt.widgets.Shell;
 import org.lamport.tla.toolbox.Activator;
 import org.lamport.tla.toolbox.editor.basic.TLAEditor;
 import org.lamport.tla.toolbox.editor.basic.util.EditorUtil;
+import org.lamport.tla.toolbox.spec.Spec;
+import org.lamport.tla.toolbox.spec.parser.IParseConstants;
 import org.lamport.tla.toolbox.ui.preference.EditorPreferencePage;
 import org.lamport.tla.toolbox.util.AdapterFactory;
-import org.lamport.tla.toolbox.util.StringHelper;
 import org.lamport.tla.toolbox.util.UIHelper;
 
 import tla2sany.semantic.DefStepNode;
@@ -36,6 +37,7 @@ import tla2sany.semantic.ProofNode;
 import tla2sany.semantic.TheoremNode;
 import tla2sany.semantic.UseOrHideNode;
 import tla2sany.st.Location;
+import util.StringHelper;
 import util.UniqueString;
 
 /**
@@ -398,15 +400,16 @@ public class RenumberProofHandler extends AbstractHandler implements IHandler
         return null;
     }
 
-    /* Disables or enables the command depending on whether the 
-     * cursor is in a step that has a non-leaf proof.  
-     * (non-Javadoc)
-     * @see org.eclipse.core.commands.AbstractHandler#setEnabled(java.lang.Object)
+    /**
+     * Disables or enables the command depending on both whether the cursor is in a step that has a
+     * 	non-leaf proof, and whether the spec has been parsed. (https://github.com/tlaplus/tlaplus/issues/243)
      */
-    public void setEnabled(Object context)
-    {
-        setBaseEnabled(setFields(false));
-    }
+    @Override
+	public void setEnabled(Object context) {
+		final Spec spec = Activator.getSpecManager().getSpecLoaded();
+
+		setBaseEnabled(setFields(false) && (spec.getStatus() == IParseConstants.PARSED));
+	}
 
     /*
      * This method started out as code within execute to set the fields it
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/proof/TLAProofFoldingStructureProvider.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/proof/TLAProofFoldingStructureProvider.java
index 8aac5e74af396be5a6df0185ae0d53ceddb2cf57..594ececf113e3c30fd919250b8fb6781e21e4913 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/proof/TLAProofFoldingStructureProvider.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/proof/TLAProofFoldingStructureProvider.java
@@ -236,9 +236,15 @@ public class TLAProofFoldingStructureProvider implements IParseResultListener, I
      * in the editor if the parse result points to the {@link ModuleNode} representing
      * the file in the editor for this class.
      */
-    public void newParseResult(ParseResult parseResult)
-    {
-
+	public void newParseResult(ParseResult parseResult) {
+		if (editor == null) {
+			Activator.getDefault().logDebug("Null editor in proof structure provider.");
+			return;
+		} else if (editor.getEditorInput() == null) {
+			Activator.getDefault().logDebug("Null editor input in proof structure provider.");
+			return;
+		}
+		
     	if (!(editor.getEditorInput() instanceof IFileEditorInput)) {
 			// input can be the file history which isn't an IFileEditorInput and
 			// thus cannot be parsed. There is no point parsing every revision
@@ -261,17 +267,6 @@ public class TLAProofFoldingStructureProvider implements IParseResultListener, I
 
         String moduleName = ResourceHelper.getModuleName(((IFileEditorInput) editor.getEditorInput()).getFile());
 
-        // TLAEditorActivator.getDefault().logDebug("Proof structure provider for " + moduleName + " recieved a parse result.");
-
-        if (editor == null)
-        {
-            Activator.getDefault().logDebug("Null editor in proof structure provider.");
-            return;
-        } else if (editor.getEditorInput() == null)
-        {
-            Activator.getDefault().logDebug("Null editor input in proof structure provider.");
-            return;
-        }
 
         // check if the editor is dirty or the editor document has been modified
         // or saved before SANY finished
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/proof/TLAProofPosition.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/proof/TLAProofPosition.java
index 2eacce2d1bb43fe4e9845220749447090f86021e..676396cbf0e6a8e11cbc81da40d7def699df3ba2 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/proof/TLAProofPosition.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/proof/TLAProofPosition.java
@@ -257,12 +257,7 @@ public class TLAProofPosition extends Position implements IProjectionPosition
          */
         length = toFold.getOffset() + toFold.getLength() - offset;
 
-        if (toFold != null)
-        {
-            return new IRegion[] { toFold };
-        }
-
-        return null;
+        return new IRegion[] { toFold };
     }
 
     public ProjectionAnnotation getAnnotation()
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/ITLAReserveredWords.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/ITLAReserveredWords.java
index 5b28e58975cd86aac1daf18e310aa08d8bc0f00b..c7a1c5e09f681552ac4d4a3a8649d97ff5c180d8 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/ITLAReserveredWords.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/ITLAReserveredWords.java
@@ -3,6 +3,8 @@ package org.lamport.tla.toolbox.editor.basic.tla;
 import java.util.Arrays;
 import java.util.HashSet;
 
+import util.TLAConstants;
+
 /**
  * TLA+ Reserved words
 
@@ -18,8 +20,8 @@ public interface ITLAReserveredWords
     public final static String BY           = "BY";    
     public final static String CASE 		= "CASE";
     public final static String CHOOSE 		= "CHOOSE";
-    public final static String CONSTANT		= "CONSTANT";
-    public final static String CONSTANTS	= "CONSTANTS";
+    public final static String CONSTANT		= TLAConstants.KeyWords.CONSTANT;
+    public final static String CONSTANTS	= TLAConstants.KeyWords.CONSTANTS;
     public final static String COROLLARY    = "COROLLARY";  // Added 16 July 2012 by LL
     public final static String DEF          = "DEF";
     public final static String DEFINE       = "DEFINE";
@@ -61,8 +63,8 @@ public interface ITLAReserveredWords
     public final static String UNCHANGED 	= "UNCHANGED";
     public final static String UNION 		= "UNION";
     public final static String USE          = "USE";
-    public final static String VARIABLE 	= "VARIABLE";
-    public final static String VARIABLES 	= "VARIABLES";
+    public final static String VARIABLE 	= TLAConstants.KeyWords.VARIABLE;
+    public final static String VARIABLES 	= VARIABLE + "S";
     public final static String WF_ 			= "WF_";
     public final static String WITH 		= "WITH";
     public final static String WITNESS      = "WITNESS";
@@ -194,6 +196,6 @@ public interface ITLAReserveredWords
         FALSE
     };
     
-    public final static HashSet ALL_WORDS_SET = new HashSet(Arrays.asList(ALL_WORDS_ARRAY));
+    public final static HashSet<String> ALL_WORDS_SET = new HashSet<>(Arrays.asList(ALL_WORDS_ARRAY));
     
 }
\ No newline at end of file
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/PCALCodeScanner.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/PCALCodeScanner.java
index 98509d28ed91c5388786b39fa9f61a52d5d8dee0..64b4cdaf60c66cfdb0de9989c16733896c034a1d 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/PCALCodeScanner.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/PCALCodeScanner.java
@@ -32,10 +32,10 @@ public class PCALCodeScanner extends RuleBasedScanner
     {
         TLAColorProvider provider = TLAEditorActivator.getDefault().getTLAColorProvider();
 
-        IToken keyword = new Token(new TextAttribute(provider.getColor(TLAColorProvider.TLA_KEYWORD), null, SWT.BOLD));
-        IToken value = new Token(new TextAttribute(provider.getColor(TLAColorProvider.TLA_VALUE)));
-        IToken other = new Token(new TextAttribute(provider.getColor(TLAColorProvider.TLA_DEFAULT)));
-        IToken pcal = new Token(new TextAttribute(provider.getColor(TLAColorProvider.PCAL_KEYWORD)));
+        IToken keyword = new Token(new TextAttribute(provider.getColor(TLAColorProvider.TLA_KEYWORD_KEY), null, SWT.BOLD));
+        IToken value = new Token(new TextAttribute(provider.getColor(TLAColorProvider.TLA_VALUE_KEY)));
+        IToken other = new Token(new TextAttribute(provider.getColor(TLAColorProvider.DEFAULT_TEXT_KEY)));
+        IToken pcal = new Token(new TextAttribute(provider.getColor(TLAColorProvider.PCAL_KEYWORD_KEY)));
         
         List<WordRule> rules = new ArrayList<WordRule>();
 
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLACodeScanner.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLACodeScanner.java
index d6fb73284adc0c3d518166615eec641f56e624a6..cf37886188e2abe3ffa7819f0e36799439d97166 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLACodeScanner.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLACodeScanner.java
@@ -28,9 +28,9 @@ public class TLACodeScanner extends RuleBasedScanner
     {
         TLAColorProvider provider = TLAEditorActivator.getDefault().getTLAColorProvider();
 
-        IToken keyword = new Token(new TextAttribute(provider.getColor(TLAColorProvider.TLA_KEYWORD), null, SWT.BOLD));
-        IToken value = new Token(new TextAttribute(provider.getColor(TLAColorProvider.TLA_VALUE)));
-        IToken other = new Token(new TextAttribute(provider.getColor(TLAColorProvider.TLA_DEFAULT)));
+        IToken keyword = new Token(new TextAttribute(provider.getColor(TLAColorProvider.TLA_KEYWORD_KEY), null, SWT.BOLD));
+        IToken value = new Token(new TextAttribute(provider.getColor(TLAColorProvider.TLA_VALUE_KEY)));
+        IToken other = new Token(new TextAttribute(provider.getColor(TLAColorProvider.DEFAULT_TEXT_KEY)));
 
         List rules = new ArrayList();
 
diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLACompletionProcessor.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLACompletionProcessor.java
index ff3de00067466baa925588658e35068bd9476283..90866d8811815eaac7049d5a11c53c0c4eccbd2f 100644
--- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLACompletionProcessor.java
+++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLACompletionProcessor.java
@@ -32,7 +32,7 @@ public class TLACompletionProcessor extends ToolboxCompletionProcessor implement
 		l.add(new CompletionProposalTemplate(
 				"(***************************************************************************\r\n"
 						+ "--algorithm AlgorithmName {\r\n}\r\n"
-						+ " ***************************************************************************)\r\n",
+						+ "***************************************************************************)\r\n",
 				IPCalReservedWords.ALGORITHM, IPCalReservedWords.ALGORITHM_HELP));
 		proposals.put(ITLAReserveredWords.ALGORITHM, l);
     }
diff --git a/org.lamport.tla.toolbox.feature.standalone/feature.xml b/org.lamport.tla.toolbox.feature.standalone/feature.xml
index 39cdc9dc04fef723c0b0dc61f5f3f72c349e9a1e..56a805a6e13a216d168b84a9f9c3066c863fbf11 100644
--- a/org.lamport.tla.toolbox.feature.standalone/feature.xml
+++ b/org.lamport.tla.toolbox.feature.standalone/feature.xml
@@ -87,11 +87,7 @@
          version="0.0.0"/>
 
    <includes
-         id="org.eclipse.ecf.filetransfer.httpclient4.feature"
-         version="0.0.0"/>
-
-   <includes
-         id="org.eclipse.ecf.filetransfer.httpclient4.ssl.feature"
+         id="org.eclipse.ecf.filetransfer.httpclient45.feature"
          version="0.0.0"/>
 
    <includes
@@ -328,7 +324,7 @@
          id="org.eclipse.jdt.annotation"
          download-size="0"
          install-size="0"
-         version="1.1.300.v20180905-0314"
+         version="1.1.400.v20180921-1416"
          unpack="false"/>
 
    <plugin
@@ -339,4 +335,24 @@
          fragment="true"
          unpack="false"/>
 
+   <plugin
+         id="org.eclipse.ui.themes"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"/>
+
+   <plugin
+         id="org.eclipse.e4.ui.css.swt.theme"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
+   <plugin
+         id="org.eclipse.e4.ui.css.swt"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
 </feature>
diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/Application.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/Application.java
index c3e3ae70fc01b9c3cf702fe9135abe4ba69b5be0..4bc779a86d74b9fa0ef6d53123eb09d0576ba6c1 100644
--- a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/Application.java
+++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/Application.java
@@ -34,6 +34,7 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.Properties;
 
@@ -119,10 +120,12 @@ public class Application implements IApplication {
         	tlcParams.append(String.valueOf(coverage));
 		}
 		
+		final boolean doJFR = Arrays.asList(args).contains("jfr");
+		
 		final TLCJobFactory factory = new CloudTLCJobFactory();
 		final CloudDistributedTLCJob job = (CloudDistributedTLCJob) factory.getTLCJob(cloud, new File(modelDirectory), 1, props, tlcParams.toString());
 		job.setIsCLI(true);
-//		job.setDoJfr(true); //Todo Reactivate once CloudTLC copies the JFR dump file to the local machine.
+		job.setDoJfr(doJFR);
 		final IStatus status = job.run(new MyProgressMonitor(9));
 		// Show error message if any such as invalid credentials.
 		if (status.getSeverity() == IStatus.ERROR || !(status instanceof ITLCJobStatus)) {
@@ -152,6 +155,10 @@ public class Application implements IApplication {
 			return new Integer(1);
 		}
 		
+		if (doJFR) {
+			((ITLCJobStatus) status).getJavaFlightRecording();
+		}
+
 		return IApplication.EXIT_OK;
 	}
 
diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureARMCloudTLCInstanceParameters.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureARMCloudTLCInstanceParameters.java
index f460bdc095d6fc6f33b5f74704c6926d477139df..4a9eed46f7c1fea11a8fa49fa52b0e4831166e8c 100644
--- a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureARMCloudTLCInstanceParameters.java
+++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureARMCloudTLCInstanceParameters.java
@@ -67,7 +67,8 @@ public class AzureARMCloudTLCInstanceParameters extends AzureCloudTLCInstancePar
 	@Override
 	public String getImageId() {
 		// With azure-cli v2 (based on Python) extract name from 'az vm image list --all --publisher Canonical'.
-		return System.getProperty("azure.image", "eastus/Canonical/UbuntuServer/18.04-LTS");	}
+		return System.getProperty("azure.image", "eastus/Canonical/UbuntuServer/18.04-LTS");
+	}
 
 	/* (non-Javadoc)
 	 * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getHardwareId()
@@ -75,7 +76,10 @@ public class AzureARMCloudTLCInstanceParameters extends AzureCloudTLCInstancePar
 	@Override
 	public String getHardwareId() {
 		// STANDARD_D14: 16 cores, 112GB
-		return System.getProperty("azure.instanceType", "eastus/Standard_D14");
+		// Find more with: 'az vm list-sizes -l eastus'
+		return System.getProperty("azure.instanceType", getRegion() + "/Standard_D14");
+//		return System.getProperty("azure.instanceType", getRegion() + "/Standard_L8s_v2");
+//		return System.getProperty("azure.instanceType", getRegion() + "/Standard_L80s_v2");
 	}
 
 	/* (non-Javadoc)
@@ -225,8 +229,10 @@ public class AzureARMCloudTLCInstanceParameters extends AzureCloudTLCInstancePar
 				+ "Type=oneshot\\n"
 				+ "RemainAfterExit=true\\n"
 				+ "ExecStart=/bin/true\\n"
-				// Great, this is much simpler compared to 589e6fc82ce182b0c49c4c1fb63bc0aae711cf5f
-				+ "ExecStop=/usr/bin/az group delete --name %s -y\\n"
+				// Great, this is much simpler compared to 589e6fc82ce182b0c49c4c1fb63bc0aae711cf5f.
+				// Do not delete the instance if /tmp/NoAZ... marker exist. Create this file to
+				// skip deletion once e.g. when creating an image.
+				+ "ExecStop=/usr/bin/test -e /tmp/NoAZDelete.txt || /usr/bin/az group delete --name %s -y\\n"
 				+ "[Install]\\n"
 				+ "WantedBy=multi-user.target\\n\" | sudo tee /lib/systemd/system/delete-on-shutdown.service"
 				+ " && systemctl enable delete-on-shutdown" // restart delete-on-shutdown service after a reboot.
diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudDistributedTLCJob.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudDistributedTLCJob.java
index 110755aa6072964b59482b950d43b963e4238362..d84689919670f3e7a1d665229aa73a268ac843bc 100644
--- a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudDistributedTLCJob.java
+++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudDistributedTLCJob.java
@@ -32,10 +32,12 @@ import static org.jclouds.compute.predicates.NodePredicates.inGroup;
 import static org.jclouds.scriptbuilder.domain.Statements.exec;
 
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Map;
@@ -82,9 +84,12 @@ import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
+import com.google.common.io.ByteStreams;
 import com.google.common.io.Files;
 import com.google.inject.AbstractModule;
 
+import util.TLAConstants;
+
 /*
  * TODO
  * ====
@@ -110,6 +115,7 @@ public class CloudDistributedTLCJob extends Job {
 	private final Properties props;
 	private final CloudTLCInstanceParameters params;
 	private boolean isCLI = false;
+	// Azul VM comes with JFR support. This can thus be safely activated.
 	private boolean doJfr = false;
 
 	public CloudDistributedTLCJob(String aName, File aModelFolder,
@@ -179,6 +185,10 @@ public class CloudDistributedTLCJob extends Job {
 
 			// Create compute environment in the cloud and inject an ssh
 			// implementation. ssh is our means of communicating with the node.
+			// In order to debug jclouds on the command-line or from the Toolbox:
+			// a) Make sure command-line also uses SLF4JLogginModule by hacking the build.
+			// b) Append -Dorg.slf4j.simpleLogger.defaultLogLevel=debug to toolbox/toolbox.ini
+			// c) Delete toolbox/plugins/slf4j.nop_1.7.25.jar to make sure slf4j.simple gets loaded.
 			final Iterable<AbstractModule> modules = ImmutableSet.<AbstractModule>of(new SshjSshClientModule(),
 					isCLI ? new ConsoleLoggingModule() : new SLF4JLoggingModule());
 
@@ -243,7 +253,13 @@ public class CloudDistributedTLCJob extends Job {
 				return Status.CANCEL_STATUS;
 			}
 
-			final String tlcMasterCommand = " sudo shutdown -c && rm -rf /mnt/tlc/* && " // Cancel and remove any pending shutdown and leftovers from previous runs.
+			final String tlcMasterCommand = " sudo shutdown -c && " // Cancel a pending shutdown.
+					// In case the provision step didn't run (e.g. because we run a custom VM image), /mnt/tlc does not
+					// exist because it is on ephemeral storage. For the subsequent commands to work, create it and make
+					// it writeable.
+					+ "sudo mkdir -p /mnt/tlc && sudo chmod 777 /mnt/tlc/ && "
+					// Remove any leftovers from previous runs.
+					+ "rm -rf /mnt/tlc/* && "
 					+ "cd /mnt/tlc/ && "
 					// Decompress tla2tools.pack.gz
 					+ "unpack200 /tmp/tla2tools.pack.gz /tmp/tla2tools.jar"
@@ -279,9 +295,18 @@ public class CloudDistributedTLCJob extends Job {
 						+ "-Dcom.sun.management.jmxremote.authenticate=false "
 						// TLC tuning options
 						+ params.getJavaSystemProperties() + " "
-						+ "-jar /tmp/tla2tools.jar " 
+						+ "-jar /tmp/tla2tools.jar "
+						// Explicitly tell TLC to create states/ on ephemeral storage. This is redundant
+						// because we cd into /mnt/tlc above, but when the command is manually executed,
+						// this might not be the case (related to java.io.tmpdir).
+						+ "-metadir /mnt/tlc/ "
 						+ params.getTLCParameters()
-						+ " && "
+						// Unless TLC's exit value is 1 or 255 (see EC.java),
+						// run the shutdown sequence. In other words, ignore
+						// all non-zero exit values because the represent 
+						// regular termination in which case we can safely
+						// terminate the cloud instance.
+						+ " ; [[ $? -ne 255 && $? -ne 1 ]] && "
 					// Let the machine power down immediately after
 					// finishing model checking to cut costs. However,
 					// do not shut down (hence "&&") when TLC finished
@@ -393,18 +418,19 @@ public class CloudDistributedTLCJob extends Job {
 			// not necessarily require an email to be sent).
 			final ExecChannel execChannel = sshClient.execChannel(
 					// Wait for the java process to start before tail'ing its MC.out file below.
-					// This obviously open the door to blocking indefinitely if the java/TLC process
+					// This obviously opens the door to blocking indefinitely if the java/TLC process
 					// terminates before until starts.
 					"until pids=$(pgrep -f \"^java .* -jar /tmp/tla2tools.jar\"); do sleep 1; done"
 					+ " && "
 					// Guarantee the MC.out file exists in case the java process has not written to
 					// it yet. Otherwise tail might terminate immediately. touch is idempotent and
 					// thus does not fail when MC.out already exists.
-					+ "touch /mnt/tlc/MC.out"
+					+ "touch /mnt/tlc/" + TLAConstants.Files.MODEL_CHECK_OUTPUT_FILE
 					+ " && "
 					// Read the MC.out file and remain attached for as long as there is a TLC/java
 					// process.
-					+ "tail -q -f -n +1 /mnt/tlc/MC.out --pid $(pgrep -f \"^java .* -jar /tmp/tla2tools.jar\")");
+					+ "tail -q -f -n +1 /mnt/tlc/" + TLAConstants.Files.MODEL_CHECK_OUTPUT_FILE
+					+ " --pid $(pgrep -f \"^java .* -jar /tmp/tla2tools.jar\")");
 			
 			// Communicate result to user
 			monitor.done();
@@ -524,6 +550,13 @@ public class CloudDistributedTLCJob extends Job {
 			if (isCLI) {
 				templateOptions.tags(Arrays.asList("CLI"));
 			}
+			
+			// Overriding login password to be able to login to the cloud instance if
+			// jclouds bootstrapping fails. This is the instances initial root password set
+			// by the cloud provider that jclouds makes the first connection with to
+			// subsequently set up ssh keys... If the setup of ssh keys fails for whatever
+			// reason, this password is the only way to login into the instance.
+			//templateOptions.overrideLoginPassword("8nwc3+r897NR98as37cr589234598");
 			params.mungeTemplateOptions(templateOptions);
 			
             final TemplateBuilder templateBuilder = compute.templateBuilder();
@@ -542,6 +575,11 @@ public class CloudDistributedTLCJob extends Job {
 				return createNodesInGroup;
 			}
 
+			if (!params.isVanillaVMImage()) {
+				// A non-vanilla image is needs no provisioning.
+				return createNodesInGroup;
+			}
+			
 			// Install custom tailored jmx2munin to monitor the TLC process. Can
 			// either monitor standalone tlc2.TLC or TLCServer.
 			monitor.subTask("Provisioning TLC environment on all node(s)");
@@ -636,9 +674,12 @@ public class CloudDistributedTLCJob extends Job {
 							// instance.
 							+ " && "
 							+ "mkdir -p /mnt/tlc/ && chmod 777 /mnt/tlc/ && "
-							+ "ln -s /mnt/tlc/MC.out /var/www/html/MC.out && "
-							+ "ln -s /mnt/tlc/MC.out /var/www/html/MC.txt && " // Microsoft IE and Edge fail to show line breaks correctly unless ".txt" extension.
-							+ "ln -s /mnt/tlc/MC.err /var/www/html/MC.err && "
+							+ "ln -s /mnt/tlc/" + TLAConstants.Files.MODEL_CHECK_OUTPUT_FILE
+									+ " /var/www/html/" + TLAConstants.Files.MODEL_CHECK_OUTPUT_FILE + " && "
+							+ "ln -s /mnt/tlc/" + TLAConstants.Files.MODEL_CHECK_OUTPUT_FILE
+									+ " /var/www/html/MC.txt && " // Microsoft IE and Edge fail to show line breaks correctly unless ".txt" extension.
+							+ "ln -s /mnt/tlc/" + TLAConstants.Files.MODEL_CHECK_ERROR_FILE
+									+ " /var/www/html/" + TLAConstants.Files.MODEL_CHECK_ERROR_FILE + " && "
 							+ "ln -s /mnt/tlc/tlc.jfr /var/www/html/tlc.jfr"),
 					new TemplateOptions().runAsRoot(true).wrapInInitScript(
 							false));			
@@ -742,6 +783,23 @@ public class CloudDistributedTLCJob extends Job {
 			return this.output;
 		}
 		
+		@Override
+		public void getJavaFlightRecording() throws IOException {
+			// Get Java Flight Recording from remote machine and save if to a local file in
+			// the current working directory. We call "cat" because sftclient#get fails with
+			// the old net.schmizz.sshj and an update to the newer com.hierynomus seems 
+			// awful lot of work.
+			final ExecChannel channel = sshClient.execChannel("cat /mnt/tlc/tlc.jfr");
+			final InputStream output = channel.getOutput();
+			final String cwd = Paths.get(".").toAbsolutePath().normalize().toString() + File.separator;
+			final File jfr = new File(cwd + "tlc-" + System.currentTimeMillis() + ".jfr");
+			ByteStreams.copy(output, new FileOutputStream(jfr));
+			if (jfr.length() == 0) {
+				System.err.println("Received empty Java Flight recording. Not creating tlc.jfr file");
+				jfr.delete();
+			}
+		}
+		
 		public void killTLC() {
 			// For some reason shutdown has to be called before kill (shrugs).
 			sshClient.execChannel(
diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudTLCInstanceParameters.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudTLCInstanceParameters.java
index 2e87b7b594c2b4aad088f37bd425b0864cead43d..83271d0ef37167a94cddfb3e886c4fe883afcc36 100644
--- a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudTLCInstanceParameters.java
+++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudTLCInstanceParameters.java
@@ -173,4 +173,11 @@ public abstract class CloudTLCInstanceParameters {
 	public void mungeTemplateBuilder(final TemplateBuilder templateBuilder) {
 		// no-op, subclass may override
 	}
+
+	// A vanilla image will be provisioned by cloud tlc. In other words, CloudTLC
+	// will install a JavaVM and other dependencies. A non-vanilla image is expected
+	// to come with all dependencies.
+	protected boolean isVanillaVMImage() {
+		return true;
+	}
 }
diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudTLCJobFactory.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudTLCJobFactory.java
index b75633f8f46c3438aac09124147762083dc4f2b2..6040c58e67645c8c552c00b87db94d14c9da3a4d 100644
--- a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudTLCJobFactory.java
+++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudTLCJobFactory.java
@@ -49,6 +49,9 @@ public class CloudTLCJobFactory implements TLCJobFactory {
 		} else if (AZURECOMPUTE.equalsIgnoreCase(aName)) {
 			return new CloudDistributedTLCJob(aName, aModelFolder, numberOfWorkers, props,
 					new AzureARMCloudTLCInstanceParameters(tlcparams, numberOfWorkers));
+		} else if ("AzureTLA".equalsIgnoreCase(aName)) {
+			return new CloudDistributedTLCJob(aName, aModelFolder, numberOfWorkers, props,
+					new TLAAzureARMCloudTLCInstanceParameters(tlcparams, numberOfWorkers));
 		} else if (PACKET_NET.equalsIgnoreCase(aName)) {
 			return new CloudDistributedTLCJob(aName, aModelFolder, numberOfWorkers, props,
 					new PacketNetCloudTLCInstanceParameters(tlcparams, numberOfWorkers));
diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/TLAAzureARMCloudTLCInstanceParameters.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/TLAAzureARMCloudTLCInstanceParameters.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd304afdbbb465113305c2f7c57fdc013e8b8887
--- /dev/null
+++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/TLAAzureARMCloudTLCInstanceParameters.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+
+package org.lamport.tla.toolbox.jcloud;
+
+import java.util.Properties;
+
+import org.jclouds.location.reference.LocationConstants;
+
+public class TLAAzureARMCloudTLCInstanceParameters extends AzureARMCloudTLCInstanceParameters {
+
+	public TLAAzureARMCloudTLCInstanceParameters(final String tlcParams, int numberOfWorkers) {
+        super(tlcParams.trim(), numberOfWorkers);
+	}
+
+	/* (non-Javadoc)
+	 * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getImageId()
+	 */
+	@Override
+	public String getImageId() {
+		// With azure-cli v2 (based on Python) extract name from 'az vm image list --all --publisher Canonical'.
+		return System.getProperty("azure.image", "tlaplus/" + getRegion() + "/tlaplus-tlc-2019.12.23");
+	}
+
+	/* (non-Javadoc)
+	 * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#mungeProperties(java.util.Properties)
+	 */
+	@Override
+	public void mungeProperties(final Properties properties) {
+		super.mungeProperties(properties);
+		// Receiving publisher images can take a long time if the publisher has many
+		// images. We know which image we want to use (ours!!!), which is why we don't
+		// want to wait. A bogus name won't have images.
+        properties.setProperty("jclouds.azurecompute.arm.publishers", "APublisherThatDoesNotExist");
+        properties.setProperty(LocationConstants.PROPERTY_REGIONS, getRegion());
+	}
+
+	@Override
+	protected boolean isVanillaVMImage() {
+		return false;
+	}
+	
+	/*
+	 * How to create a TLA+ VM image?
+	 * 1. Start a regular Axure image with Cloud TLC.
+	 * 2. Disable/Remove Cloud Shutdown hook
+	 *    (see AzureARMCloudTLCInstanceParam#getCloudAPIShutdown NoAZDelete.txt)!!!
+	 * 3. Deprovision the VM: sudo waagent -deprovision+user
+	 *    https://docs.microsoft.com/en-us/azure/virtual-machines/linux/capture-image
+	 * 3. Stop the Azure VM through the portal or az command-line app.
+	 * 4. Trigger image creation through Azure portal and wait for Azure to do its thing.
+	 * 5. Delete remnant of the actual Azure instance.
+	 * 6. Subst azure.image above with name given in 4.
+	 */
+}
diff --git a/org.lamport.tla.toolbox.jnlp/files/animator.html b/org.lamport.tla.toolbox.jnlp/files/animator.html
new file mode 100644
index 0000000000000000000000000000000000000000..1fa11211fff036183a236f22e085050465647962
--- /dev/null
+++ b/org.lamport.tla.toolbox.jnlp/files/animator.html
@@ -0,0 +1,156 @@
+<!DOCTYPE html>
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+	<title>TLA+ Trace Animator</title>
+	<script src="jquery.js"></script>
+	<!-- <script src="js/jquery.min.js"></script> -->
+</head>
+<body _adv_already_used="true">
+
+<style type="text/css">
+	body{
+		font-family: sans-serif;
+	}
+	div{
+		padding: 10px;
+	}
+</style>
+
+<div id="container" style="text-align:center;">
+
+	<h2>TLA+ Trace Animator</h2>
+
+	<!-- Text area for pasting SVG frames. -->
+	<div style="text-align: center;margin:auto;">
+		<textarea id="textdrop" cols="60" rows="20" placeholder="Paste SVG Frames Here" style="font-size:16px;"></textarea>
+	</div>
+		
+	<!-- <svg id="svgBox" width="40%" viewBox="0 0 100 90" style="border:solid;float:right"> -->
+	<div style="margin:auto">
+		<svg id="svgBox" width="50%" height="500px" viewBox="0 0 300 300" style="border:solid; border-width: 1px; border-color:lightgray; visibility: hidden">
+		</svg>
+	</div>
+
+	<!-- Control Buttons and Frame Info -->
+	<!-- FrameNum above buttons to easily exclude buttons in screencast --> 
+	<div id="frameNum">Frame Number: 0</div>
+	<button id="prevBtn">Prev Frame</button>
+	<button id="nextBtn">Next Frame</button>
+
+</div>
+
+
+<script type="text/javascript">
+	let frameClass = "tlaframe";
+	let frameElems = $([]); // stores all SVG frame elements.
+	let currFrame = 0;
+	let maxFrame = frameElems.length;
+
+	function init(){
+		// children = ;
+		// console.log(children);
+		// We expect that first level <g> child that lives inside the SVG box is its own frame. This is a simple convention 
+		// that makes the contract between the TLA+ toolbox and this web animator tool simpler. The only thing 
+		// the toolbox needs to export is a sequence of <g> elements, where each one is an animation frame.
+		frameElems = $("#svgBox > g"); // gets all first-level children.		
+		currFrame = 0;
+		maxFrame = frameElems.length;
+		console.log("Initialized animation. Current frame: " + currFrame + ", Total Frames: " + maxFrame);
+	}
+
+	$("#textdrop").on('input', function(ev) {
+	    var text = $("#textdrop").val();
+
+		// The pasted text should be a TLA+ sequence (tuple) of records, where each record has
+		// one key-value pair, whose value is the SVG element for that frame. We expect
+		// that the record has been filtered to only include the view expression, so we 
+		// pull out all lines that contain a record delimiter. We might want to eventually
+		// make this a regex that properly matches and extracts key-value pairs from a TLA+
+		// record, but for now this will do the job.
+		// text should look something like:
+		// <<
+		// [SlotNumber |-> "<text x='25' font='Arial' y='25'>Text A</text>"],
+		// [SlotNumber |-> "<text x='50' font='Arial' y='50'>Text B</text>"],
+		// [SlotNumber |-> "<text x='75' font='Arial' y='75'>Text C</text>"]
+		// >>
+		//
+		tlaRecordDelim = "|->";
+		frameLines = text.split("\n").filter(line => line.includes(tlaRecordDelim));
+		frames = frameLines.map(line => line.split("|->").pop());
+		framesText = frames.join("");
+
+		$("#svgBox").html(framesText);
+
+		// Hide the text area input and show the SVG viewer.
+		$(this).hide();
+		init();
+		reload();
+		$("#svgBox").css("visibility", "visible");
+
+	});
+
+	function reload(){
+		frameElems.each(function(index){
+			let gid = $(this).attr("id");
+			if(index == currFrame){
+				$(this).attr("visibility", "visible");
+			} else{
+				$(this).attr("visibility", "hidden");
+			}
+		});
+		$("#frameNum").html("Frame Number: "+ currFrame + "/" + Math.max(0, maxFrame - 1));
+		console.log("Current frame: " + currFrame);
+	}
+
+	// Set the current frame to the given index. If an out of bound frame index is given, we take the
+	// index modulo the maximum frame index.
+	function setFrame(frameInd){
+		currFrame = frameInd % maxFrame;
+		reload();
+	}
+
+
+	function advanceFrame(){
+		currFrame = (currFrame + 1) % maxFrame;
+		reload();
+	}
+
+	function prevFrame(){
+		if(currFrame - 1 < 0){
+			currFrame = maxFrame - 1;
+		} else{
+			currFrame = currFrame - 1;
+		}
+		reload();
+	}
+
+	$(document).keydown(function(e) {
+    switch(e.which) {
+        case 37: // left
+        	prevFrame();
+        	break;
+
+        case 39: // right
+        	advanceFrame();
+        	break;
+
+        default: return; // exit this handler for other keys
+    }
+	    e.preventDefault(); // prevent the default action (scroll / move caret)
+	});
+
+	$("#nextBtn").click(advanceFrame);
+	$("#prevBtn").click(prevFrame);
+
+	reload();
+
+</script>
+
+
+
+
+
+
+
+
+</body></html>
\ No newline at end of file
diff --git a/org.lamport.tla.toolbox.jnlp/files/jquery.js b/org.lamport.tla.toolbox.jnlp/files/jquery.js
new file mode 100644
index 0000000000000000000000000000000000000000..4d9b3a258759c53e7bc66b6fc554c51e2434437c
--- /dev/null
+++ b/org.lamport.tla.toolbox.jnlp/files/jquery.js
@@ -0,0 +1,2 @@
+/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */
+!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){"use strict";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return"function"==typeof t&&"number"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement("script");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[c.call(e)]||"object":typeof e}var b="3.3.1",w=function(e,t){return new w.fn.init(e,t)},T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;w.fn=w.prototype={jquery:"3.3.1",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:s,sort:n.sort,splice:n.splice},w.extend=w.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||g(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)n=a[t],a!==(r=e[t])&&(l&&r&&(w.isPlainObject(r)||(i=Array.isArray(r)))?(i?(i=!1,o=n&&Array.isArray(n)?n:[]):o=n&&w.isPlainObject(n)?n:{},a[t]=w.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},w.extend({expando:"jQuery"+("3.3.1"+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==c.call(e))&&(!(t=i(e))||"function"==typeof(n=f.call(t,"constructor")&&t.constructor)&&p.call(n)===d)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e){m(e)},each:function(e,t){var n,r=0;if(C(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(C(Object(e))?w.merge(n,"string"==typeof e?[e]:e):s.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:u.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r,i=[],o=0,a=e.length,s=!n;o<a;o++)(r=!t(e[o],o))!==s&&i.push(e[o]);return i},map:function(e,t,n){var r,i,o=0,s=[];if(C(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&s.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&s.push(i);return a.apply([],s)},guid:1,support:h}),"function"==typeof Symbol&&(w.fn[Symbol.iterator]=n[Symbol.iterator]),w.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function C(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!g(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},P="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",I="\\["+M+"*("+R+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+R+"))|)"+M+"*\\]",W=":("+R+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+I+")*)|.*)\\)|)",$=new RegExp(M+"+","g"),B=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),F=new RegExp("^"+M+"*,"+M+"*"),_=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="<a id='"+b+"'></a><select id='"+b+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:he(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:he(function(e,t,n){for(var r=n<0?n+t:n;--r>=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=r.pseudos.eq;for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})r.pseudos[t]=fe(t);for(t in{submit:!0,reset:!0})r.pseudos[t]=pe(t);function ye(){}ye.prototype=r.filters=r.pseudos,r.setFilters=new ye,a=oe.tokenize=function(e,t){var n,i,o,a,s,u,l,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,u=[],l=r.preFilter;while(s){n&&!(i=F.exec(s))||(i&&(s=s.slice(i[0].length)||s),u.push(o=[])),n=!1,(i=_.exec(s))&&(n=i.shift(),o.push({value:n,type:i[0].replace(B," ")}),s=s.slice(n.length));for(a in r.filter)!(i=V[a].exec(s))||l[a]&&!(i=l[a](i))||(n=i.shift(),o.push({value:n,type:a,matches:i}),s=s.slice(n.length));if(!n)break}return t?s.length:s?oe.error(e):k(e,u).slice(0)};function ve(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function me(e,t,n){var r=t.dir,i=t.next,o=i||r,a=n&&"parentNode"===o,s=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||a)return e(t,n,i);return!1}:function(t,n,u){var l,c,f,p=[T,s];if(u){while(t=t[r])if((1===t.nodeType||a)&&e(t,n,u))return!0}else while(t=t[r])if(1===t.nodeType||a)if(f=t[b]||(t[b]={}),c=f[t.uniqueID]||(f[t.uniqueID]={}),i&&i===t.nodeName.toLowerCase())t=t[r]||t;else{if((l=c[o])&&l[0]===T&&l[1]===s)return p[2]=l[2];if(c[o]=p,p[2]=e(t,n,u))return!0}return!1}}function xe(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r<i;r++)oe(e,t[r],n);return n}function we(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Te(e,t,n,r,i,o){return r&&!r[b]&&(r=Te(r)),i&&!i[b]&&(i=Te(i,o)),se(function(o,a,s,u){var l,c,f,p=[],d=[],h=a.length,g=o||be(t||"*",s.nodeType?[s]:s,[]),y=!e||!o&&t?g:we(g,p,e,s,u),v=n?i||(o?e:h||r)?[]:a:y;if(n&&n(y,v,s,u),r){l=we(v,d),r(l,[],s,u),c=l.length;while(c--)(f=l[c])&&(v[d[c]]=!(y[d[c]]=f))}if(o){if(i||e){if(i){l=[],c=v.length;while(c--)(f=v[c])&&l.push(y[c]=f);i(null,v=[],l,u)}c=v.length;while(c--)(f=v[c])&&(l=i?O(o,f):p[c])>-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u<o;u++)if(n=r.relative[e[u].type])p=[me(xe(p),n)];else{if((n=r.filter[e[u].type].apply(null,e[u].matches))[b]){for(i=++u;i<o;i++)if(r.relative[e[i].type])break;return Te(u>1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u<i&&Ce(e.slice(u,i)),i<o&&Ce(e=e.slice(i)),i<o&&ve(e))}p.push(n)}return xe(p)}function Ee(e,t){var n=t.length>0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t<r;t++)if(w.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)w.find(e,i[t],n);return r>1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(w.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&w(e);if(!D.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?a.index(n)>-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s<o.length)!1===o[s].apply(n[0],n[1])&&e.stopOnFalse&&(s=o.length,n=!1)}e.memory||(n=!1),t=!1,i&&(o=n?[]:"")},l={add:function(){return o&&(n&&!t&&(s=o.length-1,a.push(n)),function t(n){w.each(n,function(n,r){g(r)?e.unique&&l.has(r)||o.push(r):r&&r.length&&"string"!==x(r)&&t(r)})}(arguments),n&&!t&&u()),this},remove:function(){return w.each(arguments,function(e,t){var n;while((n=w.inArray(t,o,n))>-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t<o)){if((e=r.apply(s,u))===n.promise())throw new TypeError("Thenable self-resolution");l=e&&("object"==typeof e||"function"==typeof e)&&e.then,g(l)?i?l.call(e,a(o,n,I,i),a(o,n,W,i)):(o++,l.call(e,a(o,n,I,i),a(o,n,W,i),a(o,n,I,n.notifyWith))):(r!==I&&(s=void 0,u=[e]),(i||n.resolveWith)(s,u))}},c=i?l:function(){try{l()}catch(e){w.Deferred.exceptionHook&&w.Deferred.exceptionHook(e,c.stackTrace),t+1>=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},X=/^-ms-/,U=/-([a-z])/g;function V(e,t){return t.toUpperCase()}function G(e){return e.replace(X,"ms-").replace(U,V)}var Y=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function Q(){this.expando=w.expando+Q.uid++}Q.uid=1,Q.prototype={cache:function(e){var t=e[this.expando];return t||(t={},Y(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[G(t)]=n;else for(r in t)i[G(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][G(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(G):(t=G(t))in r?[t]:t.match(M)||[]).length;while(n--)delete r[t[n]]}(void 0===t||w.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!w.isEmptyObject(t)}};var J=new Q,K=new Q,Z=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,ee=/[A-Z]/g;function te(e){return"true"===e||"false"!==e&&("null"===e?null:e===+e+""?+e:Z.test(e)?JSON.parse(e):e)}function ne(e,t,n){var r;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(ee,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n=te(n)}catch(e){}K.set(e,t,n)}else n=void 0;return n}w.extend({hasData:function(e){return K.hasData(e)||J.hasData(e)},data:function(e,t,n){return K.access(e,t,n)},removeData:function(e,t){K.remove(e,t)},_data:function(e,t,n){return J.access(e,t,n)},_removeData:function(e,t){J.remove(e,t)}}),w.fn.extend({data:function(e,t){var n,r,i,o=this[0],a=o&&o.attributes;if(void 0===e){if(this.length&&(i=K.get(o),1===o.nodeType&&!J.get(o,"hasDataAttrs"))){n=a.length;while(n--)a[n]&&0===(r=a[n].name).indexOf("data-")&&(r=G(r.slice(5)),ne(o,r,i[r]));J.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof e?this.each(function(){K.set(this,e)}):z(this,function(t){var n;if(o&&void 0===t){if(void 0!==(n=K.get(o,e)))return n;if(void 0!==(n=ne(o,e)))return n}else this.each(function(){K.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length<n?w.queue(this[0],e):void 0===t?this:this.each(function(){var n=w.queue(this,e,t);w._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&w.dequeue(this,e)})},dequeue:function(e){return this.each(function(){w.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=w.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=J.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var re=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,ie=new RegExp("^(?:([+-])=|)("+re+")([a-z%]*)$","i"),oe=["Top","Right","Bottom","Left"],ae=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&w.contains(e.ownerDocument,e)&&"none"===w.css(e,"display")},se=function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i};function ue(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return w.css(e,t,"")},u=s(),l=n&&n[3]||(w.cssNumber[t]?"":"px"),c=(w.cssNumber[t]||"px"!==l&&+u)&&ie.exec(w.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)w.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,w.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var le={};function ce(e){var t,n=e.ownerDocument,r=e.nodeName,i=le[r];return i||(t=n.body.appendChild(n.createElement(r)),i=w.css(t,"display"),t.parentNode.removeChild(t),"none"===i&&(i="block"),le[r]=i,i)}function fe(e,t){for(var n,r,i=[],o=0,a=e.length;o<a;o++)(r=e[o]).style&&(n=r.style.display,t?("none"===n&&(i[o]=J.get(r,"display")||null,i[o]||(r.style.display="")),""===r.style.display&&ae(r)&&(i[o]=ce(r))):"none"!==n&&(i[o]="none",J.set(r,"display",n)));for(o=0;o<a;o++)null!=i[o]&&(e[o].style.display=i[o]);return e}w.fn.extend({show:function(){return fe(this,!0)},hide:function(){return fe(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?w(this).show():w(this).hide()})}});var pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n<r;n++)J.set(e[n],"globalEval",!t||J.get(t[n],"globalEval"))}var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===x(o))w.merge(p,o.nodeType?[o]:o);else if(me.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+w.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;w.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&w.inArray(o,r)>-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="<textarea>x</textarea>",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n<arguments.length;n++)u[n]=arguments[n];if(t.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,t)){s=w.event.handlers.call(this,t,l),n=0;while((o=s[n++])&&!t.isPropagationStopped()){t.currentTarget=o.elem,r=0;while((a=o.handlers[r++])&&!t.isImmediatePropagationStopped())t.rnamespace&&!t.rnamespace.test(a.namespace)||(t.handleObj=a,t.data=a.data,void 0!==(i=((w.event.special[a.origType]||{}).handle||a.handler).apply(o.elem,u))&&!1===(t.result=i)&&(t.preventDefault(),t.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,t),t.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&e.button>=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?w(i,this).index(l)>-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(e,t){Object.defineProperty(w.Event.prototype,e,{enumerable:!0,configurable:!0,get:g(t)?function(){if(this.originalEvent)return t(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[e]},set:function(t){Object.defineProperty(this,e,{enumerable:!0,configurable:!0,writable:!0,value:t})}})},fix:function(e){return e[w.expando]?e:new w.Event(e)},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==Se()&&this.focus)return this.focus(),!1},delegateType:"focusin"},blur:{trigger:function(){if(this===Se()&&this.blur)return this.blur(),!1},delegateType:"focusout"},click:{trigger:function(){if("checkbox"===this.type&&this.click&&N(this,"input"))return this.click(),!1},_default:function(e){return N(e.target,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},w.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},w.Event=function(e,t){if(!(this instanceof w.Event))return new w.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?Ee:ke,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&w.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[w.expando]=!0},w.Event.prototype={constructor:w.Event,isDefaultPrevented:ke,isPropagationStopped:ke,isImmediatePropagationStopped:ke,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=Ee,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=Ee,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=Ee,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},w.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&we.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&Te.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},w.event.addProp),w.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,t){w.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return i&&(i===r||w.contains(r,i))||(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),w.fn.extend({on:function(e,t,n,r){return De(this,e,t,n,r)},one:function(e,t,n,r){return De(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,w(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=ke),this.each(function(){w.event.remove(this,e,n,t)})}});var Ne=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/<script|<style|<link/i,je=/checked\s*(?:[^=]|=\s*.checked.)/i,qe=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n<r;n++)w.event.add(t,i,l[i][n])}K.hasData(e)&&(s=K.access(e),u=w.extend({},s),K.set(t,u))}}function Me(e,t){var n=t.nodeName.toLowerCase();"input"===n&&pe.test(e.type)?t.checked=e.checked:"input"!==n&&"textarea"!==n||(t.defaultValue=e.defaultValue)}function Re(e,t,n,r){t=a.apply([],t);var i,o,s,u,l,c,f=0,p=e.length,d=p-1,y=t[0],v=g(y);if(v||p>1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f<p;f++)l=i,f!==d&&(l=w.clone(l,!0,!0),u&&w.merge(s,ye(l,"script"))),n.call(e[f],l,f);if(u)for(c=s[s.length-1].ownerDocument,w.map(s,Oe),f=0;f<u;f++)l=s[f],he.test(l.type||"")&&!J.access(l,"globalEval")&&w.contains(c,l)&&(l.src&&"module"!==(l.type||"").toLowerCase()?w._evalUrl&&w._evalUrl(l.src):m(l.textContent.replace(qe,""),c,l))}return e}function Ie(e,t,n){for(var r,i=t?w.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||w.cleanData(ye(r)),r.parentNode&&(n&&w.contains(r.ownerDocument,r)&&ve(ye(r,"script")),r.parentNode.removeChild(r));return e}w.extend({htmlPrefilter:function(e){return e.replace(Ne,"<$1></$2>")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r<i;r++)Me(o[r],a[r]);if(t)if(n)for(o=o||ye(e),a=a||ye(s),r=0,i=o.length;r<i;r++)Pe(o[r],a[r]);else Pe(e,s);return(a=ye(s,"script")).length>0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(w.cleanData(ye(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=[];return Re(this,arguments,function(t){var n=this.parentNode;w.inArray(this,e)<0&&(w.cleanData(ye(this)),n&&n.replaceChild(t,this))},e)}}),w.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){w.fn[e]=function(e){for(var n,r=[],i=w(e),o=i.length-1,a=0;a<=o;a++)n=a===o?this:this.clone(!0),w(i[a])[t](n),s.apply(r,n.get());return this.pushStack(r)}});var We=new RegExp("^("+re+")(?!px)[a-z%]+$","i"),$e=function(t){var n=t.ownerDocument.defaultView;return n&&n.opener||(n=e),n.getComputedStyle(t)},Be=new RegExp(oe.join("|"),"i");!function(){function t(){if(c){l.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",c.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",be.appendChild(l).appendChild(c);var t=e.getComputedStyle(c);i="1%"!==t.top,u=12===n(t.marginLeft),c.style.right="60%",s=36===n(t.right),o=36===n(t.width),c.style.position="absolute",a=36===c.offsetWidth||"absolute",be.removeChild(l),c=null}}function n(e){return Math.round(parseFloat(e))}var i,o,a,s,u,l=r.createElement("div"),c=r.createElement("div");c.style&&(c.style.backgroundClip="content-box",c.cloneNode(!0).style.backgroundClip="",h.clearCloneStyle="content-box"===c.style.backgroundClip,w.extend(h,{boxSizingReliable:function(){return t(),o},pixelBoxStyles:function(){return t(),s},pixelPosition:function(){return t(),i},reliableMarginLeft:function(){return t(),u},scrollboxSize:function(){return t(),a}}))}();function Fe(e,t,n){var r,i,o,a,s=e.style;return(n=n||$e(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||w.contains(e.ownerDocument,e)||(a=w.style(e,t)),!h.pixelBoxStyles()&&We.test(a)&&Be.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function _e(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}var ze=/^(none|table(?!-c[ea]).+)/,Xe=/^--/,Ue={position:"absolute",visibility:"hidden",display:"block"},Ve={letterSpacing:"0",fontWeight:"400"},Ge=["Webkit","Moz","ms"],Ye=r.createElement("div").style;function Qe(e){if(e in Ye)return e;var t=e[0].toUpperCase()+e.slice(1),n=Ge.length;while(n--)if((e=Ge[n]+t)in Ye)return e}function Je(e){var t=w.cssProps[e];return t||(t=w.cssProps[e]=Qe(e)||e),t}function Ke(e,t,n){var r=ie.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function Ze(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=w.css(e,n+oe[a],!0,i)),r?("content"===n&&(u-=w.css(e,"padding"+oe[a],!0,i)),"margin"!==n&&(u-=w.css(e,"border"+oe[a]+"Width",!0,i))):(u+=w.css(e,"padding"+oe[a],!0,i),"padding"!==n?u+=w.css(e,"border"+oe[a]+"Width",!0,i):s+=w.css(e,"border"+oe[a]+"Width",!0,i));return!r&&o>=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a<i;a++)o[t[a]]=w.css(e,t[a],!1,r);return o}return void 0!==n?w.style(e,t,n):w.css(e,t)},e,t,arguments.length>1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?"":"px")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function ct(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&ae(e),y=J.get(e,"fxshow");n.queue||(null==(a=w._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,w.queue(e,"fx").length||a.empty.fire()})}));for(r in t)if(i=t[r],it.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!y||void 0===y[r])continue;g=!0}d[r]=y&&y[r]||w.style(e,r)}if((u=!w.isEmptyObject(t))||!w.isEmptyObject(d)){f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=y&&y.display)&&(l=J.get(e,"display")),"none"===(c=w.css(e,"display"))&&(l?c=l:(fe([e],!0),l=e.style.display||l,c=w.css(e,"display"),fe([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===w.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1;for(r in d)u||(y?"hidden"in y&&(g=y.hidden):y=J.access(e,"fxshow",{display:l}),o&&(y.hidden=!g),g&&fe([e],!0),p.done(function(){g||fe([e]),J.remove(e,"fxshow");for(r in d)w.style(e,r,d[r])})),u=lt(g?y[r]:0,r,p),r in y||(y[r]=u.start,g&&(u.end=u.start,u.start=0))}}function ft(e,t){var n,r,i,o,a;for(n in e)if(r=G(n),i=t[r],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=w.cssHooks[r])&&"expand"in a){o=a.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}function pt(e,t,n){var r,i,o=0,a=pt.prefilters.length,s=w.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;for(var t=nt||st(),n=Math.max(0,l.startTime+l.duration-t),r=1-(n/l.duration||0),o=0,a=l.tweens.length;o<a;o++)l.tweens[o].run(r);return s.notifyWith(e,[l,r,n]),r<1&&a?n:(a||s.notifyWith(e,[l,1,0]),s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:w.extend({},t),opts:w.extend(!0,{specialEasing:{},easing:w.easing._default},n),originalProperties:t,originalOptions:n,startTime:nt||st(),duration:n.duration,tweens:[],createTween:function(t,n){var r=w.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;n<r;n++)l.tweens[n].run(1);return t?(s.notifyWith(e,[l,1,0]),s.resolveWith(e,[l,t])):s.rejectWith(e,[l,t]),this}}),c=l.props;for(ft(c,l.opts.specialEasing);o<a;o++)if(r=pt.prefilters[o].call(l,e,c,l.opts))return g(r.stop)&&(w._queueHooks(l.elem,l.opts.queue).stop=r.stop.bind(r)),r;return w.map(c,lt,l),g(l.opts.start)&&l.opts.start.call(e,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),w.fx.timer(w.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l}w.Animation=w.extend(pt,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return ue(n.elem,e,ie.exec(t),n),n}]},tweener:function(e,t){g(e)?(t=e,e=["*"]):e=e.match(M);for(var n,r=0,i=e.length;r<i;r++)n=e[r],pt.tweeners[n]=pt.tweeners[n]||[],pt.tweeners[n].unshift(t)},prefilters:[ct],prefilter:function(e,t){t?pt.prefilters.unshift(e):pt.prefilters.push(e)}}),w.speed=function(e,t,n){var r=e&&"object"==typeof e?w.extend({},e):{complete:n||!n&&t||g(e)&&e,duration:e,easing:n&&t||t&&!g(t)&&t};return w.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in w.fx.speeds?r.duration=w.fx.speeds[r.duration]:r.duration=w.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){g(r.old)&&r.old.call(this),r.queue&&w.dequeue(this,r.queue)},r},w.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ae).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=w.isEmptyObject(e),o=w.speed(t,n,r),a=function(){var t=pt(this,w.extend({},e),o);(i||J.get(this,"finish"))&&t.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(e,t,n){var r=function(e){var t=e.stop;delete e.stop,t(n)};return"string"!=typeof e&&(n=t,t=e,e=void 0),t&&!1!==e&&this.queue(e||"fx",[]),this.each(function(){var t=!0,i=null!=e&&e+"queueHooks",o=w.timers,a=J.get(this);if(i)a[i]&&a[i].stop&&r(a[i]);else for(i in a)a[i]&&a[i].stop&&ot.test(i)&&r(a[i]);for(i=o.length;i--;)o[i].elem!==this||null!=e&&o[i].queue!==e||(o[i].anim.stop(n),t=!1,o.splice(i,1));!t&&n||w.dequeue(this,e)})},finish:function(e){return!1!==e&&(e=e||"fx"),this.each(function(){var t,n=J.get(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=w.timers,a=r?r.length:0;for(n.finish=!0,w.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;t<a;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}}),w.each(["toggle","show","hide"],function(e,t){var n=w.fn[t];w.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ut(t,!0),e,r,i)}}),w.each({slideDown:ut("show"),slideUp:ut("hide"),slideToggle:ut("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){w.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),w.timers=[],w.fx.tick=function(){var e,t=0,n=w.timers;for(nt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||w.fx.stop(),nt=void 0},w.fx.timer=function(e){w.timers.push(e),w.fx.start()},w.fx.interval=13,w.fx.start=function(){rt||(rt=!0,at())},w.fx.stop=function(){rt=null},w.fx.speeds={slow:600,fast:200,_default:400},w.fn.delay=function(t,n){return t=w.fx?w.fx.speeds[t]||t:t,n=n||"fx",this.queue(n,function(n,r){var i=e.setTimeout(n,t);r.stop=function(){e.clearTimeout(i)}})},function(){var e=r.createElement("input"),t=r.createElement("select").appendChild(r.createElement("option"));e.type="checkbox",h.checkOn=""!==e.value,h.optSelected=t.selected,(e=r.createElement("input")).value="t",e.type="radio",h.radioValue="t"===e.value}();var dt,ht=w.expr.attrHandle;w.fn.extend({attr:function(e,t){return z(this,w.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!N(n.parentNode,"optgroup"))){if(t=w(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=w.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=w.inArray(w.valHooks.option.get(r),o)>-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w("<script>").prop({charset:e.scriptCharset,src:e.url}).on("load error",n=function(e){t.remove(),n=null,e&&o("error"===e.type?404:200,e.type)}),r.head.appendChild(t[0])},abort:function(){n&&n()}}}});var Yt=[],Qt=/(=)\?(?=&|$)|\?\?/;w.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Yt.pop()||w.expando+"_"+Et++;return this[e]=!0,e}}),w.ajaxPrefilter("json jsonp",function(t,n,r){var i,o,a,s=!1!==t.jsonp&&(Qt.test(t.url)?"url":"string"==typeof t.data&&0===(t.contentType||"").indexOf("application/x-www-form-urlencoded")&&Qt.test(t.data)&&"data");if(s||"jsonp"===t.dataTypes[0])return i=t.jsonpCallback=g(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,s?t[s]=t[s].replace(Qt,"$1"+i):!1!==t.jsonp&&(t.url+=(kt.test(t.url)?"&":"?")+t.jsonp+"="+i),t.converters["script json"]=function(){return a||w.error(i+" was not called"),a[0]},t.dataTypes[0]="json",o=e[i],e[i]=function(){a=arguments},r.always(function(){void 0===o?w(e).removeProp(i):e[i]=o,t[i]&&(t.jsonpCallback=n.jsonpCallback,Yt.push(i)),a&&g(o)&&o(a[0]),a=o=void 0}),"script"}),h.createHTMLDocument=function(){var e=r.implementation.createHTMLDocument("").body;return e.innerHTML="<form></form><form></form>",2===e.childNodes.length}(),w.parseHTML=function(e,t,n){if("string"!=typeof e)return[];"boolean"==typeof t&&(n=t,t=!1);var i,o,a;return t||(h.createHTMLDocument?((i=(t=r.implementation.createHTMLDocument("")).createElement("base")).href=r.location.href,t.head.appendChild(i)):t=r),o=A.exec(e),a=!n&&[],o?[t.createElement(o[1])]:(o=xe([e],t,a),a&&a.length&&w(a).remove(),w.merge([],o.childNodes))},w.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return s>-1&&(r=vt(e.slice(s)),e=e.slice(0,s)),g(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),a.length>0&&w.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?w("<div>").append(w.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},w.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){w.fn[t]=function(e){return this.on(t,e)}}),w.expr.pseudos.animated=function(e){return w.grep(w.timers,function(t){return e===t.elem}).length},w.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l,c=w.css(e,"position"),f=w(e),p={};"static"===c&&(e.style.position="relative"),s=f.offset(),o=w.css(e,"top"),u=w.css(e,"left"),(l=("absolute"===c||"fixed"===c)&&(o+u).indexOf("auto")>-1)?(a=(r=f.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),g(t)&&(t=t.call(e,n,w.extend({},s))),null!=t.top&&(p.top=t.top-s.top+a),null!=t.left&&(p.left=t.left-s.left+i),"using"in t?t.using.call(e,p):f.css(p)}},w.fn.extend({offset:function(e){if(arguments.length)return void 0===e?this:this.each(function(t){w.offset.setOffset(this,e,t)});var t,n,r=this[0];if(r)return r.getClientRects().length?(t=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:t.top+n.pageYOffset,left:t.left+n.pageXOffset}):{top:0,left:0}},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===w.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===w.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=w(e).offset()).top+=w.css(e,"borderTopWidth",!0),i.left+=w.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-w.css(r,"marginTop",!0),left:t.left-i.left-w.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===w.css(e,"position"))e=e.offsetParent;return e||be})}}),w.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,t){var n="pageYOffset"===t;w.fn[e]=function(r){return z(this,function(e,r,i){var o;if(y(e)?o=e:9===e.nodeType&&(o=e.defaultView),void 0===i)return o?o[t]:e[r];o?o.scrollTo(n?o.pageXOffset:i,n?i:o.pageYOffset):e[r]=i},e,r,arguments.length)}}),w.each(["top","left"],function(e,t){w.cssHooks[t]=_e(h.pixelPosition,function(e,n){if(n)return n=Fe(e,t),We.test(n)?w(e).position()[t]+"px":n})}),w.each({Height:"height",Width:"width"},function(e,t){w.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,r){w.fn[r]=function(i,o){var a=arguments.length&&(n||"boolean"!=typeof i),s=n||(!0===i||!0===o?"margin":"border");return z(this,function(t,n,i){var o;return y(t)?0===r.indexOf("outer")?t["inner"+e]:t.document.documentElement["client"+e]:9===t.nodeType?(o=t.documentElement,Math.max(t.body["scroll"+e],o["scroll"+e],t.body["offset"+e],o["offset"+e],o["client"+e])):void 0===i?w.css(t,n,s):w.style(t,n,i,s)},t,a?i:void 0,a)}})}),w.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,t){w.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),w.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),w.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}}),w.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),g(e))return r=o.call(arguments,2),i=function(){return e.apply(t||this,r.concat(o.call(arguments)))},i.guid=e.guid=e.guid||w.guid++,i},w.holdReady=function(e){e?w.readyWait++:w.ready(!0)},w.isArray=Array.isArray,w.parseJSON=JSON.parse,w.nodeName=N,w.isFunction=g,w.isWindow=y,w.camelCase=G,w.type=x,w.now=Date.now,w.isNumeric=function(e){var t=w.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},"function"==typeof define&&define.amd&&define("jquery",[],function(){return w});var Jt=e.jQuery,Kt=e.$;return w.noConflict=function(t){return e.$===w&&(e.$=Kt),t&&e.jQuery===w&&(e.jQuery=Jt),w},t||(e.jQuery=e.$=w),w});
diff --git a/org.lamport.tla.toolbox.jnlp/plugin.xml b/org.lamport.tla.toolbox.jnlp/plugin.xml
index ef09bf95716504abbf5aba2b88bd4fbca12559fb..495a62a74206bcdecdddc09070377c3785e9679d 100644
--- a/org.lamport.tla.toolbox.jnlp/plugin.xml
+++ b/org.lamport.tla.toolbox.jnlp/plugin.xml
@@ -38,6 +38,14 @@
             alias="/files/dist-tlc.zip"
             base-name="files/dist-tlc.zip">
       </resource>
+      <resource
+            alias="/files/animator.html"
+            base-name="files/animator.html">
+      </resource>
+      <resource
+            alias="/files/jquery.js"
+            base-name="files/jquery.js">
+      </resource>
    </extension>
 
 
diff --git a/org.lamport.tla.toolbox.jnlp/src/org/lamport/tla/toolbox/distributed/CombinedJNLPGeneratorServlet.java b/org.lamport.tla.toolbox.jnlp/src/org/lamport/tla/toolbox/distributed/CombinedJNLPGeneratorServlet.java
index e3a88e92a966d6dfd74798b9fd07033d76afb5c2..fc30320f8d145dcb70b7077dc6026304de4a0649 100644
--- a/org.lamport.tla.toolbox.jnlp/src/org/lamport/tla/toolbox/distributed/CombinedJNLPGeneratorServlet.java
+++ b/org.lamport.tla.toolbox.jnlp/src/org/lamport/tla/toolbox/distributed/CombinedJNLPGeneratorServlet.java
@@ -1,6 +1,15 @@
 // Copyright (c) 2012 Markus Alexander Kuppe. All rights reserved.
 package org.lamport.tla.toolbox.distributed;
 
+/**
+ * Serves the JNLP file for the fingerprint server & TLC worker combination.
+ * 
+ * Beginning with 1.6.1 we ceased supporting JNLP, due to our move to Java 11. Until a contributor arrives to take over
+ * this functionality, including providing a nice way to bundle IcedTea or similar with the Toolbox, i am marking this
+ * class as deprecated.
+ * 
+ * @deprecated
+ */
 @SuppressWarnings("serial")
 public class CombinedJNLPGeneratorServlet extends JNLPGeneratorServlet {
 
diff --git a/org.lamport.tla.toolbox.jnlp/src/org/lamport/tla/toolbox/distributed/FPSetJNLPGeneratorServlet.java b/org.lamport.tla.toolbox.jnlp/src/org/lamport/tla/toolbox/distributed/FPSetJNLPGeneratorServlet.java
index c4d399d314144dfbd21bef7ff0c42b66bf9f69ac..876e47a4d92fbf84db71bcfc473e0d839dc7ffff 100644
--- a/org.lamport.tla.toolbox.jnlp/src/org/lamport/tla/toolbox/distributed/FPSetJNLPGeneratorServlet.java
+++ b/org.lamport.tla.toolbox.jnlp/src/org/lamport/tla/toolbox/distributed/FPSetJNLPGeneratorServlet.java
@@ -1,6 +1,15 @@
 // Copyright (c) 2012 Markus Alexander Kuppe. All rights reserved.
 package org.lamport.tla.toolbox.distributed;
 
+/**
+ * Serves the JNLP file for the fingerprint server.
+ * 
+ * Beginning with 1.6.1 we ceased supporting JNLP, due to our move to Java 11. Until a contributor arrives to take over
+ * this functionality, including providing a nice way to bundle IcedTea or similar with the Toolbox, i am marking this
+ * class as deprecated.
+ * 
+ * @deprecated
+ */
 @SuppressWarnings("serial")
 public class FPSetJNLPGeneratorServlet extends JNLPGeneratorServlet {
 	
diff --git a/org.lamport.tla.toolbox.jnlp/src/org/lamport/tla/toolbox/distributed/IndexServlet.java b/org.lamport.tla.toolbox.jnlp/src/org/lamport/tla/toolbox/distributed/IndexServlet.java
index 44c89dfa733ab9ee60161b9d8877ae80a347e678..c07b0cafd6221ae2b23d7c86b2fe6e40078a60f8 100644
--- a/org.lamport.tla.toolbox.jnlp/src/org/lamport/tla/toolbox/distributed/IndexServlet.java
+++ b/org.lamport.tla.toolbox.jnlp/src/org/lamport/tla/toolbox/distributed/IndexServlet.java
@@ -2,16 +2,17 @@
 package org.lamport.tla.toolbox.distributed;
 
 import java.io.IOException;
+import java.io.PrintWriter;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 public class IndexServlet extends URLHttpServlet {
-
 	private static final long serialVersionUID = -653938914619406447L;
 	private static final String TLA2TOOLS_JAR = "tla2tools.jar";
 
+	
 	/* (non-Javadoc)
 	 * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
 	 */
@@ -20,38 +21,59 @@ public class IndexServlet extends URLHttpServlet {
 		super.doGet(req, resp);
 
 		resp.setContentType("text/html");
-		
-		resp.getWriter().println("<!DOCTYPE html>");
 
-		resp.getWriter().println(
+		final PrintWriter writer = resp.getWriter();
+		writer.println("<!DOCTYPE html>");
+
+		writer.println(
 				"<html><head>\n" + 
 						"<title>Distributed TLC</title>\n" + 
 				"</head><body>");
 		
 		// boostrap JRE on Windows systems
-		resp.getWriter().println(
+		writer.println(
 				"<object codebase=\"http://java.sun.com/update/1.7.0/jinstall-7u80-windows-i586.cab#Version=7,0,0,0\" classid=\"clsid:5852F5ED-8BF4-11D4-A245-0080C6F74284\" height='0' width='0'>" +
 						"<param name=\"app\" value=\"" + addr + "\"/>" +
 						"<param name=\"back\" value=\"false\"/>" +
 				"</object>");
 		
-		// first table
-		printTable(resp, JNLPGeneratorServlet.JNLP, JNLPGeneratorServlet.MAINCLASS, "worker", JNLPGeneratorServlet.INDEX_DESC);
+		writer.println(
+				"<p style=\"margin: 12px 20px;\">" +
+				"<b>Please note:</b> " +
+				"Starting with the 1.6.1 release of the Toolbox, we have removed the JNLP functionality previously " +
+				"found on this page. This is due to our move towards full Java 11+ usage (support for Java WebStart " +
+				"was removed beginning with Java 9.)" + 
+				"<br/>" +
+				"<ul>" + 
+				"<li>If you found the JNLP functionality to be critical to your usage, please open an issue at " +
+				"<a href=\"https://github.com/tlaplus/tlaplus/issues\" target=_blank>our GitHub repository.</a></li>" +
+				"<li>If you would like to take over development and deployment support for the JNLP related " +
+				"functionality, please contact us.</li>" +
+				"</ul>" + 
+				"</p>" +
+				"<hr style=\"margin-left: auto; margin-right: auto; width: 67%\"/>");
+		
+		// TLC worker
+		printTable(writer, JNLPGeneratorServlet.JNLP, JNLPGeneratorServlet.MAINCLASS, "worker",
+				JNLPGeneratorServlet.INDEX_DESC);
 
-		// second table
-		printTable(resp, FPSetJNLPGeneratorServlet.JNLP, FPSetJNLPGeneratorServlet.MAINCLASS, "fingerprint set", FPSetJNLPGeneratorServlet.INDEX_DESC);
+		// Fingerprint server
+		printTable(writer, FPSetJNLPGeneratorServlet.JNLP, FPSetJNLPGeneratorServlet.MAINCLASS, "fingerprint set",
+				FPSetJNLPGeneratorServlet.INDEX_DESC);
 		
-		// third table
-		printTable(resp, CombinedJNLPGeneratorServlet.JNLP, CombinedJNLPGeneratorServlet.MAINCLASS, "combined", CombinedJNLPGeneratorServlet.INDEX_DESC);
+		// Combined fingerprint server and TLC worker
+		printTable(writer, CombinedJNLPGeneratorServlet.JNLP, CombinedJNLPGeneratorServlet.MAINCLASS, "combined",
+				CombinedJNLPGeneratorServlet.INDEX_DESC);
 		
 		// d) dist-tlc.zip OSGi fw that acts as a TLCWorker daemon
-		resp.getWriter().println(
+		writer.println(
 				"<table id=\"header\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" border=\"0\">\n" + 
-					"<p>Start a daemon-stlye TLCWorker (no need to restart the worker for each model checker run)</p>\n" + 
+					"<p style=\"font-size: 125%; font-weight: 700;\">Start a daemon-stlye TLCWorker (no need " +
+						"to restart the worker for each model checker run)</p>\n" + 
 					"<tr><td>\n" + 
 					"<ul>");
 			
-		resp.getWriter().println(
+		writer.println(
 				"<li>\n" + 
 					"<p>Run from slave command line (works best with <a href=\"http://www.oracle.com/technetwork/java/javase/downloads/index.html\">Java 8</a>):</p>\n" + 
 					// Linux
@@ -84,51 +106,52 @@ public class IndexServlet extends URLHttpServlet {
 														+ "-jar C:\\tmp\\disttlc\\dist-tlc.jar"
 														+				"\n</pre>\n" + 
 				"</li>");
-		resp.getWriter().println(
+		writer.println(
 				"</ul>\n" + 
 				"</td></tr></table>\n");
 		
-		resp.getWriter().println(
+		writer.println(
 				"</body></html>");
 	}
 
-	private void printTable(final HttpServletResponse resp, final String jnlpName, final String mainClass, final String name, final String description) throws IOException {
-		resp.getWriter().println(
+	private void printTable(final PrintWriter writer, final String jnlpName, final String mainClass, final String name, final String description) throws IOException {
+		writer.println(
 				"<table id=\"header\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" border=\"0\">\n" + 
-					"<p>" + description + "</p>\n" + 
-					"<tr><td>\n" + 
-					"<ul>");
+					"<p style=\"font-size: 125%; font-weight: 700;\">" + description + "</p>\n" + 
+					"<tr><td>\n");// + 
+//					"<ul>");
 			
-		// a) fpset direct link
-		resp.getWriter().println(
-				"<li>\n" + 
-						"<p><a href=\"" + jnlpName + "\" id=\"jnlp-link\"><img alt=\"launch FPSet\" src=\"/files/webstart.gif\" /> Launch "
-								+ name + " from browser</a></p>\n" + 
-				"</li>");
+		// a) direct link
+//		writer.println(
+//				"<li>\n" + 
+//						"<p><a href=\"" + jnlpName + "\" id=\"jnlp-link\"><img alt=\"launch FPSet\" src=\"/files/webstart.gif\" /> Launch "
+//								+ name + " from browser</a></p>\n" + 
+//				"</li>");
 		
 		// b) command line
-		resp.getWriter().println(
-				"<li>\n" + 
-					"<p>Run from slave command line:</p>\n" + 
-					"<p><pre>" + 
-						"javaws " + addr + "/" + jnlpName +
-					"</pre></p>\n" + 
-				"</li>");
+//		writer.println(
+//				"<li>\n" + 
+//					"<p>Run from slave command line:</p>\n" + 
+//					"<p><pre>" + 
+//						"javaws " + addr + "/" + jnlpName +
+//					"</pre></p>\n" + 
+//				"</li>");
 		
 		// c) headless
-		resp.getWriter().println(
-				"<li>\n" + 
-					"<p>Or if the slave is headless:</p>\n" + 
+		writer.println(
+//				"<li>\n" + 
+//					"<p>Or if the slave is headless:</p>\n" + 
 					"<pre>\n" + 
 						"wget " + addr + "/files/" + TLA2TOOLS_JAR + "\n" + 
 						"java -Djava.rmi.server.hostname=" + remoteAddr
 								+ " -cp <a href=\"/files/" + TLA2TOOLS_JAR + "\">" + TLA2TOOLS_JAR + "</a> " + mainClass
 						+ " " + url.getHost() + "\n" +
-					"</pre>\n" + 
-				"</li>");
+					"</pre>\n"); // + 
+//				"</li>");
 		
-		resp.getWriter().println(
-				"</ul>\n" + 
-				"</td></tr></table>\n");
+		writer.println(
+//				"</ul>\n" + 
+				"</td></tr></table>\n" +
+				"<hr style=\"margin-left: auto; margin-right: auto; width: 67%\"/>");
 	}
 }
diff --git a/org.lamport.tla.toolbox.jnlp/src/org/lamport/tla/toolbox/distributed/JNLPGeneratorServlet.java b/org.lamport.tla.toolbox.jnlp/src/org/lamport/tla/toolbox/distributed/JNLPGeneratorServlet.java
index 2c52ecae08704841587840b3408d6797a161a4eb..daad0a22941056154c2cc2cc9f83c8e78a0bf72d 100644
--- a/org.lamport.tla.toolbox.jnlp/src/org/lamport/tla/toolbox/distributed/JNLPGeneratorServlet.java
+++ b/org.lamport.tla.toolbox.jnlp/src/org/lamport/tla/toolbox/distributed/JNLPGeneratorServlet.java
@@ -8,7 +8,13 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 /**
- * Serves the {@link tlc2.tool.distributed.TLCWorker} jnlp file
+ * Serves the {@link tlc2.tool.distributed.TLCWorker} JNLP file.
+ * 
+ * Beginning with 1.6.1 we ceased supporting JNLP, due to our move to Java 11. Until a contributor arrives to take over
+ * this functionality, including providing a nice way to bundle IcedTea or similar with the Toolbox, i am marking this
+ * class as deprecated.
+ * 
+ * @deprecated
  */
 public class JNLPGeneratorServlet extends URLHttpServlet {
 
@@ -16,7 +22,7 @@ public class JNLPGeneratorServlet extends URLHttpServlet {
 	public static final String VM_ARGS = "vmargs";
 	public static final String MAINCLASS = "tlc2.tool.distributed.TLCWorker";
 	public static final String DESCRIPTION = "Distributed TLC worker instance";
-	public static final String INDEX_DESC = "Connect to TLCworker one of these ways:";
+	public static final String INDEX_DESC = "Connecting a TLCworker:";
 	public static final String JNLP = "worker.jnlp";
 
 	protected final String mainClass;
diff --git a/org.lamport.tla.toolbox.product.product/TLAToolbox.target b/org.lamport.tla.toolbox.product.product/TLAToolbox.target
index 973e5aff713fcaacdab5890eb1a5cb476124afb6..cce1233f60774962689ec0da9f45fa14b9fd1ed1 100644
--- a/org.lamport.tla.toolbox.product.product/TLAToolbox.target
+++ b/org.lamport.tla.toolbox.product.product/TLAToolbox.target
@@ -1,26 +1,26 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?><?pde version="3.8"?><target name="TLA+ Toolbox" sequenceNumber="86">
 <locations>
 <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
-<unit id="org.eclipse.contribution.weaving.feature.group" version="2.2.4.201805281636"/>
-<unit id="org.eclipse.ajdt.feature.group" version="2.2.4.201805281636"/>
-<repository id="eclipse-ajdt" location="http://download.eclipse.org/tools/ajdt/48/dev/update/ajdt-e48-2.2.4.201805281636/"/>
+<unit id="org.eclipse.contribution.weaving.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.ajdt.feature.group" version="0.0.0"/>
+<repository id="eclipse-ajdt" location="http://download.eclipse.org/tools/ajdt/48/dev/update/ajdt-e48-2.2.4.201908131520/"/>
 </location>
 <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
-<unit id="org.apache.log4j" version="1.2.15.v201012070815"/>
-<unit id="org.hamcrest" version="1.1.0.v20090501071000"/>
-<unit id="com.jcraft.jsch" version="0.1.54.v20170116-1932"/>
-<unit id="org.apache.commons.io" version="2.2.0.v201405211200"/>
-<unit id="org.apache.commons.collections" version="3.2.2.v201511171945"/>
-<unit id="javax.activation" version="1.1.0.v201211130549"/>
-<unit id="javax.mail" version="1.4.0.v201005080615"/>
-<unit id="org.easymock" version="2.4.0.v20090202-0900"/>
+<unit id="org.apache.log4j" version="0.0.0"/>
+<unit id="org.hamcrest" version="0.0.0"/>
+<unit id="com.jcraft.jsch" version="0.0.0"/>
+<unit id="org.apache.commons.io" version="0.0.0"/>
+<unit id="org.apache.commons.collections" version="0.0.0"/>
+<unit id="javax.activation" version="0.0.0"/>
+<unit id="javax.mail" version="0.0.0"/>
+<unit id="org.easymock" version="0.0.0"/>
 <repository id="eclipse-orbit" location="http://download.eclipse.org/tools/orbit/downloads/drops/R20180905201904/repository/"/>
 </location>
 <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
-<unit id="org.eclipse.swtbot.ide.feature.group" version="2.7.0.201806111355"/>
-<unit id="org.eclipse.swtbot.eclipse.test.junit.feature.group" version="2.7.0.201806111355"/>
-<unit id="org.eclipse.swtbot.feature.group" version="2.7.0.201806111355"/>
-<unit id="org.eclipse.swtbot.eclipse.feature.group" version="2.7.0.201806111355"/>
+<unit id="org.eclipse.swtbot.ide.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.swtbot.eclipse.test.junit.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.swtbot.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.swtbot.eclipse.feature.group" version="0.0.0"/>
 <repository id="eclipse-swtbot" location="http://download.eclipse.org/technology/swtbot/releases/2.7.0/"/>
 </location>
 <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
@@ -28,20 +28,24 @@
 <repository location="http://lemmy.github.com/jclouds2p2/"/>
 </location>
 <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
-<unit id="org.eclipse.help.feature.group" version="2.2.300.v20180906-0745"/>
-<unit id="org.eclipse.equinox.core.sdk.feature.group" version="3.15.0.v20180827-1536"/>
-<unit id="org.eclipse.platform.feature.group" version="4.9.0.v20180906-1121"/>
-<unit id="org.eclipse.rcp.configuration.feature.group" version="1.1.200.v20180906-0745"/>
-<unit id="org.eclipse.emf.ecore.feature.group" version="2.15.0.v20180722-1159"/>
-<unit id="org.eclipse.equinox.executable" version="3.8.100.v20180827-1352"/>
-<unit id="org.eclipse.ecf.core.feature.feature.group" version="1.5.1.v20180810-0833"/>
-<unit id="org.eclipse.e4.rcp.feature.group" version="1.6.200.v20180906-1121"/>
-<unit id="org.eclipse.emf.common.feature.group" version="2.15.0.v20180723-1316"/>
-<unit id="org.eclipse.equinox.sdk.feature.group" version="3.15.0.v20180904-1442"/>
-<unit id="org.eclipse.core.runtime.feature.feature.group" version="1.2.200.v20180903-1343"/>
-<unit id="org.eclipse.jdt.feature.group" version="3.15.0.v20180906-0745"/>
-<unit id="org.eclipse.pde.source.feature.group" version="3.13.200.v20180906-0745"/>
-<repository id="eclipse" location="http://download.eclipse.org/eclipse/updates/4.9/R-4.9-201809060745"/>
+<unit id="org.eclipse.help.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.equinox.core.sdk.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.platform.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.rcp.configuration.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.emf.ecore.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.equinox.executable" version="0.0.0"/>
+<unit id="org.eclipse.ecf.core.feature.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.e4.rcp.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.emf.common.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.equinox.sdk.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.core.runtime.feature.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.jdt.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.pde.source.feature.group" version="0.0.0"/>
+<repository id="eclipse" location="http://download.eclipse.org/eclipse/updates/4.13/R-4.13-201909161045"/>
+</location>
+<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
+<unit id="org.eclipse.egit.feature.group" version="0.0.0"/>
+<repository location="http://download.eclipse.org/egit/updates/"/>
 </location>
 <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
 <unit id="de.vonloesch.pdf4eclipse.feature.feature.group" version="0.0.0"/>
@@ -52,16 +56,16 @@
 <repository location="http://lemmy.github.com/eclipse-jdk-bundles/"/>
 </location>
 <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
-<unit id="com.abstratt.eclipsegraphviz.feature.feature.group" version="2.5.201812"/>
+<unit id="com.abstratt.eclipsegraphviz.feature.feature.group" version="0.0.0"/>
 <repository location="jar:https://dl.bintray.com/abstratt-oss/abstratt-oss/com/abstratt/eclipsegraphviz/com.abstratt.eclipsegraphviz.repository/2.5.201812/com.abstratt.eclipsegraphviz.repository-2.5.201812.zip!/"/>
 </location>
 <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
-<unit id="org.eclipse.recommenders.news.rcp.feature.feature.group" version="2.5.4.v20180909-1132"/>
+<unit id="org.eclipse.recommenders.news.rcp.feature.feature.group" version="0.0.0"/>
 <repository location="http://download.eclipse.org/releases/2018-09/201809191000"/>
 </location>
 <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
-<unit id="org.eclipse.mylyn.commons.feature.group" version="3.24.2.v20180904-2231"/>
-<unit id="org.eclipse.mylyn.commons.notifications.feature.group" version="1.16.0.v20180904-2231"/>
+<unit id="org.eclipse.mylyn.commons.feature.group" version="0.0.0"/>
+<unit id="org.eclipse.mylyn.commons.notifications.feature.group" version="0.0.0"/>
 <repository location="http://download.eclipse.org/mylyn/releases/3.24"/>
 </location>
 <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit">
diff --git a/org.lamport.tla.toolbox.product.product/org.lamport.tla.toolbox.product.product.product b/org.lamport.tla.toolbox.product.product/org.lamport.tla.toolbox.product.product.product
index aeaafcf998dd0151dc6967f92a35652e17b3130f..253c3038cd7482f55fa72ef736eac6873e44cc1b 100644
--- a/org.lamport.tla.toolbox.product.product/org.lamport.tla.toolbox.product.product.product
+++ b/org.lamport.tla.toolbox.product.product/org.lamport.tla.toolbox.product.product.product
@@ -8,7 +8,7 @@
       <text>
          TLA+ Toolbox provides a user interface for TLA+ Tools. 
 
-This is Version 1.6.0 of Day Month 20?? and includes:
+This is Version 1.6.1 of Day Month 20?? and includes:
   - SANY Version 2.1 of 23 July 2017
   - TLC Version 2.14 of 10 July 2019
   - PlusCal Version 1.9 of 10 July 2019
@@ -86,7 +86,7 @@ openFile
       <plugin id="jclouds-core" autoStart="true" startLevel="4" />
       <plugin id="org.eclipse.core.runtime" autoStart="true" startLevel="4" />
       <plugin id="org.eclipse.equinox.common" autoStart="true" startLevel="2" />
-      <plugin id="org.eclipse.equinox.ds" autoStart="true" startLevel="2" />
+      <plugin id="org.apache.felix.scr" autoStart="true" startLevel="2" />
       <plugin id="org.eclipse.equinox.event" autoStart="true" startLevel="2" />
       <plugin id="org.eclipse.equinox.http.jetty" autoStart="true" startLevel="3" />
       <plugin id="org.eclipse.equinox.http.registry" autoStart="true" startLevel="3" />
@@ -95,11 +95,11 @@ openFile
       <plugin id="org.lamport.tla.toolbox.jclouds" autoStart="true" startLevel="4" />
       <plugin id="packet" autoStart="true" startLevel="4" />
       <plugin id="sts" autoStart="true" startLevel="4" />
-      <property name="eclipse.buildId" value="1.6.0" />
+      <property name="eclipse.buildId" value="1.6.1" />
    </configurations>
 
    <repositories>
-      <repository location="http://lamport.org/tlatoolbox/branches/1.6.0/toolboxUpdate/" enabled="true" />
+      <repository location="http://lamport.org/tlatoolbox/branches/1.6.1/toolboxUpdate/" enabled="true" />
       <repository location="http://lamport.org/tlatoolbox/ci/toolboxUpdate/" enabled="false" />
    </repositories>
 
diff --git a/org.lamport.tla.toolbox.product.product/src/deb/control/control b/org.lamport.tla.toolbox.product.product/src/deb/control/control
index 9a43bac6206620b6633e408092d1718971ffa06c..feca96629582595b125e55bb0961ada93b9338e5 100644
--- a/org.lamport.tla.toolbox.product.product/src/deb/control/control
+++ b/org.lamport.tla.toolbox.product.product/src/deb/control/control
@@ -3,10 +3,6 @@ Version: [[product.version]]~[[product.build]]
 Section: misc
 Distribution: development
 Priority: optional
-## default-jre points to openjdk-11-re on Ubuntu for Bionic and up. We are not going to support Xenial/2016.
-## default-jre installs Java 8 on Debian stretch (The successor buster already has Java 11). Users of stretch
-## have to manually instal openjdk-11-jre from stretch backports (https://packages.debian.org/stretch-backports/openjdk-11-dbg)  
-Depends: default-jre (>= 1.7)
 Recommends: texlive-latex-recommended, libwebkitgtk-1.0-0
 Architecture: amd64
 Description: The TLA Toolbox is an IDE (integrated development environment) for the TLA+ tools.
diff --git a/org.lamport.tla.toolbox.product.product/src/deb/control/postinst b/org.lamport.tla.toolbox.product.product/src/deb/control/postinst
index 3fea71ebf4ec17f7543efb5091fac4e184cbf72b..9f224232924cd30f97d2d1e3a978cc17e3549a81 100644
--- a/org.lamport.tla.toolbox.product.product/src/deb/control/postinst
+++ b/org.lamport.tla.toolbox.product.product/src/deb/control/postinst
@@ -4,6 +4,7 @@
 chmod 755 /opt/TLA+Toolbox/toolbox
 chmod 755 /opt/TLA+Toolbox/tla2tools.jar
 chmod 755 /opt/TLA+Toolbox/plugins/org.lamport.openjdk.linux.x86_64_*/jre/bin/*
+chmod 755 /opt/TLA+Toolbox/plugins/org.lamport.openjdk.linux.x86_64_*/jre/lib/jspawnhelper
 
 ## Update mime database for x-tla type.
 /usr/bin/update-mime-database /usr/share/mime
diff --git a/org.lamport.tla.toolbox.product.standalone/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.product.standalone/META-INF/MANIFEST.MF
index 9579ae4ec2f514977d544768d662dd1cf144dddc..c90d062bb676ae9ce83164adee3a1ac66308e637 100644
--- a/org.lamport.tla.toolbox.product.standalone/META-INF/MANIFEST.MF
+++ b/org.lamport.tla.toolbox.product.standalone/META-INF/MANIFEST.MF
@@ -18,7 +18,10 @@ Require-Bundle: org.eclipse.ui,
  org.eclipse.equinox.p2.ui.sdk;bundle-version="1.0.0",
  org.eclipse.equinox.p2.operations;bundle-version="2.4.0",
  org.eclipse.equinox.p2.repository;bundle-version="2.3.0",
- org.eclipse.equinox.p2.metadata;bundle-version="2.3.0"
+ org.eclipse.equinox.p2.metadata;bundle-version="2.3.0",
+ org.eclipse.ui.themes;bundle-version="1.2.200",
+ org.eclipse.e4.ui.css.swt;bundle-version="0.13.200",
+ org.eclipse.e4.ui.css.swt.theme;bundle-version="0.12.100"
 Bundle-ActivationPolicy: lazy
 Bundle-Activator: org.lamport.tla.toolbox.StandaloneActivator
 Export-Package: org.lamport.tla.toolbox.lifecycle,
diff --git a/org.lamport.tla.toolbox.product.standalone/plugin.xml b/org.lamport.tla.toolbox.product.standalone/plugin.xml
index f711ae8773c3b89b4c4076ed4626e773a75fb86d..785eaed5d4b4c3482ae25ee947a5c5fc2bad89d5 100644
--- a/org.lamport.tla.toolbox.product.standalone/plugin.xml
+++ b/org.lamport.tla.toolbox.product.standalone/plugin.xml
@@ -30,7 +30,7 @@
          </property>
          <property
                name="aboutText"
-               value="TLA+ Toolbox provides a user interface for TLA+ Tools. &#x0A;&#x0A;This is Version 1.6.0 of 10 July 2019 and includes:&#x0A;  - SANY Version 2.1 of 23 July 2017&#x0A;  - TLC Version 2.14 of 10 July 2019&#x0A;  - PlusCal Version 1.9 of 10 July 2019&#x0A;  - TLATeX Version 1.0 of 20 September 2017&#x0A;&#x0A;Don&apos;t forget to click on help.  You can learn about features that you never knew about or have forgotten.&#x0A;&#x0A;Please send us reports of problems or suggestions; see https://groups.google.com/d/forum/tlaplus .&#x0A;&#x0A;Some icons used in the Toolbox were provided by www.flaticon.com">
+               value="TLA+ Toolbox provides a user interface for TLA+ Tools. &#x0A;&#x0A;This is Version 1.6.1 of Day Month 20?? and includes:&#x0A;  - SANY Version 2.1 of 23 July 2017&#x0A;  - TLC Version 2.15 of Day Month 20??&#x0A;  - PlusCal Version 1.9 of 10 July 2019&#x0A;  - TLATeX Version 1.0 of 20 September 2017&#x0A;&#x0A;Don&apos;t forget to click on help.  You can learn about features that you never knew about or have forgotten.&#x0A;&#x0A;Please send us reports of problems or suggestions; see https://groups.google.com/d/forum/tlaplus .&#x0A;&#x0A;Some icons used in the Toolbox were provided by www.flaticon.com">
          </property>
          <property
                name="aboutImage"
diff --git a/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/ApplicationActionBarAdvisor.java b/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/ApplicationActionBarAdvisor.java
index 711836e9a55545d038625ca79a0be50c5696fefa..46267f97d6ebd10032c812c01f85d6e7e884cb1f 100644
--- a/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/ApplicationActionBarAdvisor.java
+++ b/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/ApplicationActionBarAdvisor.java
@@ -3,7 +3,9 @@ package org.lamport.tla.toolbox;
 import org.eclipse.jface.action.IMenuManager;
 import org.eclipse.jface.action.MenuManager;
 import org.eclipse.jface.action.Separator;
+import org.eclipse.swt.SWT;
 import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchCommandConstants;
 import org.eclipse.ui.IWorkbenchWindow;
 import org.eclipse.ui.actions.ActionFactory;
 import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
@@ -45,8 +47,7 @@ public class ApplicationActionBarAdvisor extends ActionBarAdvisor
     /* (non-Javadoc)
      * @see org.eclipse.ui.application.ActionBarAdvisor#makeActions(org.eclipse.ui.IWorkbenchWindow)
      */
-    protected void makeActions(IWorkbenchWindow window)
-    {
+    protected void makeActions(final IWorkbenchWindow window) {
         helpContentsAction = ActionFactory.HELP_CONTENTS.create(window);
         register(helpContentsAction);
 
@@ -84,14 +85,13 @@ public class ApplicationActionBarAdvisor extends ActionBarAdvisor
         resetPerspectiveAction = ActionFactory.RESET_PERSPECTIVE.create(window);
         register(resetPerspectiveAction);
         
-        backwardHistoryAction = ActionFactory.BACKWARD_HISTORY
-                .create(window);
+        backwardHistoryAction = ActionFactory.BACKWARD_HISTORY.create(window);
+        backwardHistoryAction.setId(IWorkbenchCommandConstants.NAVIGATE_BACKWARD_HISTORY);
         register(backwardHistoryAction);
         
-        forwardHistoryAction= ActionFactory.FORWARD_HISTORY
-                .create(window);
+        forwardHistoryAction= ActionFactory.FORWARD_HISTORY.create(window);
+        forwardHistoryAction.setId(IWorkbenchCommandConstants.NAVIGATE_FORWARD_HISTORY);
         register(forwardHistoryAction);
-
     }
 
     /* (non-Javadoc)
diff --git a/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/ui/intro/ToolboxIntroPart.java b/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/ui/intro/ToolboxIntroPart.java
index 2d6c6cd3b2bd2e82e6f816f8f9714d1684a62299..48f83d6228de6f8539a99e2b7011ae16da60c281 100644
--- a/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/ui/intro/ToolboxIntroPart.java
+++ b/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/ui/intro/ToolboxIntroPart.java
@@ -431,7 +431,7 @@ public class ToolboxIntroPart extends IntroPart implements IIntroPart {
 
 		final Label lblVersion = new Label(outerContainer, SWT.WRAP);
 		lblVersion.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
-		lblVersion.setText("Version 1.6.0 of 10 July 2019");
+		lblVersion.setText("Version 1.6.1 of Day Month 20??");
 		lblVersion.setBackground(backgroundColor);
 	}
 
diff --git a/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Example.test b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Example.test
index 4a5a000f74faf0042dc349716c9d16d40ad1219b..ef2299f33c3c52fb7a4210e92a9e2f1ffc3aecd2 100644
--- a/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Example.test
+++ b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Example.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _0133MAldEem_kewt0eDFQIQ
-Runtime-Version: 2.4.2.201905122359
-Save-Time: 5/29/19, 9:02 PM
+Runtime-Version: 2.4.3.201909171500
+Save-Time: 1/10/20, 9:22 AM
 Testcase-Type: ecl
 
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac
@@ -16,34 +16,63 @@ Entry-Name: .content
 try -command {
 	// Create new spec from build-in example.
 	get-view "Welcome View" | get-button "Missionaries and Cannibals(TLA+)" | click
-	get-window -class WizardDialog | get-button Finish | click
-	get-view "Spec Explorer" | get-tree | select "MissionariesAndCannibals \\[ MissionariesAndCannibals.tla \\]/model" +
-		"s/Model_1" | double-click
+	get-window -class WizardDialog | get-button $TLA-BUTTON-FINISH | click
+	get-view $TLA-VIEW-SPEC-EXPLORER | get-tree 
+		| select "MissionariesAndCannibals/models/Model_1" | double-click
 
 	// Run model checking.
-	get-editor Model_1 | get-button "Runs TLC on the model." | click
+	get-editor $TLA-MODEL-ONE | get-button $TLA-BUTTON-RUN-TLC | click
 
 	// wait for model checking to finish.
 	wait-run
+	
+//	set-dialog-result File "/tmp/tlaplus/tlaplus-master/runtime-org.lamport.tla.toolbox.product.product.product/TExpression.tla"
+	set-dialog-result File [concat [get-workspace-location] "/MissionariesAndCannibals/TExpression.tla"]
+	get-menu -path "File/Open Module/Add TLA+ Module..." | click
+	// Note - the test will fail here if you're working via RCPTT locally and you've downloaded
+	//	the M&C spec previously without cleaning out your workspace directory.
+	get-window "TLA+ Module is not found" | get-button "Yes" | click
+	with [get-editor "TExpression" | get-text-viewer] {
+		set-caret-pos 2 1
+		type-text "EXTENDS Toolbox"
+		key-type Enter -times 1
+		type-text "tExpression == _TETrace[_TEPosition]"
+		key-type "M1+s"
+	}
+	get-menu -path "File/Parse Module" | click
 
-	// validate the error trace.
-	get-view "TLC Errors" | get-section "Error-Trace" | get-button "Toggle between expand and collapse all (Shift+Cli" +
-		"ck to restore the default two-level expansion)" | click
-	get-view "TLC Errors" | get-section "Error-Trace" | get-tree | get-property itemCount | equals 12 | verify-true
-
-	// Expand the Error-Trace Exploration section if collapsed.
-	if [get-view "TLC Errors" | get-section "Error-Trace Exploration" | get-property "isExpanded()" -raw | not ]{
-		get-view "TLC Errors" | get-section "Error-Trace Exploration" | click
+	// validate the error trace
+	with [get-view $TLA-VIEW-TLC-ERRORS] {
+		with [get-section $TLA-MO-ED-TLCERRORS-SECTION-ET] {
+			get-button "Toggle between expand and collapse all (Shift+Click to restore the default two-level expansion)" | click
+			get-tree | get-property itemCount | equals 12 | verify-true
+		}
+	
+		with [get-section $TLA-MO-ED-TLCERRORS-SECTION-ETE] {
+			// Expand the Error-Trace Exploration section if collapsed.
+			if [get-property "isExpanded()" -raw | not] {
+				click
+			}
+		
+			get-button "Extend extra modules in trace expressions which are not extended by the actual spec." | click
+		}
+	}
+	with [get-window "Extra Modules"] {
+		with [get-table] {
+			select "Randomization" | get-item -path "Randomization" | check
+			select "TExpression" | get-item -path "TExpression" | check
+		}
+		get-button $TLA-BUTTON-OK | click
 	}
 	
 	// Insert new trace explorer expression.
-	get-view "TLC Errors" | get-section "Error-Trace Exploration" | get-button Add | click
+	get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ETE | get-button $TLA-BUTTON-ADD | click
 	try -command {
 		with [get-window -class WizardDialog] {
 			with [get-text-viewer] {
-				type-text "selfRef == _TETrace[_TEPosition]"
+				type-text "selfRef == RandomSubset(1, {1})"
 			}
-			get-button Finish | click
+			get-button $TLA-BUTTON-FINISH | click
 		}
 	} -catch {
 		// This probably means that the section is collapsed instead of expanded.
@@ -51,15 +80,56 @@ try -command {
 			echo "Failed to open the Error-Trace Exploration expression input dialog" | log -severity warning 
 	}	
 
+	// // Insert new trace explorer expression.
+	get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ETE | get-button $TLA-BUTTON-ADD | click
+	try -command {
+		with [get-window -class WizardDialog] {
+			with [get-text-viewer] {
+				type-text "tExpression"
+			}
+			get-button $TLA-BUTTON-FINISH | click
+		}
+	} -catch {
+		// This probably means that the section is collapsed instead of expanded.
+		log -message Error -severity error -plugin "org.lamport.tla.toolbox.product.uitests"
+		echo "Failed to open the Error-Trace Exploration expression input dialog" | log -severity warning
+	}
+
 	// Run trace exploration.
-	get-view "TLC Errors" | get-section "Error-Trace Exploration" | get-button Explore | click
+	get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ETE | get-button $TLA-BUTTON-EXPLORE | click
 
 	wait-te
 
+    // Export trace to clipboard before the validation below sets a selection
+	with [get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ET] {
+	    get-button "Click to export error-trace to clipboard assequence of records. Shift-click to omit the action's position (_TEPosition), name, and location." 
+	        | click
+	        
+		// Validate error trace exploration
+		get-tree | get-cell 5 1 | click
+		get-text-viewer | get-property text | contains "[bank_of_boat |->" | verify-true
+	}
+
 	// Validate error trace exploration
-	get-view "TLC Errors" | get-section "Error-Trace" | get-tree | get-cell 6 0 | click
-	get-view "TLC Errors" | get-section "Error-Trace" | get-text-viewer | get-property text | contains "[bank_of_boat |" +
-		"-> \"W\", who_is_on_bank |-> [E |-> {" | verify-true
+	get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ET | get-tree | get-cell 5 1 | click
+	get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ET | get-text-viewer | get-property text
+		| contains "[bank_of_boat |->" | verify-true
+	
+	// Paste exported trace into ECE and verify it is valid TLA+
+	with [get-editor $TLA-MODEL-ONE] {
+	    click
+	    with [get-section $TLA-MO-ED-RESULTS-SECTION-ECE] {
+	        with [get-text-viewer] {
+	            key-type "M1+v"
+	            type-text "[2]._TEAction.name"
+	        }
+	        get-button "No Behavior Spec" | check
+	    }
+	    get-button $TLA-BUTTON-RUN-TLC | click
+	    with [get-section $TLA-MO-ED-RESULTS-SECTION-ECE] {
+	        get-text-viewer "Value:" | get-property text | contains "Next" | verify-true
+	    }
+	}
 } -finally {
 	DeleteSpecNew
 }
diff --git a/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Test1.test b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Test1.test
index 21bf35c7b2bb7aa8ac888ba9967f8075dfdad884..5b8ff3024ab6a7387da9b8871dcfde0a6b1a4db2 100644
--- a/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Test1.test
+++ b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Test1.test
@@ -6,7 +6,7 @@ Element-Version: 3.0
 External-Reference: 
 Id: _1OLRMAlXEem_pLt0eVfQIQ
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 6/10/19, 8:58 AM
+Save-Time: 10/14/19, 1:29 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -35,121 +35,109 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals, Sequences"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 0"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x + 1"
-	    key-type Enter -times 1
-	    type-text "Spec == Init /\ [][Next]_x"
-	    key-type Enter -times 1
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals, Sequences\nVARIABLE x\nInit == x = 0\n\nNext == x' = x + 1\nSpec == Init /\ [][Next]_x\n=============================================================================\n"]
 	    key-type "M1+s"
     }
     
-    get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
-	with [get-editor "Model_1" | get-section "What to check?"] {
-	    get-button "Deadlock" | uncheck
-	    with [get-section Invariants] {
+    get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+	with [get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK] {
+	    get-button $TLA-BUTTON-DEADLOCK | uncheck
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-INV] {
 	        click
-	        get-button "Add" | click
+	        get-button $TLA-BUTTON-ADD | click
 	    }
 	}
 	with [get-window -class WizardDialog] {
 	    get-text-viewer | type-text "x<10"
-	    get-button Finish | click
+	    get-button $TLA-BUTTON-FINISH | click
 	}
-	get-editor "Model_1" | get-link "Additional TLC Options" | click
+	get-editor $TLA-MODEL-ONE | get-link $TLA-MO-ED-OVERVIEW-LINK-TLC | click
 	get-editbox -after [get-label "Number of worker threads:"] | set-text 2
-	get-editor "Model_1" | get-button "Runs TLC on the model." | click
+	get-editor $TLA-MODEL-ONE | get-button $TLA-BUTTON-RUN-TLC | click
 
 	wait-run    
 	    
-	get-editor "Model_1" | get-section General | get-link "1 Error" | get-property caption | equals "1 Error" | verify-true
-	with [get-view "TLC Errors"] {
+	get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-RESULTS-SECTION-GENERAL | get-link "1 Error"
+	with [get-view $TLA-VIEW-TLC-ERRORS] {
 	    get-text-viewer | get-property text | equals "Invariant x<10 is violated." | verify-true
-	    get-section "Error-Trace" | get-property "getText()" | equals "Error-Trace" | verify-true
-	}
-	
-	with [get-view "TLC Errors" | get-section "Error-Trace" | get-tree] {
-	    get-item -path " <Initial predicate>" | expand
-	    get-cell 2 0 | click
-	}
-	
-	get-view "TLC Errors" | get-section "Error-Trace" | get-tree | get-cell 2 0 | click
-	get-view "TLC Errors" | get-section "Error-Trace" | get-text-viewer | get-property text | equals "/\\ x = 1" 
-	    | verify-true
-	with [get-view "TLC Errors" | get-section "Error-Trace" | get-tree] {
-	    get-item -path " <Next line 6, col 9 to line 6, col 18 of module new>" | expand
-	    get-cell 3 0 | click
-	}
-	get-view "TLC Errors" | get-section "Error-Trace" | get-text-viewer | get-property text | equals 1 | verify-true
-	get-view "TLC Errors" | get-section "Error-Trace" | get-tree | get-cell 4 0 | click
-	get-view "TLC Errors" | get-section "Error-Trace" | get-text-viewer | get-property text | equals "/\\ x = 2" 
-	    | verify-true
+	    
+	    with [get-section $TLA-MO-ED-TLCERRORS-SECTION-ET | get-tree] {
+		    get-item -path " <Initial predicate>" | expand
+		    get-cell 2 0 | click
+	    }
+	    
+	    get-section $TLA-MO-ED-TLCERRORS-SECTION-ET | get-text-viewer | get-property text | equals "/\\ x = 1" 
+	    	| verify-true
+	    	
+	    with [get-section $TLA-MO-ED-TLCERRORS-SECTION-ET | get-tree] {
+		    get-item -path " <Next line 6, col 9 to line 6, col 18 of module new>" | expand
+		    get-cell 3 0 | click
+	    }
+	    
+	    with [get-section $TLA-MO-ED-TLCERRORS-SECTION-ET] {
+			get-text-viewer | get-property text | equals 1 | verify-true
+			get-tree | get-cell 4 0 | click
+			get-text-viewer | get-property text | equals "/\\ x = 2" | verify-true
+	    }
 
-	with [get-view "TLC Errors" | get-section "Error-Trace Exploration"] {
-        get-button "Add" | click
+		get-section $TLA-MO-ED-TLCERRORS-SECTION-ETE | get-button $TLA-BUTTON-ADD | click
 	}
+
 	with [get-window -class WizardDialog] {
 	    get-text-viewer | type-text "foo == x \in Nat"
-	    get-button Finish | click
+	    get-button $TLA-BUTTON-FINISH | click
 	}
-	with [get-view "TLC Errors" | get-section "Error-Trace Exploration"] {
-        get-button "Add" | click
+	with [get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ETE] {
+        get-button $TLA-BUTTON-ADD | click
 	}
 	with [get-window -class WizardDialog] {
 	    get-text-viewer | type-text "42 # 23"
-	    get-button Finish | click
+	    get-button $TLA-BUTTON-FINISH | click
 	}
-	with [get-view "TLC Errors" | get-section "Error-Trace Exploration"] {
-        get-button "Add" | click
+	with [get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ETE] {
+        get-button $TLA-BUTTON-ADD | click
 	}
 	with [get-window -class WizardDialog] {
 	    get-text-viewer | type-text "stateNum == _TEPosition"
-	    get-button Finish | click
+	    get-button $TLA-BUTTON-FINISH | click
 	}
-	with [get-view "TLC Errors" | get-section "Error-Trace Exploration"] {
-        get-button "Add" | click
+	with [get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ETE] {
+        get-button $TLA-BUTTON-ADD | click
 	}
 	with [get-window -class WizardDialog] {
 	    get-text-viewer | type-text "sum == LET s[i \in DOMAIN _TETrace] == IF i = 1 THEN 1 ELSE s[i-1] + 1 IN s[stateNum]"
-	    get-button Finish | click
+	    get-button $TLA-BUTTON-FINISH | click
 	}
 
-	with [get-view "TLC Errors" | get-section "Error-Trace Exploration"] {
-	    get-button "Explore" | click
+	with [get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ETE] {
+	    get-button $TLA-BUTTON-EXPLORE | click
+	}
+	
+	with [get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ET] {
+		get-tree | get-cell 6 0 | click
+		get-text-viewer | get-property text | equals "/\\ 42 # 23 = TRUE\n/\\  foo = TRUE\n/\\  stateNum = 2\n/\\  sum = 2\n/\\  x = 1" 
+		    | verify-true
 	}
-   
-	get-view "TLC Errors" | get-section "Error-Trace" | get-tree | get-cell 6 0 | click
-	get-view "TLC Errors" | get-section "Error-Trace" | get-text-viewer | get-property text | equals "/\\ 42 # 23 = TRUE\n/\\  foo = TRUE\n/\\  stateNum = 2\n/\\  sum = 2\n/\\  x = 1" 
-	    | verify-true
 
-	with [get-view "TLC Errors" | get-section "Error-Trace Exploration"] {
+	with [get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ETE] {
         get-button "Restore" | click
-        get-button "Add" | click
+        get-button $TLA-BUTTON-ADD | click
 	}
 	with [get-window -class WizardDialog] {
 	    get-text-viewer | type-text "bar(n) == x \in Nat"
-	    get-button Finish | click
+	    get-button $TLA-BUTTON-FINISH | click
 	}
-	with [get-view "TLC Errors" | get-section "Error-Trace Exploration"] {
-	    get-button "Explore" | click
+	with [get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ETE] {
+	    get-button $TLA-BUTTON-EXPLORE | click
 	}
 	with [get-window "Parsing error when running trace explorer"] {
-    with [get-editbox] {
-        get-property text | equals "***Parse Error***\nWas expecting \"Expression or Instance\"\nEncountered \"Beginning of definition\"  in Error-Trace Exploration expression at line 5 and token \"==\" \n\nResidual stack trace follows:\nDefinition starting at line 51, column 1.\nModule body starting at line 5, column 1.\nModule definition starting at line 1, column 1.\n" 
-	    | verify-true
+	    with [get-editbox] {
+	        get-property text | equals "***Parse Error***\nWas expecting \"Expression or Instance\"\nEncountered \"Beginning of definition\"  in Error-Trace Exploration expression at line 5 and token \"==\" \n\nResidual stack trace follows:\nDefinition starting at line 46, column 1.\nModule body starting at line 4, column 1.\nModule definition starting at line 1, column 1.\n" 
+		    | verify-true
+	    }
+	    get-button $TLA-BUTTON-OK | click
     }
-    get-button OK | click
-}
-
 } -finally {
 	DeleteSpecNew
 }
diff --git a/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Test2.test b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Test2.test
index d55e4d418457ebc36cbe2515deb85b95d8a53488..867604b83aaa56bb85c689658744bf4b77081955 100644
--- a/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Test2.test
+++ b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA.End.To.End.Test2.test
@@ -6,7 +6,7 @@ Element-Version: 3.0
 External-Reference: 
 Id: _0133MAldEem_pLt0eVfQIQ
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 6/10/19, 8:59 AM
+Save-Time: 10/14/19, 1:31 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -45,86 +45,72 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 0"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x + 1"
-	    key-type Enter -times 1
-	    type-text "Spec == Init /\ [][Next]_x"
-	    key-type Enter -times 1
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 0\n\nNext == x' = x + 1\nSpec == Init /\ [][Next]_x\n=============================================================================\n"]
 	    key-type "M1+s"
     }
     
-	    get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
-	with [get-editor "Model_1" | get-section "What to check?"] {
-	    get-button "Deadlock" | uncheck
-	    with [get-section "Invariants"] {
+    get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+	with [get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK] {
+	    get-button $TLA-BUTTON-DEADLOCK | uncheck
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-INV] {
 	        click
-	        get-button "Add" | click
+	        get-button $TLA-BUTTON-ADD | click
 	    }
 	}
 	with [get-window -class WizardDialog] {
 	    get-text-viewer | type-text "x<10"
-	    get-button "Finish" | click
+	    get-button $TLA-BUTTON-FINISH | click
 	}
-	get-editor "Model_1" | get-link "Additional TLC Options" | click
+	get-editor $TLA-MODEL-ONE | get-link $TLA-MO-ED-OVERVIEW-LINK-TLC | click
     get-editbox -after [get-label "Number of worker threads:"] | set-text 2
-	get-editor "Model_1" | get-button "Runs TLC on the model." | click
+	get-editor $TLA-MODEL-ONE | get-button $TLA-BUTTON-RUN-TLC | click
 
 	wait-run      
     
-	get-view "TLC Errors" | get-section "Error-Trace" 
-	    | get-button "Toggle between expand and collapse all (Shift+Click to restore the default two-level expansion)" 
-	    | click
-	get-view "TLC Errors" | get-section "Error-Trace" | get-tree | get-property itemCount | equals 11 | verify-true
-	with [get-view "TLC Errors" | get-section "Error-Trace Exploration"] {
-	    get-button "Add" | click
-	}
+    with [get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ET] {
+    	get-button "Toggle between expand and collapse all (Shift+Click to restore the default two-level expansion)" 
+	    	| click
+	    get-tree | get-property itemCount | equals 11 | verify-true
+    }
+	get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ETE | get-button $TLA-BUTTON-ADD | click
+
 	with [get-window -class WizardDialog] {
 	    get-text-viewer | type-text "x \\in Nat"
-	    wait -ms 1000   
-	    get-button "Finish" | click
+	    get-button $TLA-BUTTON-FINISH | click
 	}
-	get-view "TLC Errors" | get-section "Error-Trace Exploration" | get-button "Explore" | click
+	get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ETE | get-button $TLA-BUTTON-EXPLORE | click
 	    
-	wait-run         
-//wait -ms 30000
-//get-view "TLC Errors" | get-section "Error-Trace" | get-tree | get-item -path " <Initial predicate>/x \\in Nat" 
+	wait-run
+
+//get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ET | get-tree | get-item -path " <Initial predicate>/x \\in Nat" 
   //  | get-property caption | equals "x \\in Nat" | verify-true
-	with [get-editor "Model_1"] {
-	    get-section "User Output" | click
+	with [get-editor $TLA-MODEL-ONE] {
+	    get-section $TLA-MO-ED-RESULTS-SECTION-UO | click
 	    with [get-tab-folder] {
-	        get-tab-item "Model Overview" | click
-	        get-tab-item "Model Checking Results" | click
-	        get-tab-item "Model Overview" | click
+	        get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+	        get-tab-item $TLA-MODEL-EDITOR-TAB-RESULTS | click
+	        get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
 	    }
-	    with [get-section "What to check?" | get-section Properties] {
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-PROP] {
 	        click
-	        get-button "Add" | click
+	        get-button $TLA-BUTTON-ADD | click
 	    }
 	}
 	with [get-window -class WizardDialog] {
 	    get-text-viewer | type-text "<>[](x - 10)"
-	    get-button "Finish" | click
+	    get-button $TLA-BUTTON-FINISH | click
 	}
-	get-editor "Model_1" | get-button "Runs TLC on the model." | click
+	get-editor $TLA-MODEL-ONE | get-button $TLA-BUTTON-RUN-TLC | click
 	
 	wait-run        
 
-	with [get-view "TLC Errors" | get-text-viewer] {
+	with [get-view $TLA-VIEW-TLC-ERRORS | get-text-viewer] {
 	    get-property enablement | equals true | verify-true
 	    get-property "getBlockSelectionBounds().isEmpty()" | equals false | verify-true
 	}
 	
-	get-view "TLC Errors" | get-section "Error-Trace" 
+	get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ET 
 	    | get-button "Toggle between expand and collapse all (Shift+Click to restore the default two-level expansion)" 
 	    | click
 } -finally {
diff --git a/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA_End_To_End_Multiple_Model_Run.test b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA_End_To_End_Multiple_Model_Run.test
index 810b9a472e12ee7f8eccd90038daf6c183cb5abe..39fc6b5299b8fa4d1eed6d4778dce34f5a9e0408 100644
--- a/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA_End_To_End_Multiple_Model_Run.test
+++ b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA_End_To_End_Multiple_Model_Run.test
@@ -6,7 +6,7 @@ Element-Version: 3.0
 External-Reference: 
 Id: _MHpE0ASNEemfpvVZm6oeFA
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 6/10/19, 8:58 AM
+Save-Time: 10/14/19, 1:05 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -24,52 +24,42 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 1"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 1"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 1\n\n=============================================================================\n"]
 	    key-type "M1+s"
     }
     wait -ms 1000
 
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
 	with [get-editor $TLA-MODEL-ONE] {
-	    get-section "What to check?" | get-button Deadlock | uncheck
-	    get-link "Additional TLC Options" | click
-        get-editbox -after [get-label "Number of worker threads:"] | set-text 2
-	    get-button "Runs TLC on the model." | click
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK | get-button $TLA-BUTTON-DEADLOCK | uncheck
+	    get-link $TLA-MO-ED-OVERVIEW-LINK-TLC | click
+        get-editbox -after [get-label "Number of worker threads:"] | set-text "2"
+	    get-button $TLA-BUTTON-RUN-TLC | click
 	}
     wait-run
     
 	// The error link should not be visible because there are no errors.
-	verify-error {get-editor $TLA-MODEL-ONE | get-section General | get-link "No errors" }
-	get-editor $TLA-MODEL-ONE | get-button "Runs TLC on the model." | click
+	verify-error {get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-RESULTS-SECTION-GENERAL | get-link "No errors" }
+	get-editor $TLA-MODEL-ONE | get-button $TLA-BUTTON-RUN-TLC | click
 	
 	wait-run
 	
 	// The error link should not be visible because there are no errors.
-	verify-error {get-editor $TLA-MODEL-ONE | get-section General | get-link "No errors" }
-	get-editor $TLA-MODEL-ONE | get-button "Runs TLC on the model." | click
+	verify-error {get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-RESULTS-SECTION-GENERAL | get-link "No errors" }
+	get-editor $TLA-MODEL-ONE | get-button $TLA-BUTTON-RUN-TLC | click
 	
 	wait-run
 	
 	// The error link should not be visible because there are no errors.
-	verify-error {get-editor $TLA-MODEL-ONE | get-section General | get-link "No errors" }
-	get-editor $TLA-MODEL-ONE | get-button "Runs TLC on the model." | click
+	verify-error {get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-RESULTS-SECTION-GENERAL | get-link "No errors" }
+	get-editor $TLA-MODEL-ONE | get-button $TLA-BUTTON-RUN-TLC | click
 	
 	wait-run
 	
 	// The error link should not be visible because there are no errors.
-	verify-error {get-editor $TLA-MODEL-ONE | get-section General | get-link "No errors" }
-	get-view "Spec Explorer" | get-tree | get-item -path $TLA-MODEL-ONE-TREE | get-property childCount 
+	verify-error {get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-RESULTS-SECTION-GENERAL | get-link "No errors" }
+	get-view $TLA-VIEW-SPEC-EXPLORER | get-tree | get-item -path $TLA-MODEL-ONE-TREE | get-property childCount 
 	    | equals 4 | verify-true
 } -finally {
 	DeleteSpecNew
diff --git a/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA_End_To_End_Test3.test b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA_End_To_End_Test3.test
index b66cf8144b16b1db72f4af0cdce8200a9038fc8c..52f731866ef418cf9f41fe18e97ec4d340468ad4 100644
--- a/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA_End_To_End_Test3.test
+++ b/org.lamport.tla.toolbox.product.uitest/EndtoEnd/TLA_End_To_End_Test3.test
@@ -6,7 +6,7 @@ Element-Version: 3.0
 External-Reference: 
 Id: _Jm-wcBB2EemUS_ZdBJsvQg
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 6/10/19, 8:58 AM
+Save-Time: 10/14/19, 1:17 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -32,76 +32,48 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 11"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x + 1"
-	    key-type Enter -times 1
-	    type-text "Spec == Init /\ [][Next]_x"
-	    key-type Enter -times 1
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 11\n\nNext == x' = x + 1\nSpec == Init /\ [][Next]_x\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
     
-    get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
-	with [get-editor "Model_1" | get-section "What to check?"] {
-	    get-button Deadlock | uncheck
-	    with [get-section Invariants] {
+    get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+	with [get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK] {
+	    get-button $TLA-BUTTON-DEADLOCK | uncheck
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-INV] {
 	        click
-	        get-button "Add" | click
+	        get-button $TLA-BUTTON-ADD | click
 	    }
 	}
 	with [get-window -class WizardDialog] {
 	    get-text-viewer | type-text "x<9"
-	    get-button "Finish" | click
+	    get-button $TLA-BUTTON-FINISH | click
 	}
 
-	with [get-editor "Model_1"] {
-	    get-section "Model description" | get-text-viewer | type-text "This is a text of end to end"
-	    get-section "What is the model?" | click
-	    get-link "Additional TLC Options" | click
-        get-editbox -after [get-label "Number of worker threads:"] | set-text 2
+	with [get-editor $TLA-MODEL-ONE] {
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-DESCRIPTION | get-text-viewer | type-text "This is a text of end to end"
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-MODEL | click
+	    get-link $TLA-MO-ED-OVERVIEW-LINK-TLC | click
+        get-editbox -after [get-label "Number of worker threads:"] | set-text "2"
         get-button "Recover from checkpoint" | check
-	}
-	get-editor "Model_1" | get-link "1 error detected" | get-property caption | equals "1 error detected" | verify-true
-	with [get-editor "Model_1"] {
-	    get-button "Recover from checkpoint" | uncheck
-	    get-button "Checks the model for errors but does not run TLC on it." | click
-	}
+        
+        get-link "1 error detected"
 
-	wait -ms 500
-	
-	get-editor "Model_1" | get-button "Recover from checkpoint" | get-property selected 
-	    | equals false | verify-true
-	with [get-editor "Model_1"] {
-	    with [get-tab-folder] {
-	        get-tab-item "Model Checking Results" | click
-	    }
-	    //get-button "Runs TLC on the model." | click
-	    get-editor "Model_1" | get-button "Checks the model for errors but does not run TLC on it." | click
-	}
+	    get-button "Recover from checkpoint" | uncheck
+	    get-button $TLA-BUTTON-MODEL-CHECK | click
 
-    wait -ms 500
+		wait -ms 500
 
-	with [get-editor "Model_1"] {
-	    get-tab-folder | get-tab-item "Model Overview" | click
-	    with [get-section "What to check?" | get-section Invariants] {
+		get-button "Recover from checkpoint" | get-property selected | equals false | verify-true
+		
+	    get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-INV] {
 	        get-table | select "x<9"
-	        get-button Remove | click
+	        get-button $TLA-BUTTON-REMOVE | click
 	    }
-		get-editor "Model_1" | get-button "Checks the model for errors but does not run TLC on it." | click
+	    
+		get-button $TLA-BUTTON-MODEL-CHECK | click
 	}
-	
-	wait -ms 500
-
-	get-editor "Model_1" | get-tab-folder | get-tab-item "Model Overview" | click
 } -finally {
 	DeleteSpecNew
 }
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA-Functional_Tree_Collapse.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA-Functional_Tree_Collapse.test
index d963c3b506e0750a2e9be0b99d2d6bf89e76634d..ef6e8954124bc8e64372f2164f324d39b0926002 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA-Functional_Tree_Collapse.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA-Functional_Tree_Collapse.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _7jq7EAOuEemtrbArmQOOJA
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 9:13 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 12:56 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -27,25 +27,19 @@ Entry-Name: .content
 OpenTLACreateNew
 
 try -command {
-with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-    key-type Down
-    type-text "EXTENDS Naturals"
-    key-type Enter
-    type-text "VARIABLE x"
-    key-type Enter -times 2
-    type-text "Init == x = 0"
-    key-type Enter -times 2
-    type-text "Next == x' = x + 1"
-    key-type "M1+s"
+	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 0\n\nNext == x' = x + 1\n=============================================================================\n"]
+	    key-type "M1+s"
+	}
+	
+	with [get-view $TLA-VIEW-SPEC-EXPLORER | get-tree] {
+		select $TLA-MODEL-NEW | get-menu -path "Close" | click
+		get-item -path $TLA-TREE-NAME | get-property childCount | equals 0 | verify-true
+		select $TLA-TREE-NAME | double-click
+		get-item -path $TLA-TREE-NAME | get-property childCount | equals 2 | verify-true
+	}
+} -finally {
+	DeleteSpecNew
 }
-get-view "Spec Explorer" | get-tree | select $TLA-MODEL-NEW | get-menu -path Close | click
-get-view "Spec Explorer" | get-tree | get-item -path $TLA-TREE-NAME | get-property childCount | equals 0 
-    | verify-true
-get-view "Spec Explorer" | get-tree | select $TLA-TREE-NAME | double-click
-get-view "Spec Explorer" | get-tree | get-item -path $TLA-TREE-NAME | get-property childCount | equals 2 
-    | verify-true
 
-} -finally
-//Delete Spec
-{DeleteSpecNew}
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Delete.Additional.Module.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Delete.Additional.Module.test
index d91d5b0ab4b8a9cd155c42ef7bb035fa0c30ed36..849bb42684c10b94e631603491cc7cf87a25dbc2 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Delete.Additional.Module.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Delete.Additional.Module.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _b7FWkFSpEemyiKKvW3h83Q
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 11:55 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:11 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -44,33 +44,19 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 2
-	    type-text "Init == x = 0"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x + 1"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 0\n\nNext == x' = x + 1\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
 
 	AddModule
 	
 	with [get-editor $TLA-ADDITIONAL-MODULE-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE w"
-	    key-type Enter -times 2
-	    type-text "Init == w = 8"
-	    key-type Enter -times 2
-	    type-text "Next == w' = (w + 3) % 11"
+		set-text [concat "-------------------------------- MODULE " $TLA-ADDITIONAL-MODULE-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE w\nInit == w = 8\n\nNext == w' = (w + 3) % 11\n=============================================================================\n"]
 	}
 	
 	let [val treePath [concat $TLA-TREE-NAME "/modules/" $TLA-ADDITIONAL-MODULE-NAME]] {
-		get-view "Spec Explorer" | get-tree | get-item $treePath | select-item | get-menu -path "Delete" | click
-		get-window "Save Resource" | get-button "Cancel" | click
+		get-view $TLA-VIEW-SPEC-EXPLORER | get-tree | get-item $treePath | select-item | get-menu -path "Delete" | click
+		get-window "Save Resource" | get-button $TLA-BUTTON-CANCEL | click
 		
 		if [editor-exists $TLA-ADDITIONAL-MODULE-NAME] {
 		} -else {
@@ -81,7 +67,7 @@ try -command {
 		    key-type "M1+s"
 		}
 		
-		with [get-view "Spec Explorer"] {
+		with [get-view $TLA-VIEW-SPEC-EXPLORER] {
 			get-tree | get-item $treePath | select-item | get-menu -path "Delete" | click
 		}
 		
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_ECE_Placement.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.ECE.Placement.test
similarity index 60%
rename from org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_ECE_Placement.test
rename to org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.ECE.Placement.test
index 39bfe0ec8ce5ec48ad7d43a2a7fbdc7a36997e8f..6c0efd2bebee9bbd1df194679914452caa42a399 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_ECE_Placement.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.ECE.Placement.test
@@ -1,12 +1,12 @@
 --- RCPTT testcase ---
 Format-Version: 1.0
-Element-Name: TLA_Functional_ECE_Placement
+Element-Name: TLA.Functional.ECE.Placement
 Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _JObaIIvTEemXYtOZX2zpng
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 6/14/19, 10:55 AM
+Save-Time: 10/14/19, 1:12 PM
 Testcase-Type: ecl
 
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac
@@ -18,29 +18,26 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 1"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 1"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 1\n\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
 
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-button OK | click
-	with [get-editor "Model_1"] {
-	    get-tab-item "Model Checking Results" | click
-	    with [get-section "Evaluate Constant Expression" | get-text-viewer -after [get-label "Expression:"]] {
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+	with [get-editor $TLA-MODEL-ONE] {
+	    get-button $TLA-BUTTON-RUN-TLC | click
+
+		wait-run
+
+	    get-tab-item $TLA-MODEL-EDITOR-TAB-RESULTS | click
+	    with [get-section $TLA-MO-ED-RESULTS-SECTION-ECE | get-text-viewer -after [get-label "Expression:"]] {
     		type-text "CHOOSE w in {3, 5, 7} : w*w*w = 125"  // yes, "in" is invalid but escaping backspaces in the comparison below is quirky
 	    }
 	}
 	
 	get-preferences-menu | click
 	with [get-window Preferences ] {
-		get-tree | select "TLA+ Preferences/TLC Model Checker" 
+		get-tree | select "TLA+ Preferences/Model Editor" 
 	    get-checkbox -text "Show Evaluate Constant Expression in its own tab" | check
 	    
 	    get-button "Apply and Close" | click
@@ -50,10 +47,10 @@ try -command {
 							-pluginId "org.lamport.tla.toolbox.tool.tlc.ui"
 							-className "org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results.EvaluateConstantExpressionPage"
 							-methodName "getTabTitle"]] {
-		with [get-editor "Model_1"] {
-			verify-error { get-section "Evaluate Constant Expression" }
+		with [get-editor $TLA-MODEL-ONE] {
+			verify-error { get-section $TLA-MO-ED-RESULTS-SECTION-ECE }
 			get-tab-item $tabTitle | click
-		    with [get-section "Evaluate Constant Expression"] {
+		    with [get-section $TLA-MO-ED-RESULTS-SECTION-ECE] {
 		    	get-text-viewer -after [get-label "Expression:"] | get-text |
 		    		equals "CHOOSE w in {3, 5, 7} : w*w*w = 125" | verify-true
 		    }
@@ -61,28 +58,28 @@ try -command {
 		
 		get-preferences-menu | click
 		with [get-window Preferences ] {
-			get-tree | select "TLA+ Preferences/TLC Model Checker" 
+			get-tree | select "TLA+ Preferences/Model Editor" 
 		    get-checkbox -text "Show Evaluate Constant Expression in its own tab" | uncheck
 		    
 		    get-button "Apply and Close" | click
 		}
 		
-		with [get-editor "Model_1"] {
+		with [get-editor $TLA-MODEL-ONE] {
 			verify-error { get-tab-item $tabTitle }
-		    get-tab-item "Model Checking Results" | click
-		    with [get-section "Evaluate Constant Expression"] {
+		    get-tab-item $TLA-MODEL-EDITOR-TAB-RESULTS | click
+		    with [get-section $TLA-MO-ED-RESULTS-SECTION-ECE] {
 		    	get-text-viewer -after [get-label "Expression:"] | get-text |
 		    		equals "CHOOSE w in {3, 5, 7} : w*w*w = 125" | verify-true
 		    	get-button "No Behavior Spec" | click
 		    	get-button "No Behavior Spec" | get-object | invoke getSelection | verify-true
 		    }
-		    get-tab-item "Model Overview" | click
-		    with [get-section "What is the behavior spec?" | get-combo] {
+		    get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+		    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-SPEC | get-combo] {
 		    	get-text | equals "No behavior spec" | verify-true
 		    	select "Temporal formula"
 		    }
-		    get-tab-item "Model Checking Results" | click
-		    get-section "Evaluate Constant Expression" | get-button | get-object | invoke getSelection | verify-false
+		    get-tab-item $TLA-MODEL-EDITOR-TAB-RESULTS | click
+		    get-section $TLA-MO-ED-RESULTS-SECTION-ECE | get-button | get-object | invoke getSelection | verify-false
 		    key-type "M1+s"
 		}	
 	}
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Error.Trace.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Error.Trace.test
new file mode 100644
index 0000000000000000000000000000000000000000..53856a3748e7a819799b013e2359c4bc19aca934
--- /dev/null
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Error.Trace.test
@@ -0,0 +1,126 @@
+--- RCPTT testcase ---
+Format-Version: 1.0
+Element-Name: TLA.Functional.Error.Trace
+Element-Type: testcase
+Element-Version: 3.0
+External-Reference: 
+Id: _BbLbgO0TEemu8qbF8JrHog
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 11/26/19, 1:03 PM
+Testcase-Type: ecl
+
+------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac
+Content-Type: text/ecl
+Entry-Name: .content
+
+//Create Spec
+OpenTLACreateNew
+
+try -command {
+	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
+		set-text [concat "-------------------------- MODULE " $TLA-SPEC-NAME " -----------------------------\nEXTENDS Integers\nCONSTANT Proc\nCONSTANT defaultInitValue\nVARIABLES b, c, k, pc, temp\nvars == << b, c, k, pc, temp >>\nProcSet == (Proc)\nInit == /\ b = [i \in Proc |-> TRUE]\n        /\ c = [i \in Proc |-> TRUE]\n        /\ k \in Proc\n        /\ temp = [self \in Proc |-> defaultInitValue]\n        /\ pc = [self \in ProcSet |-> CASE self \in Proc -> \"Li0\"]\nLi0(self) == /\ pc[self] = \"Li0\"\n             /\ b' = [b EXCEPT ![self] = FALSE]\n             /\ pc' = [pc EXCEPT ![self] = \"Li1\"]\n             /\ UNCHANGED << c, k, temp >>\nLi1(self) == /\ pc[self] = \"Li1\"\n             /\ IF k # self\n                   THEN /\ pc' = [pc EXCEPT ![self] = \"Li2\"]\n                   ELSE /\ pc' = [pc EXCEPT ![self] = \"Li4a\"]\n             /\ UNCHANGED << b, c, k, temp >>\nLi2(self) == /\ pc[self] = \"Li2\"\n             /\ c' = [c EXCEPT ![self] = TRUE]\n             /\ pc' = [pc EXCEPT ![self] = \"Li3a\"]\n             /\ UNCHANGED << b, k, temp >>\nLi3a(self) == /\ pc[self] = \"Li3a\"\n              /\ temp' = [temp EXCEPT ![self] = k]\n              /\ pc' = [pc EXCEPT ![self] = \"Li3b\"]\n              /\ UNCHANGED << b, c, k >>\nLi3b(self) == /\ pc[self] = \"Li3b\"\n              /\ IF b[temp[self]]\n                    THEN /\ pc' = [pc EXCEPT ![self] = \"Li3c\"]\n                    ELSE /\ pc' = [pc EXCEPT ![self] = \"Li3d\"]\n              /\ UNCHANGED << b, c, k, temp >>\nLi3c(self) == /\ pc[self] = \"Li3c\"\n              /\ k' = self\n              /\ pc' = [pc EXCEPT ![self] = \"Li3d\"]\n              /\ UNCHANGED << b, c, temp >>\nLi3d(self) == /\ pc[self] = \"Li3d\"\n              /\ pc' = [pc EXCEPT ![self] = \"Li1\"]\n              /\ UNCHANGED << b, c, k, temp >>\nLi4a(self) == /\ pc[self] = \"Li4a\"\n              /\ c' = [c EXCEPT ![self] = FALSE]\n              /\ temp' = [temp EXCEPT ![self] = Proc \ {self}]\n              /\ pc' = [pc EXCEPT ![self] = \"Li4b\"]\n              /\ UNCHANGED << b, k >>\nLi4b(self) == /\ pc[self] = \"Li4b\"\n              /\ IF temp[self] # {}\n                    THEN /\ \E j \in temp[self]:\n                              /\ temp' = [temp EXCEPT \n                                            ![self] = temp[self] \ {j}]\n                              /\ IF ~c[j]\n                                    THEN /\ pc' = [pc EXCEPT \n                                                     ![self] = \"Li1\"]\n                                    ELSE /\ pc' = [pc EXCEPT \n                                                     ![self] = \"Li4b\"]\n                    ELSE /\ pc' = [pc EXCEPT ![self] = \"cs\"]\n                         /\ UNCHANGED temp\n              /\ UNCHANGED << b, c, k >>\ncs(self) == /\ pc[self] = \"cs\"\n            /\ TRUE\n            /\ pc' = [pc EXCEPT ![self] = \"Li5\"]\n            /\ UNCHANGED << b, c, k, temp >>\nLi5(self) == /\ pc[self] = \"Li5\"\n             /\ c' = [c EXCEPT ![self] = TRUE]\n             /\ pc' = [pc EXCEPT ![self] = \"Li6\"]\n             /\ UNCHANGED << b, k >>\nLi6(self) == /\ pc[self] = \"Li6\"\n             /\ b' = [b EXCEPT ![self] = TRUE]\n             /\ pc' = [pc EXCEPT ![self] = \"ncs\"]\n             /\ UNCHANGED << c, k, temp >>\nncs(self) == /\ pc[self] = \"ncs\"\n             /\ TRUE\n             /\ pc' = [pc EXCEPT ![self] = \"Li0\"]\n             /\ UNCHANGED << b, c, k, temp >>\nP(self) == Li0(self) \/ Li1(self) \/ Li2(self) \/ Li3a(self) \/ Li3b(self)\n              \/ Li3c(self) \/ Li3d(self) \/ Li4a(self) \/ Li4b(self)\n              \/ cs(self) \/ Li5(self) \/ Li6(self) \/ ncs(self)\nNext == (\E self \in Proc: P(self))\nMutualExclusion == \A i, j \in Proc : \n                     (i # j) => ~ /\ pc[i] = \"cs\"\n                                  /\ pc[j] = \"cs\"\nLSpec == Init /\ [][Next]_vars \n           /\ \A self \in Proc: WF_vars((pc[self] # \"ncs\") /\ P(self))\nDeadlockFreedom == \n    \A i \in Proc : \n      (pc[i] \\notin {\"Li5\", \"Li6\", \"ncs\"}) ~> (\E j \in Proc : pc[j] = \"cs\")\n\n===================================================================\n"]
+		key-type "M1+s"
+	}
+
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+
+	with [get-editor $TLA-MODEL-ONE] {
+		with [get-section $TLA-MO-ED-OVERVIEW-SECTION-SPEC] {
+			get-combo | select "Temporal formula"
+			get-text-viewer | set-text "LSpec"
+		}
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-MODEL] {
+	        get-table | select "Proc <- "
+	        get-button $TLA-BUTTON-EDIT | click
+        	with [get-window -class WizardDialog] {
+			    get-text-viewer | type-text "{ p1, p2, p3 }"
+			    get-button "Set of model values" | click
+			    get-button $TLA-BUTTON-FINISH | click
+			}
+	    }
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK] {
+	        get-button $TLA-BUTTON-DEADLOCK | check
+	        with [get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-INV] {
+	        	click
+	        	get-button $TLA-BUTTON-ADD | click
+	        	with [get-window -class WizardDialog] {
+				    get-text-viewer | type-text "MutualExclusion"
+				    get-button $TLA-BUTTON-FINISH | click
+				}
+	        }
+	        with [get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-PROP] {
+	        	click
+	        	get-button $TLA-BUTTON-ADD | click
+	        	with [get-window -class WizardDialog] {
+				    get-text-viewer | type-text "DeadlockFreedom"
+				    get-button $TLA-BUTTON-FINISH | click
+				}
+	        }
+	    }
+	}	
+
+	get-menu -path "TLC Model Checker/Run model" | click
+	
+	wait-run
+
+	// I tried all manners of niceness to get the tree items by using basic ECL all to no avail, so now
+	//		i'm doing this hacky invoking of Java methods.
+	// This specific item is testing for regressions like the one behind Issue 372.
+	with [get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ET | get-tree] {
+		let [val stateOneP1Val [get-object | invoke getItem 1 | invoke getItem 3 | invoke getItem 0 | invoke getText 1 | str]] {
+			let [val stateTwoP1Val [get-object | invoke getItem 2 | invoke getItem 3 | invoke getItem 0 | invoke getText 1 | str]] {
+				concat $stateOneP1Val | equals $stateTwoP1Val | verify-false
+			}
+		}
+	}
+	
+	listen errorLog {
+		try {
+			get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ET | get-button "Reflect filtering"
+			log -message "Found value reflect filtering button when we shouldn't." -severity error -plugin "org.lamport.tla.toolbox.product.uitests"
+		} -catch { }
+	} | assert-empty
+	
+	// The following is testing for regressions like the one behind Issue 386, which is, sadly, a regression due to 372.
+	get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ET
+			| get-button "Click to select variables and expressions to omit from the trace display; ALT-click on an individual item below to omit it immediately."
+			| click
+	with [ get-window "Error Trace Filter" ] {
+		get-table | get-item -path " b" | check
+		get-button "OK" | click
+	}
+	with [get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ET] {
+		with [get-tree] {
+			get-object | invoke getItem 0 | invoke getItem 0 | invoke getText 0 | str | equals " c" | verify-true
+			get-object | invoke getItem 1 | invoke getItem 0 | invoke getText 0 | str | equals " b" | verify-false
+		}
+
+		// make sure the reflect filtering button is visible
+		get-button "Reflect filtering"		
+	}
+	
+	
+	// Testing the 'reflect filtering' checkbox, additionally in the case where not all state frames are shown due to
+	//		filtering
+	get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ET
+			| get-button "Click to display all variables and expressions."
+			| click
+	get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ET
+			| get-button "Click to select variables and expressions to omit from the trace display; ALT-click on an individual item below to omit it immediately."
+			| click
+	with [ get-window "Error Trace Filter" ] {
+		get-combo | select "Show only changed variables in changed frames"
+		get-button "OK" | click
+	}
+	with [get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ET] {
+		get-tree | get-cell 0 0 | click
+		get-text-viewer | get-property text | equals "/\\  pc = (p1 :> \"Li1\" @@ p2 :> \"Li0\" @@ p3 :> \"Li0\")" | verify-true
+
+		get-button "Reflect filtering" | click	
+		get-text-viewer | get-property text | equals "/\\  b = (p1 :> FALSE @@ p2 :> TRUE @@ p3 :> TRUE)\n/\\  c = (p1 :> TRUE @@ p2 :> TRUE @@ p3 :> TRUE)\n/\\  k = p1\n/\\  pc = (p1 :> \"Li1\" @@ p2 :> \"Li0\" @@ p3 :> \"Li0\")\n/\\  temp = (p1 :> defaultInitValue @@ p2 :> defaultInitValue @@ p3 :> defaultInitValue)" | verify-true
+	}
+} -finally {
+	DeleteSpecNew
+}
+------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.File.Property.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.File.Property.test
index 71833b468e53905aa39d5c11fc1cc5553ad3b053..2a249a611aa64f017c9dc5c1416ded2838c54bcd 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.File.Property.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.File.Property.test
@@ -6,7 +6,7 @@ Element-Version: 3.0
 External-Reference: 
 Id: _cCrygP25EeiCTvrXzYZPCg
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 3/29/19, 3:57 PM
+Save-Time: 10/14/19, 12:02 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -26,18 +26,25 @@ Entry-Name: .content
 OpenTLACreateNew
 
 try -command {
-	get-view "Spec Explorer" | get-tree | get-item -path $TLA-TREE-NAME | get-property caption 
-	    | equals $TLA-TREE-NAME | verify-true
-	get-view "Spec Explorer" | get-tree | select [concat $TLA-TREE-NAME "/modules"] | get-menu -path "New Specification" | click
-	get-window -class WizardDialog | get-label "New TLA+ Specification" | get-property caption 
-	    | equals "New TLA+ Specification" | verify-true
-	get-window -class WizardDialog | get-button Cancel | click
-	get-view "Spec Explorer" | get-tree | select [concat $TLA-TREE-NAME "/modules/new"] | get-menu -path Properties
-		| get-property enablement | equals false | verify-true
-	get-view "Spec Explorer" | get-tree | select $TLA-TREE-NAME | get-menu -path Properties | click
+	with [get-view $TLA-VIEW-SPEC-EXPLORER | get-tree] {
+		get-item -path $TLA-TREE-NAME
+		select [concat $TLA-TREE-NAME "/modules"] | get-menu -path "New Specification" | click
+	}
+
+	with [get-window -class WizardDialog] {
+		get-label "New TLA+ Specification"
+		get-button $TLA-BUTTON-CANCEL | click
+	}
+
+	with [get-view $TLA-VIEW-SPEC-EXPLORER | get-tree] {
+		select [concat $TLA-TREE-NAME "/modules/new"] | get-menu -path "Properties" | get-property enablement
+			| equals false | verify-true
+		select $TLA-TREE-NAME | get-menu -path "Properties" | click
+	}
+
 	with [get-window [concat "Properties for " $TLA-SPEC-NAME]] {
 		get-editbox -after [get-label "Specification root module"] | get-text | length | not-eq 0 | verify-true
-		get-button "Cancel" | click
+		get-button $TLA-BUTTON-CANCEL | click
 	}
 } -finally {
 	DeleteSpecNew
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Help.Menu.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Help.Menu.test
index afe38721b0fb227f7d52771855a212456628f0b6..15d8f259b5a0daa1ce2e89344dda0277a4a1ea99 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Help.Menu.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Help.Menu.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _y2T94AL0EemtrbArmQOOJA
-Runtime-Version: 2.4.2.201905122359
-Save-Time: 6/10/19, 3:33 PM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 12:05 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -24,10 +24,10 @@ OpenTLACreateNew
 let [val checkView [get-by-os -macosx "yes" -default "no"]] {
 	try -command {
 		get-menu -path "Help/Table of Contents" | click
-		get-view Help | get-link Contents | get-property caption | equals Contents | verify-true
+		get-view "Help" | get-link "Contents"
 		
 		get-menu -path "Help/Dynamic Help" | click
-		get-view Help | get-section "About Help" | get-canvas | get-property text 
+		get-view "Help" | get-section "About Help" | get-canvas | get-property text 
 		    | equals "Click on any workbench part to show related help topics.\r\n" | verify-true
 
 // Since commit b3d9edd9760ea9dbcfd4f4f774a0877c4aecdddb these two PDFs are loaded externally.  If one knows how to test this, please re-add.
@@ -71,7 +71,7 @@ let [val checkView [get-by-os -macosx "yes" -default "no"]] {
 			get-editor "TLA+ Cheat Sheet" | close
 		}
 
-		get-view Help | click
+		get-view "Help" | click
 		with [get-editor $TLA-SPEC-NAME] {
 		    click
 		    click
@@ -79,7 +79,7 @@ let [val checkView [get-by-os -macosx "yes" -default "no"]] {
 		
 		get-editor $TLA-SPEC-NAME | click
 		
-		get-view Help | close
+		get-view "Help" | close
 	}
 	-finally {
 		DeleteSpecNew
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.New.Model.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.New.Model.test
index da953c9cb02f8bb411c246a9675ebc144ec2d816..a8676061892d0018f5084e9fb668203e81f98789 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.New.Model.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.New.Model.test
@@ -6,7 +6,7 @@ Element-Version: 3.0
 External-Reference: 
 Id: _LxG3gAJFEemDc-4PKyNT9w
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 6/10/19, 9:05 AM
+Save-Time: 10/14/19, 12:55 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -33,47 +33,36 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 2
-	    type-text "Init == x = 0"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x + 1"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 0\n\nNext == x' = x + 1\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
-	wait -ms 500
-	get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-button "Runs TLC on the model." | click
+
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+	get-editor $TLA-MODEL-ONE | get-button $TLA-BUTTON-RUN-TLC | click
 	wait -ms 1000
 	
-	get-editor "Model_1" | get-button "Stops the current TLC model checker run." | click
-	
+	get-editor $TLA-MODEL-ONE | get-button $TLA-BUTTON-CANCEL-TLC | click
 	
 	wait-run
 	
-	with [get-editor "Model_1"] {
-	    get-tab-folder | get-tab-item "Model Overview" | click
-		get-section "What is the model?" | click
-		get-link "Additional Spec Options" | click
-	    get-section "Additional Definitions" | click
-	    get-section "State Constraint" | click
-	    get-section "Model Values" | click
-	    get-section "Definition Override" | click
-	    get-section "Action Constraint" | click
-	    get-button "Checks the model for errors but does not run TLC on it." | click
-	    get-tab-folder | get-tab-item "Model Overview" | click
-	    get-section "What is the model?" | click
-	    get-section "How to run?" | click
+	with [get-editor $TLA-MODEL-ONE] {
+	    get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+		get-section $TLA-MO-ED-OVERVIEW-SECTION-MODEL | click
+		get-link $TLA-MO-ED-OVERVIEW-LINK-SPEC | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-AD | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-SC | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-MV | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-DO | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-AC | click
+	    get-button $TLA-BUTTON-MODEL-CHECK | click
+	    get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-MODEL | click
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-RUN | click
 	}
-	with [get-editor "Model_1" | get-section "What is the behavior spec?"] {
-	    get-text-viewer | get-property text | equals Init | verify-true
-	    get-text-viewer -after [get-label "Next:"] | get-property text | equals Next | verify-true
+	with [get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-OVERVIEW-SECTION-SPEC] {
+	    get-text-viewer | get-property text | equals "Init" | verify-true
+	    get-text-viewer -after [get-label "Next:"] | get-property text | equals "Next" | verify-true
 	}
 } -finally {
 	DeleteSpecNew
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.PCal.Checksums.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.PCal.Checksums.test
new file mode 100644
index 0000000000000000000000000000000000000000..3962a7f69b0640a7a9a5a98101c8d3555d99fed6
--- /dev/null
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.PCal.Checksums.test
@@ -0,0 +1,52 @@
+--- RCPTT testcase ---
+Format-Version: 1.0
+Element-Name: TLA.Functional.PCal.Checksums
+Element-Type: testcase
+Element-Version: 3.0
+External-Reference: 
+Id: _wH2aMNWzEemOp9qASlV00A
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/13/19, 7:31 PM
+Testcase-Type: ecl
+
+------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac
+Content-Type: text/ecl
+Entry-Name: .content
+
+//Create Spec
+OpenTLACreateNew
+
+try -command {
+	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
+		set-text [concat "-------------------------- MODULE " $TLA-SPEC-NAME " -----------------------------\nEXTENDS Naturals, Sequences\nAttacks(queens,i,j) ==\n  \/ queens[i] = queens[j]\n  \/ queens[i] - queens[j] = i - j\n  \/ queens[j] - queens[i] = i - j\nIsSolution(queens) ==\n  \A i \in 1 .. Len(queens)-1 : \A j \in i+1 .. Len(queens) : \n       ~ Attacks(queens,i,j) \nSolutions == { queens \in [1..3 -> 1..3] : IsSolution(queens) }\n(* --algorithm Queens\n     variables\n       todo = { << >> };\n       sols = {};\n\n     begin\nnxtQ:  while todo # {}\n       do\n         with queens \in todo,\n              nxtQ = Len(queens) + 1,\n              cols = { c \in 1..3 : ~ \E i \in 1 .. Len(queens) :\n                                      Attacks( Append(queens, c), i, nxtQ ) },\n              exts = { Append(queens,c) : c \in cols }\n         do\n           if (nxtQ = 3)\n           then todo := todo \ {queens}; sols := sols \union exts;\n           else todo := (todo \ {queens}) \union exts;\n           end if;\n         end with;\n       end while;\n     end algorithm\n*)\n\n===================================================================\n"]
+		key-type "M1+s"
+	    key-type "M1+t"
+	    set-text-offset 7 13
+	    type-text "new"
+	    key-type "M1+s"
+	}
+
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+	
+	get-menu -path "TLC Model Checker/Run model" | click
+	with [get-window "PlusCal out of sync"] {
+		get-checkbox | click
+		get-button -index 2 | click  // don't seem to able to get by title, likely due to the ampersand in the text
+	}
+	get-view "History" | close
+
+	get-menu -path "TLC Model Checker/Run model" | click
+	
+	listen errorLog {
+		try {
+			get-window "PlusCal out of sync"
+			log -message "Found checksum warning dialog that shouldn't be shown." -severity error -plugin "org.lamport.tla.toolbox.product.uitests"
+		} -catch { }
+	} | assert-empty
+
+	wait -ms 1200	
+} -finally {
+	DeleteSpecNew
+}
+------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Parse.Pref.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Parse.Pref.test
index e6bd7898cff8c642c9c80ed7e6998a879bc9e723..514dd308078217619f1b20c6b67d20463fec187b 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Parse.Pref.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Parse.Pref.test
@@ -5,24 +5,25 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _eblOcP23EeiCTvrXzYZPCg
-Runtime-Version: 2.3.0.201806262310
-Save-Time: 1/9/19 2:14 PM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 2:11 PM
 Testcase-Type: ecl
 
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac
 Content-Type: text/ecl
 Entry-Name: .content
 
-//New Spec
 OpenTLACreateNew
-try -command {
-get-menu -path "File/Parse Module" | click
-get-preferences-menu | click
-get-window Preferences | get-label "Automatic Update" | get-property caption | equals "Automatic Update" | verify-true
-get-window Preferences | get-button Cancel | click
 
+try -command {
+	get-menu -path "File/Parse Module" | click
+	get-preferences-menu | click
+	with [get-window "Preferences"] {
+		get-tree | select "Automatic Update"
+		get-button $TLA-BUTTON-CANCEL | click
+	}
+} -finally {
+	DeleteSpecNew
+}
 
-} -finally
-//Delete Spec
-{DeleteSpecNew}
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Start.From.Error.Trace.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Start.From.Error.Trace.test
new file mode 100644
index 0000000000000000000000000000000000000000..6dd13424b2722dfe451a0606c70150cf76e0932b
--- /dev/null
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Start.From.Error.Trace.test
@@ -0,0 +1,96 @@
+--- RCPTT testcase ---
+Format-Version: 1.0
+Element-Name: TLA.Functional.Start.From.Error.Trace
+Element-Type: testcase
+Element-Version: 3.0
+External-Reference: https://github.com/tlaplus/tlaplus/issues/275
+Id: _r_EqIP84EemUPYAc4mFamA
+Runtime-Version: 2.4.3.201909171500
+Save-Time: 1/6/20, 3:02 PM
+Testcase-Type: ecl
+
+------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
+Content-Type: text/plain
+Entry-Name: .description
+
+A test for Issue 275
+------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa--
+------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac
+Content-Type: text/ecl
+Entry-Name: .content
+
+//Create Spec
+OpenTLACreateNew
+
+try -command {
+	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
+		set-text [concat "-------------------------- MODULE " $TLA-SPEC-NAME " -----------------------------\nEXTENDS Integers\nCONSTANT Proc\nCONSTANT defaultInitValue\nVARIABLES b, c, k, pc, temp\nvars == << b, c, k, pc, temp >>\nProcSet == (Proc)\nInit == /\ b = [i \in Proc |-> TRUE]\n        /\ c = [i \in Proc |-> TRUE]\n        /\ k \in Proc\n        /\ temp = [self \in Proc |-> defaultInitValue]\n        /\ pc = [self \in ProcSet |-> CASE self \in Proc -> \"Li0\"]\nLi0(self) == /\ pc[self] = \"Li0\"\n             /\ b' = [b EXCEPT ![self] = FALSE]\n             /\ pc' = [pc EXCEPT ![self] = \"Li1\"]\n             /\ UNCHANGED << c, k, temp >>\nLi1(self) == /\ pc[self] = \"Li1\"\n             /\ IF k # self\n                   THEN /\ pc' = [pc EXCEPT ![self] = \"Li2\"]\n                   ELSE /\ pc' = [pc EXCEPT ![self] = \"Li4a\"]\n             /\ UNCHANGED << b, c, k, temp >>\nLi2(self) == /\ pc[self] = \"Li2\"\n             /\ c' = [c EXCEPT ![self] = TRUE]\n             /\ pc' = [pc EXCEPT ![self] = \"Li3a\"]\n             /\ UNCHANGED << b, k, temp >>\nLi3a(self) == /\ pc[self] = \"Li3a\"\n              /\ temp' = [temp EXCEPT ![self] = k]\n              /\ pc' = [pc EXCEPT ![self] = \"Li3b\"]\n              /\ UNCHANGED << b, c, k >>\nLi3b(self) == /\ pc[self] = \"Li3b\"\n              /\ IF b[temp[self]]\n                    THEN /\ pc' = [pc EXCEPT ![self] = \"Li3c\"]\n                    ELSE /\ pc' = [pc EXCEPT ![self] = \"Li3d\"]\n              /\ UNCHANGED << b, c, k, temp >>\nLi3c(self) == /\ pc[self] = \"Li3c\"\n              /\ k' = self\n              /\ pc' = [pc EXCEPT ![self] = \"Li3d\"]\n              /\ UNCHANGED << b, c, temp >>\nLi3d(self) == /\ pc[self] = \"Li3d\"\n              /\ pc' = [pc EXCEPT ![self] = \"Li1\"]\n              /\ UNCHANGED << b, c, k, temp >>\nLi4a(self) == /\ pc[self] = \"Li4a\"\n              /\ c' = [c EXCEPT ![self] = FALSE]\n              /\ temp' = [temp EXCEPT ![self] = Proc \ {self}]\n              /\ pc' = [pc EXCEPT ![self] = \"Li4b\"]\n              /\ UNCHANGED << b, k >>\nLi4b(self) == /\ pc[self] = \"Li4b\"\n              /\ IF temp[self] # {}\n                    THEN /\ \E j \in temp[self]:\n                              /\ temp' = [temp EXCEPT \n                                            ![self] = temp[self] \ {j}]\n                              /\ IF ~c[j]\n                                    THEN /\ pc' = [pc EXCEPT \n                                                     ![self] = \"Li1\"]\n                                    ELSE /\ pc' = [pc EXCEPT \n                                                     ![self] = \"Li4b\"]\n                    ELSE /\ pc' = [pc EXCEPT ![self] = \"cs\"]\n                         /\ UNCHANGED temp\n              /\ UNCHANGED << b, c, k >>\ncs(self) == /\ pc[self] = \"cs\"\n            /\ TRUE\n            /\ pc' = [pc EXCEPT ![self] = \"Li5\"]\n            /\ UNCHANGED << b, c, k, temp >>\nLi5(self) == /\ pc[self] = \"Li5\"\n             /\ c' = [c EXCEPT ![self] = TRUE]\n             /\ pc' = [pc EXCEPT ![self] = \"Li6\"]\n             /\ UNCHANGED << b, k >>\nLi6(self) == /\ pc[self] = \"Li6\"\n             /\ b' = [b EXCEPT ![self] = TRUE]\n             /\ pc' = [pc EXCEPT ![self] = \"ncs\"]\n             /\ UNCHANGED << c, k, temp >>\nncs(self) == /\ pc[self] = \"ncs\"\n             /\ TRUE\n             /\ pc' = [pc EXCEPT ![self] = \"Li0\"]\n             /\ UNCHANGED << b, c, k, temp >>\nP(self) == Li0(self) \/ Li1(self) \/ Li2(self) \/ Li3a(self) \/ Li3b(self)\n              \/ Li3c(self) \/ Li3d(self) \/ Li4a(self) \/ Li4b(self)\n              \/ cs(self) \/ Li5(self) \/ Li6(self) \/ ncs(self)\nNext == (\E self \in Proc: P(self))\nMutualExclusion == \A i, j \in Proc : \n                     (i # j) => ~ /\ pc[i] = \"cs\"\n                                  /\ pc[j] = \"cs\"\nLSpec == Init /\ [][Next]_vars \n           /\ \A self \in Proc: WF_vars((pc[self] # \"ncs\") /\ P(self))\nDeadlockFreedom == \n    \A i \in Proc : \n      (pc[i] \\notin {\"Li5\", \"Li6\", \"ncs\"}) ~> (\E j \in Proc : pc[j] = \"cs\")\n\n===================================================================\n"]
+		key-type "M1+s"
+	}
+
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+
+	with [get-editor $TLA-MODEL-ONE] {
+		with [get-section $TLA-MO-ED-OVERVIEW-SECTION-SPEC] {
+			get-combo | select "Temporal formula"
+			get-text-viewer | set-text "LSpec"
+		}
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-MODEL] {
+	        get-table | select "Proc <- "
+	        get-button $TLA-BUTTON-EDIT | click
+        	with [get-window -class WizardDialog] {
+			    get-text-viewer | type-text "{ p1, p2, p3 }"
+			    get-button "Set of model values" | click
+			    get-button $TLA-BUTTON-FINISH | click
+			}
+	    }
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK] {
+	        get-button $TLA-BUTTON-DEADLOCK | check
+	        with [get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-INV] {
+	        	click
+	        	get-button $TLA-BUTTON-ADD | click
+	        	with [get-window -class WizardDialog] {
+				    get-text-viewer | type-text "MutualExclusion"
+				    get-button $TLA-BUTTON-FINISH | click
+				}
+	        }
+	        with [get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-PROP] {
+	        	click
+	        	get-button $TLA-BUTTON-ADD | click
+	        	with [get-window -class WizardDialog] {
+				    get-text-viewer | type-text "DeadlockFreedom"
+				    get-button $TLA-BUTTON-FINISH | click
+				}
+	        }
+	    }
+	}	
+
+	get-menu -path "TLC Model Checker/Run model" | click
+	
+	wait-run
+	
+	with [get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ET | get-tree] {
+	    select " <Li0 line 13, col 14 to line 16, col 42 of module new>" | mouse down Right
+	    get-menu -path "Run model from this point" | click
+	}
+	
+	get-window "Model Reconfigured" | get-button OK | click
+	
+	with [get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-OVERVIEW-SECTION-SPEC ] {
+		get-combo | get-text | equals "Initial predicate and next-state relation" | verify-true
+		get-text-viewer -after [get-label "Next:"] | get-text | equals "LSpec" | verify-true
+		// In no possible contortion could i get the equals operator to play nice with the backslashes we were
+		//		getting back in the get-text below; so i replaced them in the text.
+		global [val scrubbed ""]
+		get-text-viewer -after [get-label "Init:"] | get-text | split -sep "/\\\\" -trimResults | foreach [val item] {
+			global [val scrubbed [concat $scrubbed "CONJ" $item]] -override
+		}
+		concat $scrubbed | equals "CONJCONJb = (p1 :> FALSE @@ p2 :> TRUE @@ p3 :> TRUE)CONJc = (p1 :> TRUE @@ p2 :> TRUE @@ p3 :> TRUE)CONJk = p1CONJpc = (p1 :> \"Li1\" @@ p2 :> \"Li0\" @@ p3 :> \"Li0\")CONJtemp = (p1 :> defaultInitValue @@ p2 :> defaultInitValue @@ p3 :> defaultInitValue)" | verify-true
+	}
+
+	get-menu -path "File/Save" | click
+} -finally {
+	DeleteSpecNew
+}
+------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.TLAPS.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.TLAPS.test
new file mode 100644
index 0000000000000000000000000000000000000000..bd8d8921799355fb4d008eaeba797b244020f0af
--- /dev/null
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.TLAPS.test
@@ -0,0 +1,61 @@
+--- RCPTT testcase ---
+Format-Version: 1.0
+Element-Name: TLA.Functional.TLAPS
+Element-Type: testcase
+Element-Version: 3.0
+External-Reference: 
+Id: _RifTcLZDEemcF9BXFSE9ew
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 12:56 PM
+Testcase-Type: ecl
+
+------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac
+Content-Type: text/ecl
+Entry-Name: .content
+
+let [val shouldRunTest [get-by-os -macosx "no" -default "yes"]] {
+	if [$shouldRunTest] {
+		OpenTLACreateNew
+		
+		let [val isWindows [get-by-os -win "yes" -default "no"]] {
+			try -command {
+				with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
+					set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 3\n\nNext == x' = x ^ 1\n=============================================================================\n"]
+				    key-type "M1+s"
+				    
+				    mouse down -button Right | get-menu -path "TLA Proof Manager/Launch Prover..." | is-disabled | verify-true
+			    }
+			    
+				get-preferences-menu | click
+				with [get-window Preferences ] {
+					get-tree | select "TLA+ Preferences/TLAPS" 
+					
+					if [$isWindows | equals "yes"] {
+						// we only need an existing file that is executable
+						get-editbox -after [get-label "Location of tlapm"] | set-text "C:\Windows\explorer.exe"
+					}
+					-else {
+						// we only need an existing file that is executable
+						get-editbox -after [get-label "Location of tlapm"] | set-text "/bin/ls"
+					}
+				    
+				    get-button "Apply and Close" | click
+				}
+				
+				with [get-editor $TLA-SPEC-NAME] {
+					with [get-text-viewer] {
+						mouse down -button Right
+						with [get-menu -path "TLA Proof Manager/Launch Prover..."] {
+							is-disabled | verify-false
+						}
+					}
+				}
+			}
+			-finally {
+				DeleteSpecNew
+			}
+		}
+	}
+}
+
+------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Temporal.Formula.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Temporal.Formula.test
index efe0dd806c1611402143778ad38e7aa43d04c634..9393d4cb58d65e7e450d1e865be3c62f8502114c 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Temporal.Formula.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Temporal.Formula.test
@@ -6,7 +6,7 @@ Element-Version: 3.0
 External-Reference: 
 Id: _g-dKoAPoEemwBd2liJ-qvA
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 6/10/19, 9:02 AM
+Save-Time: 10/14/19, 1:12 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -28,54 +28,43 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 1"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 1"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 1\n\n=============================================================================\n"]
 	    key-type "M1+s"
     }
-    wait -ms 1000
 
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	with [get-window "New model..."] {
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	with [get-window $TLA-DIALOG-TITLE-NEW-MODEL] {
 	    get-editbox -after [get-label "Please input the name of the model to create"] 
 	        | set-text $TLA-Long-Model-Name
-	    get-button OK | click
+	    get-button $TLA-BUTTON-OK | click
 	}
 	with [get-editor $TLA-Long-Model-Name] {
-	    get-section "Model description" | get-text-viewer | type-text tlatlatla
-	    with [get-section "What to check?"] {
-	        get-button "Deadlock" | uncheck
-	        get-section "Invariants" | click
-	        get-section "Properties" | click
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-DESCRIPTION | get-text-viewer | type-text "tlatlatla"
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK] {
+	        get-button $TLA-BUTTON-DEADLOCK | uncheck
+	        get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-INV | click
+	        get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-PROP | click
 	    }
 	}
 	
 	with [get-editor $TLA-Long-Model-Name] {
-	    with [get-section "What is the behavior spec?"] {
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-SPEC] {
 	        get-combo | select "Temporal formula"
 	        get-text-viewer | type-text "x=2"
 	    }
-	    get-link "Additional TLC Options" | click
-	    get-editbox -after [get-label "Number of worker threads:"] | set-text 2
-	    get-button "Checks the model for errors but does not run TLC on it." | click
-	    get-button "Runs TLC on the model." | click
+	    get-link $TLA-MO-ED-OVERVIEW-LINK-TLC | click
+	    get-editbox -after [get-label "Number of worker threads:"] | set-text "2"
+	    get-button $TLA-BUTTON-MODEL-CHECK | click
+	    get-button $TLA-BUTTON-RUN-TLC | click
 	}
 	
 	wait-run
 	
 	with [get-editor $TLA-Long-Model-Name] {
-	    get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" | verify-true
-	    get-link "State space exploration incomplete" | get-property caption | equals "State space exploration incomplete" 
-	        | verify-true
+		get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-RESULTS | click
+	    get-link "State space exploration incomplete"
+	    get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
 	}
-	get-editor $TLA-Long-Model-Name | get-tab-folder | get-tab-item "Model Overview" | click
 } -finally {
 	DeleteSpecNew
 }
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Test.Suite.suite b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Test.Suite.suite
index c5d744ef5912419c2b79095dc1f89646a28846f5..278d50deb0756c8fa793039422740906548d7a1f 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Test.Suite.suite
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA.Functional.Test.Suite.suite
@@ -5,7 +5,7 @@ Element-Type: testsuite
 Element-Version: 2.0
 Id: _XtCd4APNEemtrbArmQOOJA
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 6/10/19, 4:39 PM
+Save-Time: 11/4/19, 12:24 PM
 
 ------=_testcase-items-62c497da-4241-31f4-811a-6b453a3ecff8
 Content-Type: text/testcase
@@ -45,6 +45,10 @@ _EdNeQBUsEemG79v6PBILBA	// kind: 'test' name: 'TLA.Functional.Property.Formula'
 _HJaIUBU4EemG79v6PBILBA	// kind: 'test' name: 'TLA.Functional.TLA.Options.Defaults' path: 'TLA_Functional_TLA_Options_Defaults.test'
 _s4DEYBXnEemrGZBXFuwIoA	// kind: 'test' name: 'TLA.Functional.Model.Results.Defaults' path: 'TLA_Functional_Model_Results_Defaults.test'
 _b7FWkFSpEemyiKKvW3h83Q	// kind: 'test' name: 'TLA.Functional.Delete.Additional.Module' path: 'TLA.Functional.Delete.Additional.Module.test'
-_JObaIIvTEemXYtOZX2zpng	// kind: 'test' name: 'TLA_Functional_ECE_Placement' path: 'TLA_Functional_ECE_Placement.test'
+_JObaIIvTEemXYtOZX2zpng	// kind: 'test' name: 'TLA.Functional.ECE.Placement' path: 'TLA.Functional.ECE.Placement.test'
+_RifTcLZDEemcF9BXFSE9ew	// kind: 'test' name: 'TLA.Functional.TLAPS' path: 'TLA.Functional.TLAPS.test'
+_wH2aMNWzEemOp9qASlV00A	// kind: 'test' name: 'TLA.Functional.PCal.Checksums' path: 'TLA.Functional.PCal.Checksums.test'
+_BbLbgO0TEemu8qbF8JrHog	// kind: 'test' name: 'TLA.Functional.Error.Trace' path: 'TLA.Functional.Error.Trace.test'
+_r_EqIP84EemUPYAc4mFamA	// kind: 'test' name: 'TLA.Functional.Start.From.Error.Trace' path: 'TLA.Functional.Start.From.Error.Trace.test'
 
 ------=_testcase-items-62c497da-4241-31f4-811a-6b453a3ecff8--
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Action_Constraint.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Action_Constraint.test
index 54940b05b30f365a18333885c8d2e9d5d50ad87e..56c6da9c80a7f5e85c3f4ec4b9e5ae398b579cbf 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Action_Constraint.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Action_Constraint.test
@@ -6,7 +6,7 @@ Element-Version: 3.0
 External-Reference: 
 Id: _TZC_4BU2EemG79v6PBILBA
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 6/10/19, 9:03 AM
+Save-Time: 10/14/19, 1:05 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -24,46 +24,32 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 1"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 2"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 2\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
-	wait -ms 500
-	get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
-	wait -ms 1000
+
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
 	
-	with [get-editor "Model_1"] {
-		get-section "What is the model?" | click
-		get-link "Additional Spec Options" | click
-	    with [get-section "Action Constraint"] {
+	with [get-editor $TLA-MODEL-ONE] {
+		get-section $TLA-MO-ED-OVERVIEW-SECTION-MODEL | click
+		get-link $TLA-MO-ED-OVERVIEW-LINK-SPEC | click
+	    with [get-section $TLA-MO-ED-ADDITIONAL-SECTION-AC] {
 	        get-text-viewer | type-text "x=1+5"
 	    }
-	    get-button "Checks the model for errors but does not run TLC on it." | click
-	}
-	get-editor "Model_1" | get-section "Action Constraint" | get-text-viewer | get-property text | equals "x=1+5" 
-	    | verify-true
-	with [get-editor "Model_1"] {
-	    with [get-section "Action Constraint" | get-text-viewer] {
+	    get-button $TLA-BUTTON-MODEL-CHECK | click
+	    
+	    with [get-section $TLA-MO-ED-ADDITIONAL-SECTION-AC | get-text-viewer] {
+	    	get-property text | equals "x=1+5" | verify-true
+	    	
 	        set-caret-pos 1 6
 	        key-type BackSpace -times 5
-	        type-text badformula
+	        type-text "badformula"
 	    }
-	    get-button "Checks the model for errors but does not run TLC on it." | click
-	}
-	with [get-editor "Model_1"] {
-	    get-link "1 error detected" | get-property caption | equals "1 error detected" | verify-true
-	    get-section "Action Constraint" | get-text-viewer | get-property text | equals badformula | verify-true
+	    get-button $TLA-BUTTON-MODEL-CHECK | click
+
+	    get-link "1 error detected"
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-AC | get-text-viewer | get-property text | equals "badformula" | verify-true
 	}
 } -finally {
 	DeleteSpecNew
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Basic_Model.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Basic_Model.test
index ba6f1be6af104e02adaf5b5808c7eab29bc09ac5..fa3c833d563cc300589d18ed9cd6e0bc3f974278 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Basic_Model.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Basic_Model.test
@@ -6,7 +6,7 @@ Element-Version: 3.0
 External-Reference: 
 Id: _44K9cAJWEemDc-4PKyNT9w
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 6/10/19, 9:47 AM
+Save-Time: 10/14/19, 1:06 PM
 Testcase-Type: ecl
 
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac
@@ -18,73 +18,63 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 1"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 1"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 1\n\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
 
-	get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	with [get-editor "Model_1"] {
-		get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
-		get-section "What is the model?" | click
-		get-link "Additional Spec Options" | click
-		get-tab-folder | get-tab-item "Model Overview" | click
-		get-section "How to run?" | click
-		get-link "Additional TLC Options" | click
-		get-tab-folder | get-tab-item "Model Overview" | click
-		get-button "Runs TLC on the model." | click
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+	with [get-editor $TLA-MODEL-ONE] {
+		get-section $TLA-MO-ED-OVERVIEW-SECTION-MODEL | click
+		get-link $TLA-MO-ED-OVERVIEW-LINK-SPEC | click
+		get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+		get-section $TLA-MO-ED-OVERVIEW-SECTION-RUN | click
+		get-link $TLA-MO-ED-OVERVIEW-LINK-TLC | click
+		get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+	    verify-error { get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-RESULTS }
+		get-button $TLA-BUTTON-RUN-TLC | click
 	}
 	
 	wait-run
 	
 	// The error link should not be visible because there are no errors.
-	verify-error {get-editor $TLA-MODEL-ONE | get-section General | get-link "No errors" }
-	with [get-editor "Model_1" | get-tab-folder] {
-	    get-tab-item "Model Overview" | click
-	    get-tab-item "Spec Options" | click
-	    get-tab-item "TLC Options" | click
-	    get-tab-item "Model Checking Results" | click
+	verify-error {get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-RESULTS-SECTION-GENERAL | get-link "No errors" }
+	with [get-editor $TLA-MODEL-ONE | get-tab-folder] {
+	    get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+	    get-tab-item $TLA-MODEL-EDITOR-TAB-ADDITIONAL | click
+	    get-tab-item $TLA-MODEL-EDITOR-TAB-TLC-OPTIONS | click
+	    get-tab-item $TLA-MODEL-EDITOR-TAB-RESULTS | click
 	}
-	get-editor "Model_1" | close	
+	get-editor $TLA-MODEL-ONE | close	
 	
 	// Test the state-saving of open close-able tabs in the model editor:
 	
-	get-view "Spec Explorer" | get-tree | select [concat $TLA-TREE-NAME "/models/Model_1"] | get-menu -path "Open" | click
-	with [get-editor "Model_1" | get-tab-folder] {
-	    get-tab-item "Model Overview" | click
-	    get-tab-item "Spec Options" | click
-	    get-tab-item "TLC Options" | click
-	    get-tab-item "Spec Options" | close
+	get-view $TLA-VIEW-SPEC-EXPLORER | get-tree | select [concat $TLA-TREE-NAME "/models/" $TLA-MODEL-ONE] | get-menu -path "Open" | click
+	with [get-editor $TLA-MODEL-ONE | get-tab-folder] {
+	    get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+	    get-tab-item $TLA-MODEL-EDITOR-TAB-ADDITIONAL | click
+	    get-tab-item $TLA-MODEL-EDITOR-TAB-TLC-OPTIONS | click
+	    get-tab-item $TLA-MODEL-EDITOR-TAB-ADDITIONAL | close
 	}
-	get-editor "Model_1" | close	
+	get-editor $TLA-MODEL-ONE | close	
 
-	get-view "Spec Explorer" | get-tree | select [concat $TLA-TREE-NAME "/models/Model_1"] | get-menu -path "Open" | click
-	with [get-editor "Model_1" | get-tab-folder] {
-	    get-tab-item "Model Overview" | click
-	    get-tab-item "TLC Options" | click
-	    verify-error { get-tab-item "Spec Options" }
-	    get-tab-item "TLC Options" | close
-	    get-tab-item "Model Checking Results" | click
+	get-view $TLA-VIEW-SPEC-EXPLORER | get-tree | select [concat $TLA-TREE-NAME "/models/" $TLA-MODEL-ONE] | get-menu -path "Open" | click
+	with [get-editor $TLA-MODEL-ONE | get-tab-folder] {
+	    get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+	    get-tab-item $TLA-MODEL-EDITOR-TAB-TLC-OPTIONS | click
+	    verify-error { get-tab-item $TLA-MODEL-EDITOR-TAB-ADDITIONAL }
+	    get-tab-item $TLA-MODEL-EDITOR-TAB-TLC-OPTIONS | close
+	    get-tab-item $TLA-MODEL-EDITOR-TAB-RESULTS | click
 	}
-	get-editor "Model_1" | close	
+	get-editor $TLA-MODEL-ONE | close	
 
-	get-view "Spec Explorer" | get-tree | select [concat $TLA-TREE-NAME "/models/Model_1"] | get-menu -path "Open" | click
-	with [get-editor "Model_1" | get-tab-folder] {
-	    get-tab-item "Model Overview" | click
-	    verify-error { get-tab-item "TLC Options" }
-	    get-tab-item "Model Checking Results" | click
+	get-view $TLA-VIEW-SPEC-EXPLORER | get-tree | select [concat $TLA-TREE-NAME "/models/" $TLA-MODEL-ONE] | get-menu -path "Open" | click
+	with [get-editor $TLA-MODEL-ONE | get-tab-folder] {
+	    get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+	    verify-error { get-tab-item $TLA-MODEL-EDITOR-TAB-TLC-OPTIONS }
+	    get-tab-item $TLA-MODEL-EDITOR-TAB-RESULTS | click
 	}
-	get-editor "Model_1" | close	
+	get-editor $TLA-MODEL-ONE | close	
 } -finally {
 	DeleteSpecNew
 }
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Check_Model_OnError.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Check_Model_OnError.test
index ccdacc51c9e44f959d9d8a962689c0b58634bdc9..441b65f98dbfacd95690ddc48ed31528c1bd0536 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Check_Model_OnError.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Check_Model_OnError.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _ax464BUkEemG79v6PBILBA
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 9:12 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:06 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -29,47 +29,35 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 1"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 1"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 1\n\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
-	wait -ms 500
-	get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
+
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
 	
-	with [get-editor "Model_1"] {
-	    with [get-section "What is the behavior spec?"] {
+	with [get-editor $TLA-MODEL-ONE] {
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-SPEC] {
 	        with [get-text-viewer] {
 	            set-caret-pos 1 5
 	            key-type BackSpace -times 4
-	            type-text foo
+	            type-text "foo"
 	        }
 	        with [get-text-viewer -after [get-label "Next:"]] {
 	            set-caret-pos 1 4
 	            select-range 1 5 1 1
-	            type-text no
+	            type-text "no"
 	        }
 	    }
-	    get-button "Checks the model for errors but does not run TLC on it." | click
-	}
-	get-editor "Model_1" | get-link "2 errors detected" | get-property caption | equals "2 errors detected" | verify-true
-	with [get-editor "Model_1"] {
+	    get-button $TLA-BUTTON-MODEL-CHECK | click
+
 	    get-link "2 errors detected" | click
-	    get-section "What is the behavior spec?" | get-combo | select "No Behavior Spec"
-	    get-button "Checks the model for errors but does not run TLC on it." | click
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-SPEC | get-combo | select "No Behavior Spec"
+	    get-button $TLA-BUTTON-MODEL-CHECK | click
+	    
+		//Verify no error link
+		get-link | get-property caption | equals "2 errors detected" | verify-false
 	}
-	//Verify no error link
-	get-editor "Model_1" | get-link  | get-property caption | equals "2 errors detected" | verify-false
 } -finally {
 	DeleteSpecNew
 }
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clear_Console.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clear_Console.test
index 4b2eeb23a20f67273357c743a5324fb5e2b4e351..8f9362cc10a19e330f29abc25c9bb4e97f55fae8 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clear_Console.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clear_Console.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _I-Xj0APqEemwBd2liJ-qvA
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 9:13 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:06 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -29,39 +29,28 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 0"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x - 1"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x - 1\n=============================================================================\n"]
 	    key-type "M1+s"
     }
     
 	get-menu -path "TLC Model Checker/TLC Console" | click
 	
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-button "Runs TLC on the model." | click
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+	get-editor $TLA-MODEL-ONE | get-button $TLA-BUTTON-RUN-TLC | click
 
 	wait -ms 1000
 	//TODO
-	get-editor "Model_1" | get-button "Stops the current TLC model checker run." | click
+	get-editor $TLA-MODEL-ONE | get-button $TLA-BUTTON-CANCEL-TLC | click
 
 	wait-run    
 		
-	get-editor "Model_1" | get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" 
-	    | verify-true
-	with [get-view Console | get-text-viewer] {
+	with [get-view "Console" | get-text-viewer] {
 	    set-caret-pos 4 13
-	    get-menu -path Clear | click
+	    get-menu -path "Clear" | click
 	    set-caret-pos 1 1
+	    get-property text | equals "" | verify-true
 	}
-	get-view Console | get-text-viewer | get-property text | equals "" | verify-true
 } -finally {
 	DeleteSpecNew
 }
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clear_Error_Temporal.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clear_Error_Temporal.test
index 105a0b02b5410fba1c2227bf2682741ce6c62fd3..03f53a414351153b9e3849679ad7a4e503f7df94 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clear_Error_Temporal.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clear_Error_Temporal.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _gOLvABUlEemG79v6PBILBA
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 9:13 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 12:58 PM
 Testcase-Type: ecl
 
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac
@@ -18,50 +18,38 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 1"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 1"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 1\n\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
-	wait -ms 500
-	get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
+
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
 	
 	
-	with [get-editor "Model_1"] {
-	    with [get-section "What is the behavior spec?"] {
+	with [get-editor $TLA-MODEL-ONE] {
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-SPEC] {
 	    	get-combo | select "Temporal formula"
 	        get-text-viewer | type-text "x  == 1"
 	    }
-	    get-button "Checks the model for errors but does not run TLC on it." | click
-	    with [get-section "What is the behavior spec?" | get-text-viewer ] {
+	    get-button $TLA-BUTTON-MODEL-CHECK | click
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-SPEC | get-text-viewer ] {
 	        set-caret-pos 1 8
 	        key-type BackSpace -times 6
 	        type-text "=2"
 	    }
-	    get-button "Checks the model for errors but does not run TLC on it." | click
-	    get-section "What is the behavior spec?" | get-text-viewer | type-text ";y=1"
-	    get-button "Checks the model for errors but does not run TLC on it." | click
-	}
-	get-editor "Model_1" | get-link "1 error detected" | get-property caption | equals "1 error detected" | verify-true
-	with [get-editor "Model_1"] {
-	    with [get-section "What is the behavior spec?" | get-text-viewer ] {
+	    get-button $TLA-BUTTON-MODEL-CHECK | click
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-SPEC | get-text-viewer | type-text ";y=1"
+	    get-button $TLA-BUTTON-MODEL-CHECK | click
+
+		get-link "1 error detected"
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-SPEC | get-text-viewer ] {
 	        set-caret-pos 1 8
 	        key-type BackSpace -times 4
 	    }
-	    get-button "Checks the model for errors but does not run TLC on it." | click
+	    get-button $TLA-BUTTON-MODEL-CHECK | click
+	    
+	    get-link | get-property caption | equals "1 error detected" | verify-false
 	}
-	
-	get-editor "Model_1" | get-link  | get-property caption | equals "1 error detected" | verify-false
 } -finally {
 	DeleteSpecNew
 }
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clone_Model.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clone_Model.test
index f532fa99b514feeb9bad32d5d9ab560a9478a596..e36b97beaa380ce23ff489750448ce955f3a6a3d 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clone_Model.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Clone_Model.test
@@ -6,7 +6,7 @@ Element-Version: 3.0
 External-Reference: 
 Id: _ARWUAAJjEemDc-4PKyNT9w
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 6/30/19, 8:38 AM
+Save-Time: 10/14/19, 1:06 PM
 Testcase-Type: ecl
 
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac
@@ -18,37 +18,26 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 0"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x - 1"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x - 1\n=============================================================================\n"]
 	    key-type "M1+s"
     }
     
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button "OK" | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
-	get-editor "Model_1" | get-button "Runs TLC on the model." | click
-	get-editor "Model_1" | get-button "Stops the current TLC model checker run." | click
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+	with [get-editor $TLA-MODEL-ONE] {
+		get-button $TLA-BUTTON-RUN-TLC | click
+		get-button $TLA-BUTTON-CANCEL-TLC | click
+	}
 	
 	wait-run    
 	
-	get-editor "Model_1" | get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" 
-	    | verify-true
-	get-menu -path "TLC Model Checker/Clone Model/Model_1" | click
-	get-window "Clone model..." | get-label "Please input the new name of the model" | get-property caption 
-	    | equals "Please input the new name of the model" | verify-true
-	get-window "Clone model..." | get-button "OK" | click
+	get-menu -path [concat "TLC Model Checker/Clone Model/" $TLA-MODEL-ONE] | click
+	get-window "Clone model..." | get-label "Please input the new name of the model"
+	get-window "Clone model..." | get-button $TLA-BUTTON-OK | click
 	
 	let [val descriptionText "Some description text."] {
 		with [get-editor "Model_2"] {
-		    with [get-section "Model description"] {
+		    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-DESCRIPTION] {
 		        click
 		    	with [get-text-viewer] {
 		    		type-text $descriptionText
@@ -56,7 +45,7 @@ try -command {
 		    	}
 		        click
 		    }
-		    get-tab-folder | get-tab-item "Model Checking Results" | click
+		    get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-RESULTS | click
 		}
 		
 		CreateNewSpec "another.tla"
@@ -64,18 +53,17 @@ try -command {
 		with [get-window "Please choose a spec and a model"] {
 			get-list | select $TLA-SPEC-NAME
 			get-list -index 1 | select "Model_2"
-			get-button "OK" | click
+			get-button $TLA-BUTTON-OK | click
 		}
-		get-window "Clone model..." | get-label "Please input the new name of the model" | get-property caption 
-		    | equals "Please input the new name of the model" | verify-true
-		get-window "Clone model..." | get-button "OK" | click
+		get-window "Clone model..." | get-label "Please input the new name of the model"
+		get-window "Clone model..." | get-button $TLA-BUTTON-OK | click
 		with [get-editor "Model_2"] {
-		    get-tab-folder | get-tab-item "Model Overview" | click
-		    with [get-section "Model description"] {
+		    get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+		    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-DESCRIPTION] {
 		        get-text-viewer | get-text | equals $descriptionText | verify-true
 		        click
 		    }
-		    get-tab-folder | get-tab-item "Model Checking Results" | click
+		    get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-RESULTS | click
 		}
 		get-menu -path "File/Save" | click
 	}
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Deadlock_Unchecked.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Deadlock_Unchecked.test
index cf7e5a71e392965ffb229a7f3774122d9118e9ac..60ff2a32df1fcc21ea8f9ad0e597744c3f18fc37 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Deadlock_Unchecked.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Deadlock_Unchecked.test
@@ -6,7 +6,7 @@ Element-Version: 3.0
 External-Reference: 
 Id: _qD9ogAPmEemwBd2liJ-qvA
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 6/10/19, 8:59 AM
+Save-Time: 10/14/19, 1:06 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -28,48 +28,36 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 1"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 1"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 1\n\n=============================================================================\n"]
 	    key-type "M1+s"
     }
     wait -ms 1000
 
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	with [get-window "New model..."] {
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	with [get-window $TLA-DIALOG-TITLE-NEW-MODEL] {
 	    get-editbox -after [get-label "Please input the name of the model to create"] 
 	        | set-text $TLA-Long-Model-Name
-	    get-button "OK" | click
+	    get-button $TLA-BUTTON-OK | click
 	}
 	with [get-editor $TLA-Long-Model-Name] {
-	    get-section "Model description" | get-text-viewer | type-text tlatlatla
-	    with [get-section "What to check?"] {
-	        get-button "Deadlock" | uncheck
-	        get-section "Invariants" | click
-	        get-section "Properties" | click
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-DESCRIPTION | get-text-viewer | type-text "tlatlatla"
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK] {
+	        get-button $TLA-BUTTON-DEADLOCK | uncheck
+	        get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-INV | click
+	        get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-PROP | click
 	    }
-	    get-section "What is the model?" | click
-	    get-link "Additional TLC Options" | click
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-MODEL | click
+	    get-link $TLA-MO-ED-OVERVIEW-LINK-TLC | click
         get-editbox -after [get-label "Number of worker threads:"] | set-text 2
-	    get-button "Runs TLC on the model." | click
+	    get-button $TLA-BUTTON-RUN-TLC | click
 	}
 	
 	wait-run    
 	
 	with [get-editor $TLA-Long-Model-Name] {
-	    get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" | verify-true
 		// The error link should not be visible because there are no errors.
-		verify-error {get-section General | get-link "No errors" }
-	}
-	with [get-editor $TLA-Long-Model-Name | get-tab-folder] {
-	    get-tab-item "Model Overview" | click
+		verify-error {get-section $TLA-MO-ED-RESULTS-SECTION-GENERAL | get-link "No errors" }
+		get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
 	}
 } -finally {
 	DeleteSpecNew
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Definition_Override.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Definition_Override.test
index 4ba7df263659cd5307d714fb87fc4059d7834b23..843a24b94efb795b93a11a74b91d70d38722e97f 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Definition_Override.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Definition_Override.test
@@ -6,7 +6,7 @@ Element-Version: 3.0
 External-Reference: 
 Id: _1MkFEBUzEemG79v6PBILBA
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 6/10/19, 9:03 AM
+Save-Time: 10/14/19, 1:07 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -25,86 +25,67 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 1"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 2"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 2\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
-	wait -ms 500
-	
-	get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
-	
+
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
 	
-	with [get-editor "Model_1"] {
-	    get-tab-folder | get-tab-item "Model Overview" | click
-		get-section "What is the model?" | click
-		get-link "Additional Spec Options" | click
-	    with [get-section "Definition Override"] {
-	        get-button Add | click
+	with [get-editor $TLA-MODEL-ONE] {
+	    get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+		get-section $TLA-MO-ED-OVERVIEW-SECTION-MODEL | click
+		get-link $TLA-MO-ED-OVERVIEW-LINK-SPEC | click
+	    with [get-section $TLA-MO-ED-ADDITIONAL-SECTION-DO] {
+	        get-button $TLA-BUTTON-ADD | click
 	    }
 	}
+	
 	with [get-window "Select Definition to Override"] {
 	    get-table | select [get-item -path "%" -index 0]
-	    get-button OK | click
+	    get-button $TLA-BUTTON-OK | click
 	}
-	wait -ms 500
 	
 	with [get-window -class WizardDialog] {
-	    get-label "Definition Override" | get-property caption | equals "Definition Override" | verify-true
 	    get-editbox -after [get-label "("] | get-property enablement | equals true | verify-true
 	}
-	wait -ms 500
 	
 	with [get-window -class WizardDialog] {
-	    get-editbox -after [get-label "("] | set-text 1
-	    get-editbox -after [get-label ","] | set-text 1
-	    get-text-viewer | type-text x
-	    get-button Finish | click
+	    get-editbox -after [get-label "("] | set-text "1"
+	    get-editbox -after [get-label ","] | set-text "1"
+	    get-text-viewer | type-text "x"
+	    get-button $TLA-BUTTON-FINISH | click
 	}
-	wait -ms 500
 	
-	get-editor "Model_1" | get-section "Definition Override" | get-table | get-item -path "%\\(1, 1\\) <- x" 
-	    | get-property caption | equals "%(1, 1) <- x" | verify-true
-	with [get-editor "Model_1" | get-section "Definition Override"] {
+	with [get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-ADDITIONAL-SECTION-DO] {
 	    get-table | select "%(1, 1) <- x"
-	    get-button Remove | click
+	    get-button $TLA-BUTTON-REMOVE | click
 	}
 	
-	with [get-editor "Model_1"] {
-	    get-button "Checks the model for errors but does not run TLC on it." | click
-	    get-section "Definition Override" | get-button Add | click
+	with [get-editor $TLA-MODEL-ONE] {
+	    get-button $TLA-BUTTON-MODEL-CHECK | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-DO | get-button $TLA-BUTTON-ADD | click
 	}
-	get-window "Select Definition to Override" 
-	    | get-label "Type definition to override or select from the list below(?= any character, *= any string)" 
-	    | get-property caption | equals "Type definition to override or select from the list below\n"
-	    + "(?= any character, *= any string)" | verify-true
+
 	with [get-window "Select Definition to Override"] {
-	    get-table | select Next
-	    get-button OK | click
+		get-label "Type definition to override or select from the list below(?= any character, *= any string)"
+	    get-table | select "Next"
+	    get-button $TLA-BUTTON-OK | click
 	}
-	get-window -class WizardDialog | get-label "Definition Override" | get-property caption | equals "Definition Override" 
-	    | verify-true
+
 	with [get-window -class WizardDialog] {
 	    get-text-viewer | type-text 1
 	    get-button "Model value" | click
+	    get-editbox -after [get-label "<-"] | get-property enablement | equals false  | verify-true
+		get-button "Ordinary assignment" | click
+		get-text-viewer | get-property enablement | equals true | verify-true
+		get-button $TLA-BUTTON-FINISH | click
+	}
+	
+	with [get-editor $TLA-MODEL-ONE] {
+		get-section $TLA-MO-ED-ADDITIONAL-SECTION-DO | get-table | get-property itemCount | equals 1 | verify-true
+		get-button $TLA-BUTTON-MODEL-CHECK | click
 	}
-	get-window -class WizardDialog | get-editbox -after [get-label "<-"] | get-property enablement | equals false 
-	    | verify-true
-	get-window -class WizardDialog | get-button "Ordinary assignment" | click
-	get-window -class WizardDialog | get-text-viewer | get-property enablement | equals true | verify-true
-	get-window -class WizardDialog | get-button Finish | click
-	get-editor "Model_1" | get-section "Definition Override" | get-table | get-property itemCount | equals 1 | verify-true
-	get-editor "Model_1" | get-button "Checks the model for errors but does not run TLC on it." | click
 } -finally {
 	DeleteSpecNew
 }
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Distributed_Mode_Options.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Distributed_Mode_Options.test
index be3be856e7e0cbee6e06a38c17924132823ab3d9..a72b4e150acab95319b6852010ffedeab03ca635 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Distributed_Mode_Options.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Distributed_Mode_Options.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _Gvi30BUtEemG79v6PBILBA
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 9:13 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:07 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -26,39 +26,24 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 1"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 2"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 2\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
-	wait -ms 500
-	
-	get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
+
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
 	
-	get-editor "Model_1" | get-section "How to run?" | click
-	get-editor "Model_1" | get-section "How to run?" | get-combo -after [get-label "System resources dedicated to TLC:"] 
-	    | select "Ad Hoc"
-	with [get-editor "Model_1" | get-section "How to run?"] {
+	with [get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-OVERVIEW-SECTION-RUN] {
+		click
+		get-combo -after [get-label "System resources dedicated to TLC:"] | select "Ad Hoc"
 	    get-combo -after [get-label "System resources dedicated to TLC:"] | get-property selection | equals "Ad Hoc" | verify-true
 	    // TODO: unable to use ECL to get a spinner presently
 //	    get-control -kind "Spinner" -after [get-label "Number of worker threads:"] | get-property enablement | equals false | verify-true
 	    // TODO: unable to use ECL to get a scale presently
 //	    get-control -kind "Scale" -after [get-label "Fraction of physical memory allocated to TLC:"] | get-property enablement | equals true | verify-true
 	    get-combo -after [get-label "Master's network address:"] | get-property enablement | equals true | verify-true
-	}
-	get-editor "Model_1" | get-section "How to run?" | get-combo -after [get-label "System resources dedicated to TLC:"] 
-	    | select "Amazon"
-	with [get-editor "Model_1" | get-section "How to run?"] {
+	    
+	    get-combo -after [get-label "System resources dedicated to TLC:"] | select "Amazon"
 	    get-combo -after [get-label "System resources dedicated to TLC:"] | get-property selection | equals "Amazon" | verify-true
 	    with [get-editbox -after [get-label "Result mailto addresses:"]] {
 	        get-property className | equals "org.eclipse.swt.widgets.Text" | verify-true
@@ -66,7 +51,6 @@ try -command {
 	    }
 	    with [get-label "Result mailto addresses:"] {
 	        get-property enablement | equals true | verify-true
-	        get-property caption | equals "Result mailto addresses:" | verify-true
 	    }
 	    
 	    get-combo -after [get-label "System resources dedicated to TLC:"] | select "Azure"
@@ -79,9 +63,9 @@ try -command {
 	    get-combo -after [get-label "System resources dedicated to TLC:"] | get-property selection | equals "Azure" | verify-true
 	}
 
-	with [get-editor "Model_1"] {
-	    get-section "How to run?" | get-combo -after [get-label "System resources dedicated to TLC:"] | select "Medium"
-	    get-button "Checks the model for errors but does not run TLC on it." | click
+	with [get-editor $TLA-MODEL-ONE] {
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-RUN | get-combo -after [get-label "System resources dedicated to TLC:"] | select "Medium"
+	    get-button $TLA-BUTTON-MODEL-CHECK | click
 	}
 } -finally {
 	DeleteSpecNew
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Exp.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Exp.test
index ef5d3bbd858f64bdf85b7db2415a9249700d18d5..88106fb7cd1061a48f43f5ca1f8d8c09fbf894be 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Exp.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Exp.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _dOXZwAJfEemDc-4PKyNT9w
-Runtime-Version: 2.4.2.201905122359
-Save-Time: 6/17/19, 2:45 PM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:07 PM
 Testcase-Type: ecl
 
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac
@@ -18,27 +18,18 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 3"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x ^ 1"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 3\n\nNext == x' = x ^ 1\n=============================================================================\n"]
 	    key-type "M1+s"
     }
 
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
-	get-editor "Model_1" | get-button "Runs TLC on the model." | click
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
 	
-	wait-run    
+	get-editor $TLA-MODEL-ONE | get-button $TLA-BUTTON-RUN-TLC | click
+	
+	wait-run
 	        
-	with [get-editor "Model_1" | get-section General] {
+	with [get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-RESULTS-SECTION-GENERAL] {
 	    get-label "Fingerprint collision probability: calculated: 5.4E-20"
 	    verify-error {get-link "No errors"}
 	}
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Find_Replace.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Find_Replace.test
index a904790bac1e395d580b5c27db3f24a324e08c0a..cc62f4c6e9f76120ff6747f3a14e96a3640f65fd 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Find_Replace.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Find_Replace.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _uAilEAPhEemwBd2liJ-qvA
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 11:52 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:07 PM
 Testcase-Type: ecl
 
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac
@@ -14,52 +14,43 @@ Content-Type: text/ecl
 Entry-Name: .content
 
 OpenTLACreateNew
-try -command {
-
-
-with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-    key-type Down
-    type-text "EXTENDS Naturals"
-    key-type Enter
-    type-text "VARIABLE x"
-    key-type Enter -times 1
-    type-text "Init == x = 1"
-    key-type Enter -times 2
-    type-text "Next == x' = x * 1"
-     key-type "M1+s"
-    }
-    wait -ms 1000
-get-menu -path "TLC Model Checker/TLC Console" | click
-with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-    set-caret-pos 4 7
-    hover-text 4 1
-    set-caret-pos 4 1
-}
-get-menu -path "Edit/Content Assist" | click
-get-window -from "CompletionProposalPopup.createProposalSelector()" | get-table | select "\\n"
-    + "eg: \\n"
-    + "eg"
-get-editor $TLA-SPEC-NAME | get-text-viewer | set-caret-pos 7 1
-get-menu -path "Edit/Content Assist" | click
-get-window -from "CompletionProposalPopup.createProposalSelector()" | get-table | select "ACTION : ACTION "
-with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-    set-caret-pos 4 10
-    select-range 4 9 4 10
-    hover-text 4 9 -with Left
-}
-get-menu -path "Edit/Find and Replace" | click
-with [get-window "Find/Replace"] {
-    get-combo -after [get-label "Replace with:"] | set-text y
-    get-button "Replace All" | click
-    get-button Close | click
 
+try -command {
+	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 1\n\n=============================================================================\n"]
+	    key-type "M1+s"
+	}
+
+	get-menu -path "TLC Model Checker/TLC Console" | click
+	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
+	    set-caret-pos 4 7
+	    hover-text 4 1
+	    set-caret-pos 4 1
+	}
+	get-menu -path "Edit/Content Assist" | click
+	get-window -from "CompletionProposalPopup.createProposalSelector()" | get-table | select "\\n"
+	    + "eg: \\n"
+	    + "eg"
+	get-editor $TLA-SPEC-NAME | get-text-viewer | set-caret-pos 7 1
+	get-menu -path "Edit/Content Assist" | click
+	get-window -from "CompletionProposalPopup.createProposalSelector()" | get-table | select "ACTION : ACTION "
+	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
+	    set-caret-pos 4 10
+	    select-range 4 9 4 10
+	    hover-text 4 9 -with Left
+	}
+	get-menu -path "Edit/Find and Replace" | click
+	with [get-window "Find/Replace"] {
+	    get-combo -after [get-label "Replace with:"] | set-text y
+	    get-button "Replace All" | click
+	    get-button "Close" | click
+	
+	}
+	
+	get-menu -path "File/Parse Spec" | click
+	get-window "Modified resources" | get-button $TLA-BUTTON-OK | click
+} -finally {
+	DeleteSpecNew
 }
 
-
-get-menu -path "File/Parse Spec" | click
-get-window "Modified resources" | get-button OK | click
-
-} -finally
-//Delete Spec
-{DeleteSpecNew}
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Fingerprint.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Fingerprint.test
index aef79f04f7cfe6001293f715bb330045f833be24..c1a4d93e9b7f709794600de3b5c871dab9408eeb 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Fingerprint.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Fingerprint.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _orbhsAJZEemDc-4PKyNT9w
-Runtime-Version: 2.4.2.201905122359
-Save-Time: 6/17/19, 2:45 PM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:08 PM
 Testcase-Type: ecl
 
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac
@@ -18,29 +18,17 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 5"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 1"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 1\n\n=============================================================================\n"]
 	    key-type "M1+s"
     }
 
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
-	get-editor "Model_1" | get-button "Runs TLC on the model." | click
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+	get-editor $TLA-MODEL-ONE | get-button $TLA-BUTTON-RUN-TLC | click
 	wait-run  
 	    
-	with [get-editor "Model_1"] {
-	    get-section General | get-label "Fingerprint collision probability: calculated: 5.4E-20"
-	    get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" | verify-true
-	}
+	get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-RESULTS-SECTION-GENERAL
+			| get-label "Fingerprint collision probability: calculated: 5.4E-20"
 } -finally {
 	DeleteSpecNew
 }
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Invariant _Formula.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Invariant _Formula.test
index d14310f396c75a201bf8549ced5fa5ffda2cc5f1..48bb27902f35954f57d7393dd294245a5068ee50 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Invariant _Formula.test	
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Invariant _Formula.test	
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _7RvKABUnEemG79v6PBILBA
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 9:13 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:08 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -27,50 +27,34 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 1"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 2"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 2\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
-	wait -ms 500
-	get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
+
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
 	
-	with [get-editor "Model_1" | get-section "What to check?" | get-section Invariants] {
+	with [get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-INV] {
 	    click
-	    get-button Add | click
+	    get-button $TLA-BUTTON-ADD | click
 	}
 	with [get-window -class WizardDialog] {
 	    get-text-viewer | type-text "x=1+1"
-	    get-button Finish | click
-	}
-	get-editor "Model_1" | get-section "What to check?" | get-section Invariants | get-table | get-item -path "x=1\\+1" 
-	    | get-property caption | equals "x=1+1" | verify-true
-	
-	with [get-editor "Model_1" | get-section "What to check?" | get-section Invariants] {
+	    get-button $TLA-BUTTON-FINISH | click
+	}	
+	with [get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-INV] {
 	    get-table | select "x=1+1"
-	    get-button Edit | click
+	    get-button $TLA-BUTTON-EDIT | click
 	}
-	get-window -class WizardDialog | get-button Cancel | click
-	with [get-editor "Model_1" | get-section "What to check?" | get-section Invariants] {
+	get-window -class WizardDialog | get-button $TLA-BUTTON-CANCEL | click
+	with [get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-INV] {
 	    get-table | select "x=1+1"
-	    get-button Remove | click
+	    get-button $TLA-BUTTON-REMOVE | click
 	}
 	
-	//get-editor "Model_1" | get-link  | get-property caption | equals "1 error detected" | verify-false
-	
-	get-editor "Model_1" | get-section "What to check?" | get-section Invariants | get-table | get-property itemCount 
-	    | equals 0 | verify-true
-	get-editor "Model_1" | get-button "Checks the model for errors but does not run TLC on it." | click
+	get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-INV
+		| get-table | get-property itemCount | equals 0 | verify-true
+	get-editor $TLA-MODEL-ONE | get-button $TLA-BUTTON-MODEL-CHECK | click
 } -finally {
 	DeleteSpecNew
 }
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Links.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Links.test
index 823fbe789ad047d3e28552dc8fe7fb4d22e1d6bf..66089bf966c0f92cb50ed91a7f1a3d28572ffd35 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Links.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Links.test
@@ -6,7 +6,7 @@ Element-Version: 3.0
 External-Reference: 
 Id: _CTEKoBUbEemG79v6PBILBA
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 6/10/19, 9:04 AM
+Save-Time: 10/14/19, 1:08 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -27,57 +27,48 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 1"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 1"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 1\n\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
-	wait -ms 500
-	get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
+
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
 	
-	with [get-editor "Model_1"] {
-	    get-section "Model description" | get-text-viewer | type-text sample
-	    get-section "What is the model?" | click
-	    get-link "Additional TLC Options" | click
-        get-editbox -after [get-label "Number of worker threads:"] | set-text 2
-        get-tab-folder | get-tab-item "Model Overview" | click
-	    get-link "Additional Spec Options" | click
-	}
-	get-editor "Model_1" | get-section "Additional Definitions" | get-label "Additional Definitions" | get-property caption 
-	    | equals "Additional Definitions" | verify-true
-	with [get-editor "Model_1"] {
-	    get-tab-folder | get-tab-item "Model Overview" | click
-	    get-section "What is the model?" | get-button Edit | click
-	    get-button "Checks the model for errors but does not run TLC on it." | click
-	    get-section "What is the behavior spec?" | get-combo | select "No Behavior Spec"
-	    get-button "Checks the model for errors but does not run TLC on it." | click
-	    get-link "Additional Spec Options" | click
+	with [get-editor $TLA-MODEL-ONE] {
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-DESCRIPTION | get-text-viewer | type-text "sample"
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-MODEL | click
+	    get-link $TLA-MO-ED-OVERVIEW-LINK-TLC | click
+        get-editbox -after [get-label "Number of worker threads:"] | set-text "2"
+        get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+        
+	    get-link $TLA-MO-ED-OVERVIEW-LINK-SPEC | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-AD
+
+	    get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-MODEL | get-button $TLA-BUTTON-EDIT | click
+	    get-button $TLA-BUTTON-MODEL-CHECK | click
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-SPEC | get-combo | select "No Behavior Spec"
+	    get-button $TLA-BUTTON-MODEL-CHECK | click
+	    
+	    get-link $TLA-MO-ED-OVERVIEW-LINK-SPEC | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-SC
+	    
+	    get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+	    get-link $TLA-MO-ED-OVERVIEW-LINK-ECE | click
+	    get-section $TLA-MO-ED-RESULTS-SECTION-PO
 	}
-	get-editor "Model_1" | get-section "State Constraint" | get-label "State Constraint" | get-property caption 
-	    | equals "State Constraint" | verify-true
+	
 	get-editor $TLA-SPEC-NAME | click
-	with [get-editor "Model_1"] {
+	with [get-editor $TLA-MODEL-ONE] {
 	    click
-	    get-tab-folder | get-tab-item "Model Overview" | click
-		get-link "Additional Spec Options" | click
-	}
-	get-editor "Model_1" | get-section "Model Values" | get-label "Model Values" | get-property caption 
-	    | equals "Model Values" | verify-true
-	with [get-editor "Model_1"] {
-		get-tab-folder | get-tab-item "Model Overview" | click
-		get-link "Additional TLC Options" | click
+	    get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+		get-link $TLA-MO-ED-OVERVIEW-LINK-SPEC | click
+		get-section $TLA-MO-ED-ADDITIONAL-SECTION-MV
+		
+		get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+		get-link $TLA-MO-ED-OVERVIEW-LINK-TLC | click
         get-button "Select randomly" | uncheck
-	    get-button "Checks the model for errors but does not run TLC on it." | click
+	    get-button $TLA-BUTTON-MODEL-CHECK | click
 	}
 } -finally {
 	DeleteSpecNew
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Model_Defaults.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Model_Defaults.test
index 30d9e3fa5b420345fccecbedcf2fd9804ae97796..2cdc0147c3afc303a223ee305fd8b64235f54e6c 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Model_Defaults.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Model_Defaults.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _myVagAP4EemwBd2liJ-qvA
-Runtime-Version: 2.4.0.201902010011
-Save-Time: 6/10/19, 9:48 AM
+Runtime-Version: 2.4.3.201909171500
+Save-Time: 1/6/20, 3:02 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -25,53 +25,38 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 999999999999999999999999999999999999999"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 999999999999999999999999999999"
-	     key-type "M1+s"
-	    }
-	    wait -ms 1000
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 999999999999999999999999999999999999999\n\nNext == x' = x * 999999999999999999999999999999\n\n=============================================================================\n"]
+	    key-type "M1+s"
+    }
 
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
-	with [get-editor "Model_1"] {
-	    get-section "What is the model?" | click
-	    get-section "How to run?" | click
-	}
-	with [get-editor "Model_1"] {
-	    with [get-section "What is the behavior spec?"] {
-	        get-text-viewer | get-property text | equals Init | verify-true
-	        get-text-viewer -after [get-label "Next:"] | get-property text | equals Next | verify-true
-	        get-combo | get-property selection | equals "Initial predicate and next-state" | verify-true
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+
+	with [get-editor $TLA-MODEL-ONE] {
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-MODEL | click
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-RUN | click
+
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-SPEC] {
+	        get-text-viewer | get-property text | equals "Init" | verify-true
+	        get-text-viewer -after [get-label "Next:"] | get-property text | equals "Next" | verify-true
+	        get-combo | get-property selection | equals "Initial predicate and next-state relation" | verify-true
 	    }
-	}
-	
-	with [get-editor "Model_1"] {
-	    get-tab-folder | get-tab-item "Model Overview" | click
-		get-link "Additional Spec Options" | click
-		get-label "Spec Options" | get-property caption | equals "Spec Options" | verify-true
-	    get-section "Additional Definitions" | click
-	    get-section "State Constraint" | click
-	    get-section "Model Values" | click
-	    get-section "Definition Override" | click
-	    get-section "Action Constraint" | click
-	    get-section "Additional Definitions" | click
-	    get-section "Definition Override" | click
-	    get-section "Model Values" | click
-	    get-section "State Constraint" | click
-	    get-section "Action Constraint" | click | get-text-viewer | get-property text | equals "" | verify-true
-	}
-	with [get-editor "Model_1"] {
-	    get-tab-folder | get-tab-item "Model Overview" | click
-		get-link "Additional TLC Options" | click
+
+	    get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+		get-link $TLA-MO-ED-OVERVIEW-LINK-SPEC | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-AD | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-SC | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-MV | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-DO | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-AC | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-AD | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-DO | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-MV | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-SC | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-AC | click | get-text-viewer | get-property text | equals "" | verify-true
+
+	    get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+		get-link $TLA-MO-ED-OVERVIEW-LINK-TLC | click
         get-button "Model-checking mode" | get-property selected | equals true | verify-true
         get-text-viewer | get-property text | equals "" | verify-true
         get-button "Depth-first" | get-property selected | equals false | verify-true
@@ -85,7 +70,6 @@ try -command {
         get-button "Defer verification of temporal properties (liveness) to the end of model checking to reduce overall model checking time. Liveness violations will be found late compared to invariant violations. In other words check liveness only once on the complete state space." 
             | get-property selected | equals false | verify-true
         get-button "Select randomly" | get-property selected | equals true | verify-true
-        get-editbox -after [get-label "Fingerprint seed index:"] | get-property text | equals "0.0" | verify-true
         get-editbox -after [get-label "Log base 2 of number of disk storage files:"] | get-property text | equals "1.0" 
             | verify-true
         get-editbox -after [get-label "Cardinality of largest enumerable set:"] | get-property text 
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Model_Results_Defaults.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Model_Results_Defaults.test
index 937891e2f6d483e26878172257e2b55a6891e446..a4812ad461fdbfbcb2388f6dcc00a7e7e7260d26 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Model_Results_Defaults.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Model_Results_Defaults.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _s4DEYBXnEemrGZBXFuwIoA
-Runtime-Version: 2.4.2.201905122359
-Save-Time: 6/19/19, 9:27 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:09 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -25,48 +25,34 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 1"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 2"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 2\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
 	wait -ms 500
 	get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
-	
-	with [get-editor "Model_1"] {
-	    get-section "Model description" | get-text-viewer | type-text "this is a test"
-	    with [get-tab-folder] {
-	        get-tab-item "Model Checking Results" | click
-	    }
-	}
-	with [get-editor "Model_1"] {
-	    get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" | verify-true
-	    with [get-section General] {
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+
+	with [get-editor $TLA-MODEL-ONE] {
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-DESCRIPTION | get-text-viewer | type-text "this is a test"
+
+		get-link $TLA-MO-ED-OVERVIEW-LINK-ECE | click
+	    with [get-section $TLA-MO-ED-RESULTS-SECTION-GENERAL] {
 	    	get-label "Awaiting first run..."
 	        verify-error {get-label "Not running"}
 	        verify-error {get-link "No errors"}
 	    }
-	    get-section "Statistics" | get-editbox -after [get-label "Actions at"] | get-property text | equals "" | verify-true
-	    get-section "Evaluate Constant Expression" | get-editbox -after [get-label "Expression:"] | get-property text 
+	    get-section $TLA-MO-ED-RESULTS-SECTION-STATS | get-editbox -after [get-label "Sub-actions of next-state"] | get-property text | equals "" | verify-true
+	    get-section $TLA-MO-ED-RESULTS-SECTION-ECE | get-editbox -after [get-label "Expression:"] | get-property text 
 	        | equals "" | verify-true
-	    get-section "User Output" | get-text-viewer | get-property text | equals "No output is available" | verify-true
-	    get-section "Progress Output" | get-text-viewer | get-property text | equals "No output is available" | verify-true
-	    get-section "Statistics" | click
-	    get-section "Evaluate Constant Expression" | click
-	    get-section "User Output" | click
-	    get-section "General" | click
-	    get-section "Progress Output" | click
-	    get-button "Checks the model for errors but does not run TLC on it." | click
+	    get-section $TLA-MO-ED-RESULTS-SECTION-UO | get-text-viewer | get-property text | equals "No output is available" | verify-true
+	    get-section $TLA-MO-ED-RESULTS-SECTION-PO | get-text-viewer | get-property text | equals "No output is available" | verify-true
+	    get-section $TLA-MO-ED-RESULTS-SECTION-STATS | click
+	    get-section $TLA-MO-ED-RESULTS-SECTION-ECE | click
+	    get-section $TLA-MO-ED-RESULTS-SECTION-UO | click
+	    get-section $TLA-MO-ED-RESULTS-SECTION-GENERAL | click
+	    get-section $TLA-MO-ED-RESULTS-SECTION-PO | click
+	    get-button $TLA-BUTTON-MODEL-CHECK | click
 	}
 } -finally {
 	DeleteSpecNew
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Multiple_Models.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Multiple_Models.test
index 30b00a496d7782a2c155fc8bcd5d5b35ddfdd004..8b811cc69aa2fc4f9302fa2e77bb62efeec5ed94 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Multiple_Models.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Multiple_Models.test
@@ -6,7 +6,7 @@ Element-Version: 3.0
 External-Reference: 
 Id: _3CVCoAMFEemtrbArmQOOJA
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 3/25/19, 11:46 AM
+Save-Time: 10/14/19, 11:58 AM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -25,32 +25,23 @@ Entry-Name: .content
 //Create Spec
 OpenTLACreateNew
 
-//try -command {
 //Create 10 Models
 CreateTenNewModels
 wait -ms 200
-  
-  
-get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" | verify-true
+    
 get-menu -path "File/Parse Spec" | click
 get-menu -path "File/Parse Module" | click
 
-  
-
-get-view "Spec Explorer" | get-tree | select $TLA-TREE-NAME | get-menu -path Delete | click
+get-view $TLA-VIEW-SPEC-EXPLORER | get-tree | select $TLA-TREE-NAME | get-menu -path "Delete" | click
 get-window "Delete specification?" 
     | get-label "Do you really want the Toolbox to forget the specification new and delete all its models?" 
     | get-property className | equals "org.eclipse.swt.widgets.Label" | verify-true
-get-window "Delete specification?" | get-button Yes | click
+get-window "Delete specification?" | get-button "Yes" | click
 with [get-window "Save Resources" | get-button "Select All"] {
     get-property enablement | equals true | verify-true
-    get-property caption | equals "&Select All" | verify-true
 }
-get-window "Save Resources" | get-button [ get-by-os -default "Save Selected" -win "OK" ] | click
+get-window "Save Resources" | get-button [ get-by-os -default "Save Selected" ] | click
 
 wait -ms 2000
 
-
-
-
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Multiple_Models_Description.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Multiple_Models_Description.test
index 18ee795c98dc853ac5fbce277f27c47faf9cdd3a..a75878004ada9c908d44b3a4ac1a0390184e65df 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Multiple_Models_Description.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Multiple_Models_Description.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _DliAUAMNEemtrbArmQOOJA
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 9:13 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:09 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -29,14 +29,7 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 2
-	    type-text "Init == x = 0"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x + 1"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 0\n\nNext == x' = x + 1\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
 	
@@ -45,32 +38,32 @@ try -command {
 	wait -ms 1200
 	//new \\[ new.tla \\]/models
 	
-	get-view "Spec Explorer" | get-tree | get-item -path $TLA-MODEL-TREE-NAME | get-property childCount | equals 10 
+	get-view $TLA-VIEW-SPEC-EXPLORER | get-tree | get-item -path $TLA-MODEL-TREE-NAME | get-property childCount | equals 10 
 	    | verify-true
 	
-	with [get-editor "Model_10" | get-section "Model description" | get-text-viewer] {
-	    type-text TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
+	with [get-editor "Model_10" | get-section $TLA-MO-ED-OVERVIEW-SECTION-DESCRIPTION | get-text-viewer] {
+	    type-text "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT"
 	    key-type Enter
-	    type-text LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
+	    type-text "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL"
 	    key-type Enter
-	    type-text AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+	    type-text "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
 	    key-type Enter
-	    type-text PLUS
+	    type-text "PLUS"
+	}
+	get-view $TLA-VIEW-SPEC-EXPLORER | get-tree | select $TLA-MODEL-TEN | get-menu -path "Clone" | click
+	with [get-window "Clone model..."] {
+		get-label "Please input the new name of the model"
+		get-button $TLA-BUTTON-CANCEL | click
 	}
-	get-view "Spec Explorer" | get-tree | select $TLA-MODEL-TEN | get-menu -path Clone | click
-	get-window "Clone model..." | get-label "Please input the new name of the model" | get-property caption 
-	    | equals "Please input the new name of the model" | verify-true
-	get-window "Clone model..." | get-button Cancel | click
 	get-menu -path "TLC Model Checker/Run model" | click
-	//get-window "TLC run for Model_10" | get-label "Running TLC model checker" | get-property caption 
-	 //   | equals "Running TLC model checker" | verify-true
+	//get-window "TLC run for Model_10" | get-label "Running TLC model checker"
 	//TODO
 	
-	get-editor "Model_10" | get-button "Stops the current TLC model checker run." | click  
+	get-editor "Model_10" | get-button $TLA-BUTTON-CANCEL-TLC | click  
 	
 	wait-run
 	
-	get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" | verify-true
+	get-label $TLA-MODEL-EDITOR-TAB-RESULTS
 } -finally {
 	DeleteSpecNew
 }
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_NoFormula_Defaults.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_NoFormula_Defaults.test
index 415d0f26772a022cd8e8a0d198aeea640d2aa5aa..19b51637841ba593040a4f14e8ccc675ffcfa910 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_NoFormula_Defaults.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_NoFormula_Defaults.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _ntQ8oBB4EemUS_ZdBJsvQg
-Runtime-Version: 2.4.2.201905122359
-Save-Time: 6/12/19, 10:56 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 11:58 AM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -23,66 +23,56 @@ Entry-Name: .content
 OpenTLACreateNew
 
 try -command {
-	get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
 
     wait -ms 500
 
-	with [get-editor "Model_1"] {
-	    get-section "General (\"What is the behavior spec?\" on \"Model Overview\" page has no behavior spec)" 
-	        | get-label "General (\"What is the behavior spec?\" on \"Model Overview\" page has no behavior spec)" 
-	        | get-property enablement | equals false | verify-true
-	    get-section "Statistics (\"What is the behavior spec?\" on \"Model Overview\" page has no behavior spec)" 
-	        | get-label "Statistics (\"What is the behavior spec?\" on \"Model Overview\" page has no behavior spec)" 
-	        | get-property enablement | equals false | verify-true
+	with [get-editor $TLA-MODEL-ONE] {
+		let [val labelText [concat $TLA-MO-ED-RESULTS-SECTION-GENERAL " (\"" $TLA-MO-ED-OVERVIEW-SECTION-SPEC "\" on \"" $TLA-MODEL-EDITOR-TAB-OVERVIEW "\" page has no behavior spec)"]] {
+		    get-section $labelText | get-label $labelText | get-property enablement | equals false | verify-true
+		}
+		let [val labelText [concat $TLA-MO-ED-RESULTS-SECTION-STATS " (\"" $TLA-MO-ED-OVERVIEW-SECTION-SPEC "\" on \"" $TLA-MODEL-EDITOR-TAB-OVERVIEW "\" page has no behavior spec)"]] {
+		    get-section $labelText | get-label $labelText | get-property enablement | equals false | verify-true
+		}
 	}
 	
     wait -ms 1000
     
-	with [get-editor "Model_1"] {
-	    get-tab-folder | get-tab-item "Model Overview" | click
-	    get-section "Model description" | get-text-viewer | type-text "Model without any variables or formulas"
-	}
-	
-	with [get-editor "Model_1"] {
-	    with [get-section "What is the behavior spec?"] {
+	with [get-editor $TLA-MODEL-ONE] {
+	    get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-DESCRIPTION | get-text-viewer | type-text "Model without any variables or formulas"
+
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-SPEC] {
 	    	get-combo | get-combo-items | to-list | length | equals 1 | verify-true
 	    }
-	    get-section "What to check? (\"What is the behavior spec?\" above has no behavior spec)" 
-	        | get-label "What to check? (\"What is the behavior spec?\" above has no behavior spec)" 
-	        | get-property enablement | equals false | verify-true
-	}
-	
-	with [get-editor "Model_1"] {
-	    get-section "What is the model?" | click
-	    get-section "How to run?" | click
-		get-link "Additional Spec Options" | click
-	    get-section "Additional Definitions" | click
-	    get-section "State Constraint" | click
-	    get-section "Model Values" | click
-	    get-section "Definition Override" | click
-	    get-section "Action Constraint" | click
-		get-tab-folder | get-tab-item "Model Overview" | click
-		get-link "Additional TLC Options" | click
+	    
+	    let [val labelText [concat $TLA-MO-ED-OVERVIEW-SECTION-CHECK " (\"" $TLA-MO-ED-OVERVIEW-SECTION-SPEC "\" above has no behavior spec)"]] {
+		    get-section $labelText | get-label $labelText | get-property enablement | equals false | verify-true
+	    }
+
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-MODEL | click
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-RUN | click
+		get-link $TLA-MO-ED-OVERVIEW-LINK-SPEC | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-AD | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-SC | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-MV | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-DO | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-AC | click
+		get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+		get-link $TLA-MO-ED-OVERVIEW-LINK-TLC | click
 	    get-link "1 message detected" | click
-	}
-	
-	with [get-editor "Model_1"] {
+
 	    with [get-link "1 message detected"] {
-	        get-property caption | equals "1 message detected" | verify-true
-	        get-property toltip 
-	            | equals "\"What is the behavior spec?\" automatically set to \"No Behavior Spec\" because spec has no declared variables." 
+	        get-property toltip
+	            | equals [concat "\"" $TLA-MO-ED-OVERVIEW-SECTION-SPEC "\" automatically set to \"No Behavior Spec\" because spec has no declared variables."]
 	            | verify-true
 	    }
-	    get-button "Stops the current TLC model checker run." | get-property enablement | equals false 
-	        | verify-true
+	    get-button $TLA-BUTTON-CANCEL-TLC | get-property enablement | equals false | verify-true
 	}
 
 	get-menu -path "File/Parse Module" | click
-	get-view "Parsing Errors" | get-expand-bar | get-item -path "TLA\\+ Parser Error" | get-editbox | get-property text 
+	get-view $TLA-VIEW-PARSING-ERRORS | get-expand-bar | get-item -path "TLA\\+ Parser Error" | get-editbox | get-property text 
 	    | equals "Could not find module" | verify-true
 	
 	get-menu -path "File/Parse Spec" | click
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Open_More_Editors.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Open_More_Editors.test
index ce1b6466b3e415d9bc7f6647490454638c9f7648..2a1e73c6d8784d8dc28c1096f5022f6db61b2ca5 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Open_More_Editors.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Open_More_Editors.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _5O_HkgPuEemwBd2liJ-qvA
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 9:13 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:10 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -25,46 +25,30 @@ Entry-Name: .content
 OpenTLACreateNew
 
 try -command {
-with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-    key-type Down
-    type-text "EXTENDS Naturals"
-    key-type Enter
-    type-text "VARIABLE x"
-    key-type Enter -times 1
-    type-text "Init == x = 0"
-    key-type Enter -times 2
-    type-text "Next == x' = x - 1"
-     key-type "M1+s"
+	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 0\n\nNext == x' = x - 1\n=============================================================================\n"]
+	    key-type "M1+s"
     }
-
-
-get-menu -path "TLC Model Checker/New Model..." | click
-get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-    | equals "Please input the name of the model to create" | verify-true
-with [get-window "New model..."] {
-    get-editbox -after [get-label "Please input the name of the model to create"] | set-text saved
-    get-button OK | click
+	
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	with [get-window $TLA-DIALOG-TITLE-NEW-MODEL] {
+	    get-editbox -after [get-label "Please input the name of the model to create"] | set-text "saved"
+	    get-button $TLA-BUTTON-OK | click
+	}
+	
+	wait -ms 1000
+	
+	get-menu -path "Window/New Editor..." | click
+	get-menu -path "Window/Quick Access..." | click
+	get-window -class TLAFilteredItemsSelectionDialog | get-table | select "saved"
+	get-window -class TLAFilteredItemsSelectionDialog | get-label "Select an item to open (? = any character, * = any string):"
+	get-window -class TLAFilteredItemsSelectionDialog | get-button $TLA-BUTTON-OK | click
+	get-menu -path "Window/Reset Window Layout" | click
+	get-window "Reset Perspective" | get-label "Do you want to reset the current Specification perspective to its defaults?"
+	    
+	get-window "Reset Perspective" | get-button [ get-by-os -default "Reset Perspective" ] | click
+} -finally {
+	DeleteSpecNew
 }
 
-wait -ms 1000
-
-get-menu -path "Window/New Editor..." | click
-get-menu -path "Window/Quick Access..." | click
-get-window -class TLAFilteredItemsSelectionDialog | get-table | select saved
-get-window -class TLAFilteredItemsSelectionDialog 
-    | get-label "Select an item to open (? = any character, * = any string):" | get-property caption 
-    | equals "&Select an item to open (? = any character, * = any string):" | verify-true
-get-window -class TLAFilteredItemsSelectionDialog | get-button OK | click
-get-menu -path "Window/Reset Window Layout" | click
-get-window "Reset Perspective" 
-    | get-label "Do you want to reset the current Specification perspective to its defaults?" | get-property caption 
-    | equals "Do you want to reset the current Specification perspective to its defaults?" | verify-true
-    
-
-get-window "Reset Perspective" | get-button [ get-by-os -default "Reset Perspective" -win "Yes" ] | click
-
-
-} -finally
-//Delete Spec
-{DeleteSpecNew}
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Open_Saved_Model.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Open_Saved_Model.test
index 0564210393fccf85e0fa0ceb833895b47e162834..5d27b1cc5a654a77b1365029869fed12e68d2317 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Open_Saved_Model.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Open_Saved_Model.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _gPS3MAPrEemwBd2liJ-qvA
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 9:13 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:10 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -28,31 +28,24 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 0"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x - 1"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 0\n\nNext == x' = x - 1\n=============================================================================\n"]
 	    key-type "M1+s"
     }
 
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	with [get-window "New model..."] {
-	    get-editbox -after [get-label "Please input the name of the model to create"] | set-text saved
-	    get-button OK | click
-	}
-	get-editor $TLA-SPEC-NAME | click
-	get-editor saved | close
-	get-menu -path "TLC Model Checker/Open Model/saved" | click
-	
-	with [get-editor saved] {
-	    get-section "What to check?" | get-button Deadlock | uncheck
-	    get-button "Checks the model for errors but does not run TLC on it." | click
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	let [val ModelName -value "saved"] {
+		with [get-window $TLA-DIALOG-TITLE-NEW-MODEL] {
+		    get-editbox -after [get-label "Please input the name of the model to create"] | set-text $ModelName
+		    get-button $TLA-BUTTON-OK | click
+		}
+		get-editor $TLA-SPEC-NAME | click
+		get-editor $ModelName | close
+		get-menu -path [concat "TLC Model Checker/Open Model/" $ModelName] | click
+		
+		with [get-editor $ModelName] {
+		    get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK | get-button $TLA-BUTTON-DEADLOCK | uncheck
+		    get-button $TLA-BUTTON-MODEL-CHECK | click
+		}
 	}
 } -finally {
 	DeleteSpecNew
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Property_Formula.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Property_Formula.test
index 2bdb98776661944f6287b6e3c192bed1e3d9eb4f..b0fd6e75c170d9239b17eaa5e94b61cd03b84541 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Property_Formula.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Property_Formula.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _EdNeQBUsEemG79v6PBILBA
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 9:13 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:10 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -28,56 +28,44 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 1"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 2"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 2\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
-	wait -ms 500
-	get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
 
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
 
-	with [get-editor "Model_1" | get-section "What to check?"] {
-	    get-section Properties | click
-	    with [get-section Invariants] {
+
+	with [get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK] {
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-PROP | click
+	    with [get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-INV] {
 	        click
 	        click
 	    }
-	    get-section Properties | get-button Add | click
+	    get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-PROP | get-button $TLA-BUTTON-ADD | click
 	}
 	with [get-window -class WizardDialog] {
 	    get-text-viewer | type-text "x=1+x"
-	    get-button Finish | click
+	    get-button $TLA-BUTTON-FINISH | click
 	}
-	get-editor "Model_1" | get-section "What to check?" | get-section Properties | get-table | get-item -path "x=1\\+x" 
-	    | get-property caption | equals "x=1+x" | verify-true
-	with [get-editor "Model_1" | get-section "What to check?" | get-section Properties] {
+
+	with [get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-PROP] {
 	    get-table | select "x=1+x"
-	    get-button Edit | click
+	    get-button $TLA-BUTTON-EDIT | click
 	}
 	with [get-window -class WizardDialog] {
 	    with [get-text-viewer] {
 	        key-type Right -times 2
-	        type-text 3
+	        type-text "3"
 	    }
-	    get-button Finish | click
+	    get-button $TLA-BUTTON-FINISH | click
+	}
+	
+	with [get-editor $TLA-MODEL-ONE | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK | get-section $TLA-MO-ED-OVERVIEW-SECTION-CHECK-PROP] {
+		get-button $TLA-BUTTON-REMOVE | click
+		get-table | get-property itemCount | equals 0 | verify-true
 	}
-	get-editor "Model_1" | get-section "What to check?" | get-section Properties | get-table | get-item -path "x=31\\+x" 
-	    | get-property caption | equals "x=31+x" | verify-true
-	get-editor "Model_1" | get-section "What to check?" | get-section Properties | get-button Remove | click
-	get-editor "Model_1" | get-section "What to check?" | get-section Properties | get-table | get-property itemCount 
-	    | equals 0 | verify-true
-	get-editor "Model_1" | get-button "Checks the model for errors but does not run TLC on it." | click
+	get-editor $TLA-MODEL-ONE | get-button $TLA-BUTTON-MODEL-CHECK | click
 } -finally {
 	DeleteSpecNew
 }
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Run_Details.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Run_Details.test
index 20dfc0ffd1dbacda3b58e9bef840cc60aec7553b..f1f99ae1b9bbbeeb2bf62f406c080a8b1b83d246 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Run_Details.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Run_Details.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _8o7w0APsEemwBd2liJ-qvA
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 9:13 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:10 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -30,45 +30,37 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 0"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x - 1"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 0\n\nNext == x' = x - 1\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
-	wait -ms 500
 	
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	with [get-window "New model..."] {
-	    get-editbox -after [get-label "Please input the name of the model to create"] | set-text saved
-	    get-button "OK" | click
-	}
-	
-	get-editor $TLA-SPEC-NAME | click
-	get-menu -path "TLC Model Checker/Run model" | click
-	wait -ms 1000
-
-	get-window "TLC run for saved" | get-button "Details >>" | click
-	wait -ms 1000
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	let [val ModelName -value "saved"] {
+		with [get-window $TLA-DIALOG-TITLE-NEW-MODEL] {
+		    get-editbox -after [get-label "Please input the name of the model to create"] | set-text $ModelName
+		    get-button $TLA-BUTTON-OK | click
+		}
+		
+		get-editor $TLA-SPEC-NAME | click
+		get-menu -path "TLC Model Checker/Run model" | click
+		wait -ms 1000
 	
-	get-window "TLC run for saved" | get-label "TLC run for saved" | get-property caption | equals "TLC run for saved" 
-	    | verify-true
-	wait -ms 1000
-	
-	get-window "TLC run for saved" | get-button Cancel | click
+		with [get-window [concat "TLC run for " $ModelName]] {
+			get-button "Details >>" | click
+			
+			wait -ms 1000
+			
+			get-button $TLA-BUTTON-CANCEL | click
+		}
 
-	// note wait-run must be on the model page to work
-	get-editor saved | click
-	wait-run
-	
-	get-editor saved | get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" 
-	    | verify-true    
+		with [get-editor $ModelName] {
+			click
+			
+			wait-run
+			
+			get-label $TLA-MODEL-EDITOR-TAB-RESULTS
+		}	
+	}
 } -finally {
 	DeleteSpecNew
 }
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Spec_Properties.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Spec_Properties.test
index 4f5d471c83917de7cb58ccf9b3358363942caf26..f47e6e8df43cfff3c60e95183a8d96dfeaa68fdf 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Spec_Properties.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Spec_Properties.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _Lbbs8AMKEemtrbArmQOOJA
-Runtime-Version: 2.3.0.201806262310
-Save-Time: 1/9/19 2:15 PM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/13/19, 4:10 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -24,13 +24,13 @@ Entry-Name: .content
 OpenTLACreateNew
 
 try -command {
-get-view "Spec Explorer" | get-tree | select $TLA-MODEL-NEW | get-menu -path "Show in History" | click
+	get-view $TLA-VIEW-SPEC-EXPLORER | get-tree | select $TLA-MODEL-NEW | get-menu -path "Show in History" | click
+	
+	get-view "History" | get-button "Refresh" | get-property kind | equals Tool | verify-true
+	get-view $TLA-VIEW-SPEC-EXPLORER | click
+	get-view "History" | close
+} -finally {
+	DeleteSpecNew
+}
 
-get-view History | get-button Refresh | get-property kind | equals Tool | verify-true
-get-view "Spec Explorer" | click
-get-view History | close
-
-} -finally
-//Delete Spec
-{DeleteSpecNew}
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Spec_Properties_Valid.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Spec_Properties_Valid.test
index beacd9a886d69ddf8667a59bfbae48c5e088b664..e17cc7548398921d79ac750571caca861a9e9f40 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Spec_Properties_Valid.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_Spec_Properties_Valid.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _6Vm88APkEemwBd2liJ-qvA
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 9:13 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:10 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -23,24 +23,17 @@ Entry-Name: .content
 
 OpenTLACreateNew
 try -command {
-with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-    key-type Down
-    type-text "EXTENDS Naturals"
-    key-type Enter
-    type-text "VARIABLE x"
-    key-type Enter -times 1
-    type-text "Init == x = 1"
-    key-type Enter -times 2
-    type-text "Next == x' = x * 1"
-     key-type "M1+s"
+	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 1\n\n=============================================================================\n"]
+	    key-type "M1+s"
     }
     wait -ms 500
-get-view "Spec Explorer" | get-tree | select $TLA-TREE-NAME | get-menu -path Properties | click
-get-window "Properties for new" | get-label "Specification Properties" | get-property caption 
-    | equals "Specification Properties" | verify-true
-get-window "Properties for new" | get-button "Apply and Close" | click
+    
+	get-view $TLA-VIEW-SPEC-EXPLORER | get-tree | select $TLA-TREE-NAME | get-menu -path "Properties" | click
+	get-window "Properties for new" | get-button "Apply and Close" | click
+
+} -finally {
+	DeleteSpecNew
+}
 
-} -finally
-//Delete Spec
-{DeleteSpecNew}
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_TLA_Options_Defaults.test b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_TLA_Options_Defaults.test
index 4cc287610eb431248b27e8f1c51f03db03cee20e..01a781200482791137ab0a9306747a08803d829b 100644
--- a/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_TLA_Options_Defaults.test
+++ b/org.lamport.tla.toolbox.product.uitest/Functional/TLA_Functional_TLA_Options_Defaults.test
@@ -6,7 +6,7 @@ Element-Version: 3.0
 External-Reference: 
 Id: _HJaIUBU4EemG79v6PBILBA
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 6/10/19, 9:48 AM
+Save-Time: 10/14/19, 1:11 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -24,77 +24,56 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 1"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 2"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 1\n\nNext == x' = x * 2\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
-	wait -ms 500
-	get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
+
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
 	
 	
-	with [get-editor "Model_1"] {
-		get-section "What is the model?" | click
-		get-link "Additional Spec Options" | click
-		get-label "Spec Options" | get-property caption | equals "Spec Options" | verify-true
-		get-tab-folder | get-tab-item "Model Overview" | click
-		get-section "How to run?" | click
-		get-link "Additional TLC Options" | click
+	with [get-editor $TLA-MODEL-ONE] {
+		get-section $TLA-MO-ED-OVERVIEW-SECTION-MODEL | click
+		get-link $TLA-MO-ED-OVERVIEW-LINK-SPEC | click
+		get-tab-folder | get-tab-item $TLA-MODEL-EDITOR-TAB-OVERVIEW | click
+		get-section $TLA-MO-ED-OVERVIEW-SECTION-RUN | click
+		get-link $TLA-MO-ED-OVERVIEW-LINK-TLC | click
 	    with [get-button "Model-checking mode"] {
-	        get-property caption | equals "Model-checking mode" | verify-true
 	        get-property selected | equals true | verify-true
 	    }
-	    get-label "View:" | get-property caption | equals "View:" | verify-true
-	    get-button "Depth-first" | get-property caption | equals "Depth-first" | verify-true
-	    get-label "Depth:" | get-property caption | equals "Depth:" | verify-true
+	    get-label "View:"
+	    get-button "Depth-first"
+	    get-label "Depth:"
 	    with [get-button "Simulation mode"] {
-	        get-property caption | equals "Simulation mode" | verify-true
 	        get-property selected | equals false | verify-true
 	    }
-	    get-label "Maximum length of the trace:" | get-property caption | equals "Maximum length of the trace:" 
-	        | verify-true
-	    get-label "Seed:" | get-property caption | equals "Seed:" | verify-true
-	    get-label "Aril:" | get-property caption | equals "Aril:" | verify-true
-	    get-label "Verify temporal properties upon termination only:" | get-property caption 
-	        | equals "Verify temporal properties upon termination only:" | verify-true
+	    get-label "Maximum length of the trace:"
+	    get-label "Seed:"
+	    get-label "Aril:"
+	    get-label "Verify temporal properties upon termination only:"
 	    with [get-button "Defer verification of temporal properties (liveness) to the end of model checking to reduce overall model checking time. Liveness violations will be found late compared to invariant violations. In other words check liveness only once on the complete state space."] {
 	        get-property tooltip 
 	            | equals "Defer verification of temporal properties (liveness) to the end of model checking to reduce overall model checking time. Liveness violations will be found late compared to invariant violations. In other words check liveness only once on the complete state space." 
 	            | verify-true
 	        get-property selected | equals false | verify-true
 	    }
-	    get-label "Fingerprint seed index:" | get-property caption | equals "Fingerprint seed index:" | verify-true
+	    get-label "Fingerprint seed index:"
 	    with [get-button "Select randomly"] {
-	        get-property caption | equals "Select randomly" | verify-true
 	        get-property selected | equals true | verify-true
 	    }
 	    get-editbox -after [get-label "Fingerprint seed index:"] | get-property enablement | equals false | verify-true
 	    get-editbox -after [get-label "Log base 2 of number of disk storage files:"] | get-property text | equals "1.0" 
 	        | verify-true
-	    get-label "Log base 2 of number of disk storage files:" | get-property caption 
-	        | equals "Log base 2 of number of disk storage files:" | verify-true
-	    get-label "Cardinality of largest enumerable set:" | get-property caption 
-	        | equals "Cardinality of largest enumerable set:" | verify-true
+	    get-label "Log base 2 of number of disk storage files:"
+	    get-label "Cardinality of largest enumerable set:"
 	    get-editbox -after [get-label "Cardinality of largest enumerable set:"] | get-property text | equals "1000000.0" 
 	        | verify-true
-	    get-label "Visualize state graph after completion of model checking:" | get-property caption 
-	        | equals "Visualize state graph after completion of model checking:" | verify-true
+	    get-label "Visualize state graph after completion of model checking:"
 	    get-button "Draw the state graph after completion of model checking provided the state graph is sufficiently small (cannot handle more than a few dozen states and slows down model checking)." 
 	        | get-property selected | equals false | verify-true
-	    get-label "JVM arguments:" | get-property caption | equals "JVM arguments:" | verify-true
+	    get-label "JVM arguments:"
 	    get-editbox -after [get-label "JVM arguments:"] | get-property text | equals "" | verify-true
-	    get-label "TLC command line parameters:" | get-property caption | equals "TLC command line parameters:" 
-	        | verify-true
+	    get-label "TLC command line parameters:"
 	    get-editbox -after [get-label "TLC command line parameters:"] | get-property text | equals "" | verify-true
 	}
 } -finally {
diff --git a/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA.Invalid.File.test b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA.Invalid.File.test
index d6ba3b3195e1e0f7e40322fdafb055bf7468d84e..737c89c01d7558aac4795fc7ceb1124c4064bf0e 100644
--- a/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA.Invalid.File.test
+++ b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA.Invalid.File.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _RNcosP5FEeilFekyyVb9lA
-Runtime-Version: 2.3.0.201806262310
-Save-Time: 1/9/19 2:16 PM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 11:48 AM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -20,19 +20,18 @@ Content-Type: text/ecl
 Entry-Name: .content
 
 try -command {
-get-menu -path "File/Open Spec/Add New Spec..." | click
-get-window -class WizardDialog | get-editbox -after [get-label "New TLA+ Specification"] | get-property text 
-    | equals "Creates a new TLA+ specification\n"
-    + "Enter a complete file name like c:\\jones\\specs\\foo.tla or click on Browse." | verify-true
-get-window -class WizardDialog | get-editbox -after [get-label "Root-module file:"] | set-text $TLA-BADFile
-with [get-window -class WizardDialog] {
-    get-editbox -after [get-label "New TLA+ Specification"] | get-property text 
-        | equals "Root file name should have a file-system path and extension .tla" | verify-true
-    get-button Finish | get-property enablement | equals false | verify-true
+	get-menu -path "File/Open Spec/Add New Spec..." | click
+	get-window -class WizardDialog | get-editbox -after [get-label "New TLA+ Specification"] | get-property text 
+	    | equals "Creates a new TLA+ specification\n"
+	    + "Enter a complete file name like c:\\jones\\specs\\foo.tla or click on Browse." | verify-true
+	get-window -class WizardDialog | get-editbox -after [get-label "Root-module file:"] | set-text $TLA-BADFile
+	with [get-window -class WizardDialog] {
+	    get-editbox -after [get-label "New TLA+ Specification"] | get-property text 
+	        | equals "Root file name should have a file-system path and extension .tla" | verify-true
+	    get-button $TLA-BUTTON-FINISH | get-property enablement | equals false | verify-true
+	}
+} -finally {
+	get-window -class WizardDialog | get-button $TLA-BUTTON-CANCEL | click
 }
 
-} -finally
-{
-get-window -class WizardDialog | get-button Cancel | click
-}
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Model_Content.test b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Model_Content.test
index 1911415747313a993459e860da3a0553119002c1..4d656b563fbb5073bf30d6f95f103dc39a05b38d 100644
--- a/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Model_Content.test
+++ b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Model_Content.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _GbDfMAJNEemDc-4PKyNT9w
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 9:13 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 12:57 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -22,23 +22,14 @@ Entry-Name: .content
 //Create Spec
 OpenTLACreateNew
 
+// This test should be renamed - there is no model content existing that could be invalid.
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x y"
-	    key-type Enter -times 2
-	    type-text "Init == x = 1"
-	    key-type Enter -times 2
-	    type-text "Init == y = 5"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 1"
-	    key-type "M1+s"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x y\nInit == x = 1\n\nInit == y = 5\n\nNext == x' = x * 1\n\n=============================================================================\n"]
+		key-type "M1+s"
 	}
-    wait -ms 5000
-	get-view "Parsing Errors" | get-expand-bar | get-item -path "TLA\\+ Parser Error" | get-property caption 
-	    | equals "TLA+ Parser Error" | verify-true
+    wait -ms 1500
+	get-view $TLA-VIEW-PARSING-ERRORS | get-expand-bar | get-item -path "TLA\\+ Parser Error"
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
 	    set-caret-pos 1 1
 	    key-type Down -times 2
@@ -47,20 +38,11 @@ try -command {
 	    key-type BackSpace -times 2
 	    key-type Enter
 	}
-	// ldq: this never did anything (there was never a model made) - i have no idea why it's here
-	//		but i commmented out instead of nuking it.
-//	get-menu -path "TLC Model Checker/Run model" | click
-//	wait -ms 1000
-	get-label error | get-property caption | equals error | verify-true
+	get-label "error"
 } -finally {
-	get-view "Spec Explorer" | get-tree | select $TLA-TREE-NAME | get-menu -path Delete | click
-	get-window "Delete specification?" 
-	    | get-label "Do you really want the Toolbox to forget the specification new and delete all its models?" 
-	    | get-property caption 
-	    | equals "Do you really want the Toolbox to forget the specification new and delete all its models?" | verify-true
+	get-view $TLA-VIEW-SPEC-EXPLORER | get-tree | select $TLA-TREE-NAME | get-menu -path Delete | click
 	get-window "Delete specification?" | get-button Yes | click
-	get-window "Save Resource" | get-button "Don't Save" | get-property caption | equals "Do&n't Save" | verify-true
 	get-window "Save Resource" | get-button "Don't Save" | click
-	get-view "Spec Explorer" | get-tree | get-property itemCount | equals 0 | verify-true
+	get-view $TLA-VIEW-SPEC-EXPLORER | get-tree | get-property itemCount | equals 0 | verify-true
 }
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Model_Formula.test b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Model_Formula.test
index 702ac74e3461f049f768e5dc31539e00c8d8e45c..37878be1813e085da6d5c1307b84459b77833d99 100644
--- a/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Model_Formula.test
+++ b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Model_Formula.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _N4SlcAJQEemDc-4PKyNT9w
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 9:13 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 12:59 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -34,35 +34,22 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "VARIABLE y"
-	    key-type Enter -times 2
-	    type-text "Init == x = 1"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 1 + y"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nVARIABLE y\nInit == x = 1\n\nNext == x' = x * 1 + y\n=============================================================================\n"]
 	    key-type "M1+s"
 	}
-	wait -ms 500
-	get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
-	get-editor "Model_1" | get-button "Runs TLC on the model." | click
+
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+	get-editor $TLA-MODEL-ONE | get-button $TLA-BUTTON-RUN-TLC | click
 	
 	wait-run
 	
-	get-view "TLC Errors" | get-editbox -after [get-label "Model_1"] | get-property text 
+	get-view $TLA-VIEW-TLC-ERRORS | get-editbox -after [get-label $TLA-MODEL-ONE] | get-property text 
 	    | equals "current state is not a legal state\n"
 	    + "While working on the initial state:\n"
 	    + "/\\ x = 1\n"
 	    + "/\\ y = null" | verify-true
-	get-view "TLC Errors" | get-section "Error-Trace Exploration" | click
+	get-view $TLA-VIEW-TLC-ERRORS | get-section $TLA-MO-ED-TLCERRORS-SECTION-ETE | click
 } -finally {
 	DeleteSpecNew
 }
diff --git a/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Non_Real_Number.test b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Non_Real_Number.test
index 9f9c8269af3dcfe333202b2bc5d9291d9a02b5df..5b65972809f0384c21dcf4d6e1710630bb5a38dc 100644
--- a/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Non_Real_Number.test
+++ b/org.lamport.tla.toolbox.product.uitest/InvalidTest/TLA_Invalid_Non_Real_Number.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _8r57gAJbEemDc-4PKyNT9w
-Runtime-Version: 2.4.2.201905122359
-Save-Time: 6/12/19, 9:35 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:03 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -24,28 +24,17 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 3"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x - 1.5"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 3\n\nNext == x' = x - 1.5\n=============================================================================\n"]
 	    key-type "M1+s"
     }
 	
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor "Model_1" | get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
-	get-editor "Model_1" | get-button "Runs TLC on the model." | click
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+	get-editor $TLA-MODEL-ONE | get-button $TLA-BUTTON-RUN-TLC | click
 	
 	wait-run
     
-	get-view "TLC Errors" | get-text-viewer | get-property text | equals "TLC can't handle real numbers.\n"
-	    + "1.5" | verify-true
+	get-view $TLA-VIEW-TLC-ERRORS | get-text-viewer | get-property text | equals "TLC can't handle real numbers.\n1.5" | verify-true
 } -finally {
 	DeleteSpecNew
 }
diff --git a/org.lamport.tla.toolbox.product.uitest/TLA.Test.Parameters.ctx b/org.lamport.tla.toolbox.product.uitest/TLA.Test.Parameters.ctx
index e00e56dfbb1ea32bb575d5b3ed311b677a0a8e10..f9115a66082185754a90b22cc2a40964c24b414e 100644
--- a/org.lamport.tla.toolbox.product.uitest/TLA.Test.Parameters.ctx
+++ b/org.lamport.tla.toolbox.product.uitest/TLA.Test.Parameters.ctx
@@ -5,31 +5,79 @@ Element-Name: TLA.Test.Parameters
 Element-Type: context
 Element-Version: 2.0
 Id: _zmZVMP5NEeilFekyyVb9lA
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 5/7/19, 10:32 AM
+Runtime-Version: 2.4.3.201909171500
+Save-Time: 1/10/20, 9:30 AM
 
 ------=_.parameters.context-2e023de5-3294-36a9-ac1d-6701f05a40ee
 Content-Type: text/properties
 Entry-Name: .parameters.context
 
-#Tue May 07 10:32:12 PDT 2019
+#Fri Jan 10 09:30:39 PST 2020
 TLA-Long-Model-Name=thisisaverylongnameforamodel
-TLA-File=new.tla
-TLA-TREE-NAME=new [ new.tla ]
-TLA-TREE-NAME-LONG=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz [ zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.tla ]
-TLA-BAD-DIR=C\:\\foo
-TLA-MODEL-TEN=new [ new.tla ]/models/Model_10
-TLA-File-Long=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.tla
+TLA-MO-ED-TLC-SECTION-CM=Checking Mode
+TLA-MO-ED-TLC-SECTION-PARAM=Parameters
+TLA-BUTTON-EDIT=Edit
 TLA-ADDITIONAL-MODULE-NAME=other
-TLA-MODEL-NEW=new [ new.tla ]/modules/new
-TLA-TREE-NAME-RENAME=new_Copy [ new.tla ]
-TLA-NEW-FILE-RENAME=new_Copy
 TLA-MODEL-ONE=Model_1
 TLA-BADFile=QQQ
-Model-TEST-Name=foo
-TLA-MODEL-ONE-TREE=new [ new.tla ]/models/Model_1
-TLA-MODEL-TREE-NAME=new [ new.tla ]/models
-TLA-ADDITIONAL-MODULE-NAME-FILE=other.tla
+TLA-MO-ED-OVERVIEW-SECTION-CHECK-INV=Invariants
+TLA-MO-ED-ADDITIONAL-SECTION-DO=Definition Override
+TLA-BUTTON-CANCEL=Cancel
+TLA-MO-ED-TLCERRORS-SECTION-ET=Error-Trace
+TLA-BUTTON-EXPLORE=Explore
 TLA-SPEC-NAME=new
+TLA-MO-ED-OVERVIEW-LINK-TLC=Additional TLC Options
+TLA-MODEL-EDITOR-TAB-OVERVIEW=Model Overview
+TLA-MO-ED-OVERVIEW-SECTION-DESCRIPTION=Model description
+TLA-BUTTON-MODEL-CHECK=Checks the model for errors but does not run TLC on it.
+TLA-TREE-NAME-LONG=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz [ zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.tla ]
+TLA-MO-ED-ADDITIONAL-SECTION-AD=Additional Definitions
+TLA-VIEW-PARSING-ERRORS=Parsing Errors
+TLA-MO-ED-TLC-SECTION-CONF=Configuration
+TLA-MO-ED-ADDITIONAL-SECTION-AC=Action Constraint
+TLA-BUTTON-ADD=Add
+TLA-MO-ED-OVERVIEW-SECTION-CHECK-PROP=Properties
+TLA-BUTTON-OK=OK
+TLA-BUTTON-CANCEL-TLC=Stops the current TLC model checker run.
+TLA-MO-ED-ADDITIONAL-SECTION-MV=Model Values
+TLA-MO-ED-TLCERRORS-SECTION-ETE=Error-Trace Exploration
+TLA-MO-ED-OVERVIEW-SECTION-SPEC=What is the behavior spec?
+TLA-MODEL-ONE-TREE=new/models/Model_1
+TLA-ADDITIONAL-MODULE-NAME-FILE=other.tla
+TLA-MO-ED-RESULTS-SECTION-PO=Progress Output
+TLA-MO-ED-RESULTS-SECTION-STATS=Statistics
+TLA-MENU-PATH-FILE-SPEC-EXPLORER=File/Spec Explorer
+TLA-MO-ED-RESULTS-SECTION-ECE=Evaluate Constant Expression
+TLA-MENU-PATH-WINDOW-SPEC-EXPLORER=Window/Spec Explorer
+TLA-MODEL-EDITOR-TAB-RESULTS=Model Checking Results
+TLA-MODEL-EDITOR-TAB-ADDITIONAL=Spec Options
+TLA-MODEL-TEN=new/models/Model_10
+TLA-File-Long=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.tla
+TLA-MODEL-NEW=new/modules/new
+TLA-MO-ED-OVERVIEW-SECTION-RUN=How to run?
+TLA-BUTTON-REMOVE=Remove
+Model-TEST-Name=foo
+TLA-MO-ED-ADDITIONAL-SECTION-SC=State Constraint
+TLA-VIEW-SPEC-EXPLORER=Spec Explorer
+TLA-MO-ED-RESULTS-SECTION-UO=User Output
+TLA-MENU-PATH-NEW-MODEL=TLC Model Checker/New Model...
+TLA-VIEW-TLC-ERRORS=TLC Errors
+TLA-MO-ED-OVERVIEW-SECTION-CHECK=What to check?
+TLA-MO-ED-TLC-SECTION-FEATURES=Features
+TLA-File=new.tla
+TLA-TREE-NAME=new
+TLA-MODEL-EDITOR-TAB-TLC-OPTIONS=TLC Options
+TLA-BAD-DIR=C\:\\foo
+TLA-BUTTON-DEADLOCK=Deadlock
+TLA-MO-ED-OVERVIEW-SECTION-MODEL=What is the model?
+TLA-MO-ED-RESULTS-SECTION-GENERAL=General
+TLA-TREE-NAME-RENAME=new_Copy [ new.tla ]
+TLA-NEW-FILE-RENAME=new_Copy
+TLA-DIALOG-TITLE-NEW-MODEL=New model...
+TLA-MO-ED-OVERVIEW-LINK-ECE=Evaluate Constant Expressions
+TLA-BUTTON-FINISH=Finish
+TLA-MODEL-TREE-NAME=new/models
+TLA-BUTTON-RUN-TLC=Runs TLC on the model.
+TLA-MO-ED-OVERVIEW-LINK-SPEC=Additional Spec Options
 
 ------=_.parameters.context-2e023de5-3294-36a9-ac1d-6701f05a40ee--
diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Close.Open.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Close.Open.test
index da8074277a5795a8c48dadcdcfb5a1a3be2faf24..3a372602937bcb0acd1691604d48cfc6a328a9b1 100644
--- a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Close.Open.test
+++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Close.Open.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _4M7XgP21EeiCTvrXzYZPCg
-Runtime-Version: 2.3.0.201806262310
-Save-Time: 1/14/19 8:12 PM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 12:06 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -23,19 +23,19 @@ Entry-Name: .content
 
 //Create Spec
 OpenTLACreateNew
-try -command {
-//Reopen
-get-menu -path "File/Close Spec" | click
-
 
-get-view "Spec Explorer" | get-tree | select $TLA-TREE-NAME
-get-menu -path "File/Spec Explorer" | click
-get-menu -path "File/Open Spec/new" | click
-get-view "Spec Explorer" | get-tree | get-item -path [concat $TLA-TREE-NAME "/modules"] | get-property caption 
-    | equals modules | verify-true
-      
-} -finally
-//Delete Spec
-{DeleteSpecNew}
+try -command {
+	//Reopen
+	get-menu -path "File/Close Spec" | click
+	
+	get-view $TLA-VIEW-SPEC-EXPLORER | get-tree | select $TLA-TREE-NAME
+	
+	get-menu -path $TLA-MENU-PATH-FILE-SPEC-EXPLORER | click
+	get-menu -path "File/Open Spec/new" | click
+	get-view $TLA-VIEW-SPEC-EXPLORER | get-tree | get-item -path [concat $TLA-TREE-NAME "/modules"] | get-property caption 
+	    | equals "modules" | verify-true
+} -finally {
+	DeleteSpecNew
+}
 
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Delete.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Delete.test
index 78e695bd2d2792ab9dee345fceb973391970c5f5..58045ea328e70152f06e3c22518a077b6e874bbd 100644
--- a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Delete.test
+++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Delete.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _c0C1QP19EeiqL7RHpA20Ww
-Runtime-Version: 2.3.0.201806262310
-Save-Time: 1/15/19 11:11 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 11:50 AM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -23,15 +23,14 @@ Entry-Name: .content
 OpenTLACreateNew
 
 try -command {
-get-view "Spec Explorer" | get-tree | get-item -path $TLA-TREE-NAME | get-property caption 
-    | equals $TLA-TREE-NAME | verify-true
-with [get-label parsed] {
-    get-property "getVisible()" | equals true | verify-true
-    get-property "toString()" | equals "Label { parsed }" | verify-true
+	get-view $TLA-VIEW-SPEC-EXPLORER | get-tree | get-item -path $TLA-TREE-NAME
+	with [get-label "parsed"] {
+	    get-property "getVisible()" | equals true | verify-true
+	    get-property "toString()" | equals "Label { parsed }" | verify-true
+	}
+	get-view $TLA-VIEW-SPEC-EXPLORER | get-tree | select $TLA-TREE-NAME
+} -finally {
+	DeleteSpecNew
 }
-get-view "Spec Explorer" | get-tree | select $TLA-TREE-NAME
 
-} -finally
-//Delete Spec
-{DeleteSpecNew}
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Test.Spec.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Test.Spec.test
index 01a425c6254ce0bfa1919ce1685875a7cea1b0c7..92a0a30be6a42cb5b503830fdbe19faa35db8e85 100644
--- a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Test.Spec.test
+++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Create.Test.Spec.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _Nhf3gP9aEeiWgvGqW2E8Fg
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 9:11 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 12:39 PM
 Testcase-Type: ecl
 
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac
@@ -15,21 +15,21 @@ Entry-Name: .content
 
 //Create Spec
 OpenTLACreateNew
-try -command {
 
-with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-    key-type Down
-    type-text "EXTENDS Naturals"
-    key-type Enter
-    type-text "VARIABLE x"
-    key-type Enter -times 2
-    type-text "Init == x = 0"
-    key-type Enter -times 2
-    type-text "Next == x' = x + 1"
-    key-type "M1+s"
+try -command {
+	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
+	    key-type Down
+	    type-text "EXTENDS Naturals"
+	    key-type Enter
+	    type-text "VARIABLE x"
+	    key-type Enter -times 2
+	    type-text "Init == x = 0"
+	    key-type Enter -times 2
+	    type-text "Next == x' = x + 1"
+	    key-type "M1+s"
+	}
+} -finally {
+	DeleteSpecNew
 }
 
-} -finally
-//Delete Spec
-{DeleteSpecNew}
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.New.Model.Simple.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.New.Model.Simple.test
index 18ab13fd8a84556e5121d8f32993a377a8501e92..68e0d6b87dd62e759f4aac386bd72087a27c56ff 100644
--- a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.New.Model.Simple.test
+++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.New.Model.Simple.test
@@ -6,7 +6,7 @@ Element-Version: 3.0
 External-Reference: 
 Id: _thReYP27EeiCTvrXzYZPCg
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 3/26/19, 11:18 AM
+Save-Time: 10/13/19, 7:21 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -27,16 +27,13 @@ Entry-Name: .content
 OpenTLACreateNew
 
 try -command {
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-editbox -after [get-label "Please input the name of the model to create"] | set-text $Model-TEST-Name
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	get-editor $Model-TEST-Name | get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" 
-	    | verify-true
+	get-menu -path "TLC Model Checker/Run model" | get-property enablement | equals false | verify-true
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-editbox -after [get-label "Please input the name of the model to create"]
+		| set-text $Model-TEST-Name
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
 	
-	
-	get-editor foo | get-button "Checks the model for errors but does not run TLC on it." | click
+	get-editor $Model-TEST-Name | get-button $TLA-BUTTON-MODEL-CHECK | click
 } -finally {
 	DeleteSpecNew
 }
diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Rename.Spec.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Rename.Spec.test
index 3c8f1c996a7540ff05fd2944add72a0a15cf03c3..d25525a087b1c5b76e7b8972700003582625a037 100644
--- a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Rename.Spec.test
+++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Rename.Spec.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _HS58UP2vEeiCTvrXzYZPCg
-Runtime-Version: 2.3.0.201806262310
-Save-Time: 1/14/19 7:29 PM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/13/19, 7:21 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -23,13 +23,12 @@ Entry-Name: .content
 //Create new spec
 OpenTLACreateNew
 
+// This test doesn't actually do any renaming... rename the test!
 try -command {
-get-view "Spec Explorer" | get-tree | select $TLA-TREE-NAME | get-menu -path Rename | click
-get-window "New specification name" | get-label "Please input the new name of the specification" | get-property caption 
-    | equals "Please input the new name of the specification" | verify-true
-get-window "New specification name" | get-button OK | click
+	get-view $TLA-VIEW-SPEC-EXPLORER | get-tree | select $TLA-TREE-NAME | get-menu -path "Rename" | click
+	get-window "New specification name" | get-button $TLA-BUTTON-OK | click
+} -finally {
+	DeleteSpecNew
+}
 
-} -finally
-//Delete Spec
-{DeleteSpecNew}
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Valid.Path.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Valid.Path.test
index aa2b6910d1e98aa4fd85ea1612588ae9cecf1603..48bb5ca9431be555f16bbc22618abedc0bd40eec 100644
--- a/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Valid.Path.test
+++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA.Smoke.Valid.Path.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _lPDvMP18EeiqL7RHpA20Ww
-Runtime-Version: 2.3.0.201806262310
-Save-Time: 1/9/19 12:50 PM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:14 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -19,12 +19,10 @@ Standard Create then Delete. Verify
 Content-Type: text/ecl
 Entry-Name: .content
 
-//new Spec
 try -command {
-OpenTLACreateNew
-} -finally
-{
-//Delete Spec
-DeleteSpecNew
+	OpenTLACreateNew
+} -finally {
+	DeleteSpecNew
 }
+
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Model_Tabs.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Model_Tabs.test
index 04cdc2a3b40ef6d866d618d441988f4a7805c832..cc728f1bc4f25264c4cabd6711fe3f43cc5629f0 100644
--- a/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Model_Tabs.test
+++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Model_Tabs.test
@@ -6,7 +6,7 @@ Element-Version: 3.0
 External-Reference: 
 Id: __NXfoAPwEemwBd2liJ-qvA
 Runtime-Version: 2.4.0.201902010011
-Save-Time: 6/10/19, 9:48 AM
+Save-Time: 10/14/19, 1:04 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -27,41 +27,21 @@ OpenTLACreateNew
 
 try -command {
 	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-	    key-type Down
-	    type-text "EXTENDS Naturals"
-	    key-type Enter
-	    type-text "VARIABLE x"
-	    key-type Enter -times 1
-	    type-text "Init == x = 999999999999999999999999999999999999999"
-	    key-type Enter -times 2
-	    type-text "Next == x' = x * 999999999999999999999999999999"
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 999999999999999999999999999999999999999\n\nNext == x' = x * 999999999999999999999999999999\n\n=============================================================================\n"]
 	    key-type "M1+s"
     }
     wait -ms 1000
 
-	get-menu -path "TLC Model Checker/New Model..." | click
-	get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-	    | equals "Please input the name of the model to create" | verify-true
-	get-window "New model..." | get-button OK | click
-	with [get-editor "Model_1"] {
-		get-label "Model Overview" | get-property caption | equals "Model Overview" | verify-true
-		get-section "What is the model?" | click
-		get-link "Additional Spec Options" | click
-		get-label "Spec Options" | get-property caption | equals "Spec Options" | verify-true
-	    get-section "Additional Definitions" | click
-	    get-section "State Constraint" | click
-	    get-section "Model Values" | click
-	    get-section "Definition Override" | click
-	    get-section "Action Constraint" | click
-	    get-tab-folder | get-tab-item "Model Checking Results" | click
-	}
-	with [get-editor "Model_1"] {
-	    get-label "Model Checking Results" | get-property caption | equals "Model Checking Results" | verify-true
-	    with [get-section "General"] {
-	    	get-label "Awaiting first run..."
-	        verify-error {get-label "Not running"}
-	        verify-error {get-link "No errors"}
-	    }
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+	with [get-editor $TLA-MODEL-ONE] {
+		get-section $TLA-MO-ED-OVERVIEW-SECTION-MODEL | click
+		get-link $TLA-MO-ED-OVERVIEW-LINK-SPEC | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-AD | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-SC | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-MV | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-DO | click
+	    get-section $TLA-MO-ED-ADDITIONAL-SECTION-AC | click
 	}
 } -finally {
 	DeleteSpecNew
diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Quick_Access.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Quick_Access.test
index f204a45dd59dad445e287ed6bb9924138d7e0655..14ddef9acf414b8a7a69307af32aacf99cd7f758 100644
--- a/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Quick_Access.test
+++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Quick_Access.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _LlgJkAL3EemtrbArmQOOJA
-Runtime-Version: 2.3.0.201806262310
-Save-Time: 12/18/18 11:00 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 11:45 AM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -22,7 +22,7 @@ Entry-Name: .content
 
 get-menu -path "Window/Quick Access..." | click
 get-window -class TLAFilteredItemsSelectionDialog 
-    | get-label "Select an item to open (? = any character, * = any string):" | get-property caption 
-    | equals "&Select an item to open (? = any character, * = any string):" | verify-true
-get-window -class TLAFilteredItemsSelectionDialog | get-button Cancel | click
+    | get-label "Select an item to open (? = any character, * = any string):"
+get-window -class TLAFilteredItemsSelectionDialog | get-button $TLA-BUTTON-CANCEL | click
+
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Window_Reset.test b/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Window_Reset.test
index b88581947ecf4f8eef02640037c37450a26e2a46..89102e51de76cfdcd08be433e95fda26dca079e1 100644
--- a/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Window_Reset.test
+++ b/org.lamport.tla.toolbox.product.uitest/bvt/TLA_Smoke_Window_Reset.test
@@ -5,8 +5,8 @@ Element-Type: testcase
 Element-Version: 3.0
 External-Reference: 
 Id: _CxeGQAP2EemwBd2liJ-qvA
-Runtime-Version: 2.4.0.201902090011
-Save-Time: 4/3/19, 9:11 AM
+Runtime-Version: 2.4.0.201902010011
+Save-Time: 10/14/19, 1:04 PM
 Testcase-Type: ecl
 
 ------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
@@ -23,35 +23,24 @@ Entry-Name: .content
 OpenTLACreateNew
 
 try -command {
-with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
-    key-type Down
-    type-text "EXTENDS Naturals"
-    key-type Enter
-    type-text "VARIABLE x"
-    key-type Enter -times 1
-    type-text "Init == x = 999999999999999999999999999999999999999"
-    key-type Enter -times 2
-    type-text "Next == x' = x * 999999999999999999999999999999"
-     key-type "M1+s"
-    }
-    wait -ms 1000
-get-menu -path "TLC Model Checker/New Model..." | click
-get-window "New model..." | get-label "Please input the name of the model to create" | get-property caption 
-    | equals "Please input the name of the model to create" | verify-true
-get-window "New model..." | get-button OK | click
+	with [get-editor $TLA-SPEC-NAME | get-text-viewer] {
+		set-text [concat "-------------------------------- MODULE " $TLA-SPEC-NAME " --------------------------------\nEXTENDS Naturals\nVARIABLE x\nInit == x = 999999999999999999999999999999999999999\n\nNext == x' = x * 999999999999999999999999999999\n\n=============================================================================\n"]
+	    key-type "M1+s"
+	}
+	wait -ms 1000
+	get-menu -path $TLA-MENU-PATH-NEW-MODEL | click
+	get-window $TLA-DIALOG-TITLE-NEW-MODEL | get-button $TLA-BUTTON-OK | click
+	
+	
+	get-menu -path $TLA-MENU-PATH-WINDOW-SPEC-EXPLORER | click
+	get-view $TLA-VIEW-SPEC-EXPLORER | minimize
+	get-menu -path $TLA-MENU-PATH-WINDOW-SPEC-EXPLORER | click
+	//get-menu -path "Window/Reset Window Layout" | click
+	//get-window "Reset Perspective" 
+	//    | get-label "Do you want to reset the current Specification perspective to its defaults?"
+	// get-window "Reset Perspective" | get-button "Yes" | click
+} -finally {
+	DeleteSpecNew
+}
 
-
-get-menu -path "Window/Spec Explorer" | click
-get-view "Spec Explorer" | minimize
-get-menu -path "Window/Spec Explorer" | click
-//get-menu -path "Window/Reset Window Layout" | click
-//get-window "Reset Perspective" 
-//    | get-label "Do you want to reset the current Specification perspective to its defaults?" | get-property caption 
-//    | equals "Do you want to reset the current Specification perspective to its defaults?" | verify-true
-// get-window "Reset Perspective" | get-button Yes | click
-
-
-} -finally
-//Delete Spec
-{DeleteSpecNew}
 ------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--
diff --git a/org.lamport.tla.toolbox.product.uitest/pom.xml b/org.lamport.tla.toolbox.product.uitest/pom.xml
index ee48a8ced0ef632d26e87156f16f5d3841dd46a6..fc94a3dc6b0b9e8d77dbf58cdc772c56e99363e6 100644
--- a/org.lamport.tla.toolbox.product.uitest/pom.xml
+++ b/org.lamport.tla.toolbox.product.uitest/pom.xml
@@ -31,18 +31,18 @@
     -->
   </pluginRepositories>
 
-  <!-- 
-       If RCPTT tests are planned to be run on an update site, 
+  <!--
+       If RCPTT tests are planned to be run on an update site,
        RCPTT Maven Plugin can download Eclipse SDK of required version
-       for current platform from repository below (to see 
+       for current platform from repository below (to see
        an up-to-date list of available versions visit this link:
        http://maven.xored.com/nexus/content/repositories/ci4rcptt-releases/org/eclipse/sdk/
   -->
   <properties>
-    <rcptt-maven-version>2.4.2</rcptt-maven-version>
-    <rcptt-runner-version>2.4.2</rcptt-runner-version>
+    <rcptt-maven-version>2.4.3</rcptt-maven-version>
+    <rcptt-runner-version>2.4.3</rcptt-runner-version>
     <aut-unpack-directory>target/unpack-for-aut/</aut-unpack-directory>
-<!-- 
+<!--
     <jdk-bundle-plugin-prefix>st.theori.openjdk.</jdk-bundle-plugin-prefix>
  -->
     <jdk-bundle-plugin-prefix>org.lamport.openjdk.</jdk-bundle-plugin-prefix>
@@ -91,7 +91,7 @@
 
   <build>
     <plugins>
-      <!-- 
+      <!--
           Something has a bug on macos where it does not preserve the executable
             perms on unpacked files; this bites us as RCPTT attempts to run the java binary
             that has been zipped up in our JDK wrapping feature. We will unpack the ZIP using a
@@ -124,8 +124,8 @@
                 <unzip
                   src="../org.lamport.tla.toolbox.product.product/target/products/TLAToolbox-${toolbox_version}-${os_ws_arch}.zip"
                   dest="${unpack_dir}" />
-                <chmod dir="${unpack_dir}" perm="ugo+x" includes="**/bin/*,**/Contents/Home/lib/jspawnhelper"/>
-                
+                <chmod dir="${unpack_dir}" perm="ugo+x" includes="**/bin/*,**/lib/jspawnhelper"/>
+
                 <ac:if xmlns:ac="antlib:net.sf.antcontrib">
                 	<ac:equals arg1="${os_ws_arch}" arg2="macosx.cocoa.x86_64"/>
                 	<ac:then>
@@ -133,7 +133,7 @@
 						<delete file="${unpack_dir}/TLA+ Toolbox.app/Contents/Eclipse/plugins/${plugin_prefix}macosx.x86_64_${plugin_version}/Contents/MacOS/libjli.dylib"/>
 						<symlink
 						  link="${basedir}/${unpack_dir}/TLA+ Toolbox.app/Contents/Eclipse/plugins/${plugin_prefix}macosx.x86_64_${plugin_version}/Contents/MacOS/libjli.dylib"
-						  resource="${basedir}/${unpack_dir}TLA+ Toolbox.app/Contents/Eclipse/plugins/${plugin_prefix}macosx.x86_64_${plugin_version}/Contents/Home/lib/jli/libjli.dylib"/>
+						  resource="${basedir}/${unpack_dir}TLA+ Toolbox.app/Contents/Eclipse/plugins/${plugin_prefix}macosx.x86_64_${plugin_version}/Contents/Home/lib/libjli.dylib"/>
 						<!-- Rename Toolbox directory to remove "+ " in path ".../TLA+ Toolbox/..." to make RCPTT not crash with
 						         java.net.URISyntaxException: Illegal character in path at index 104: ...
 						   (see https://bugs.eclipse.org/547632) -->
@@ -181,9 +181,9 @@
 
               DO NOT USE - see above comment WRT truezip
 
-            <explicit>../org.lamport.tla.toolbox.product.product/target/products/TLAToolbox-1.6.0-[platform].zip</explicit>
+            <explicit>../org.lamport.tla.toolbox.product.product/target/products/TLAToolbox-1.6.1-[platform].zip</explicit>
             -->
-            
+
             <explicit>${aut-unpack-directory}</explicit>
 
             <!-- Or specify a path to AUT folder -->
@@ -195,9 +195,9 @@
             <!--
             <explicit>http://server/path/aut-archive.zip</explicit>
             -->
-            
+
             <!-- AUT can be downloaded automatically from Maven repository -->
-            <!-- 
+            <!--
             <groupId>com.company.product</groupId>
             <artifactId>com.company.product.rcp</artifactId>
             <version>3.7.2</version>
@@ -211,12 +211,12 @@
                  Mac OS X 64bit: macosx.coca.x86_64
             -->
 
-            <!-- Optionally it is possible to specify extra features to 
+            <!-- Optionally it is possible to specify extra features to
                  be installed into AUT, this is useful when RCPTT tests
-                 need to be executed using a repository assembled as 
+                 need to be executed using a repository assembled as
                  part of current Maven build.
 
-                 Inside an 'injection element it is possible to specify a list of 
+                 Inside an 'injection element it is possible to specify a list of
                  features/plugins to install, if nothing is set, all available
                  features will be installed.
                  feature.group suffix is required by p2,
@@ -227,7 +227,7 @@
             -->
 
 
-                 
+
             <injections>
               <!-- features are optional - when omitted, all features from given site will be installed -->
               <!--
@@ -240,9 +240,9 @@
               -->
             </injections>
 
-           <!-- additional AUT args (besides taken in its ini-file) can be set 
+           <!-- additional AUT args (besides taken in its ini-file) can be set
                 Use one argument per <arg> element -->
-           <!-- 
+           <!--
             <args>
               <arg>-ws</arg>
               <arg>$${target.ws}</arg>
@@ -260,13 +260,13 @@
           </aut>
 
           <runner>
-            <!-- RCPTT Runner location can be set using the same methods 
+            <!-- RCPTT Runner location can be set using the same methods
                  as AUT location:
             -->
             <!--
             <explicit>/path/to/rcptt/runner</explicit>
             -->
-            
+
             <!-- but the most convenient way is to just set its version,
                  RCPTT maven plugin will automatically set right groupId and
                  artifact ID and will download RCPTT Runner from Xored Maven Repo -->
@@ -288,7 +288,7 @@
 
             <!-- When set to true, in case of test failure
                  AUT will be restarted. This significantly
-                 slows down execution, but may be useful 
+                 slows down execution, but may be useful
                  for some test suites -->
             <!--
             <restartAUTOnFailure>true</restartAUTOnFailure>
@@ -296,7 +296,7 @@
           </testOptions>
 
           <!-- By default RCPTT Runner runs tests from a project directory,
-               but in some cases it might be required to import additional 
+               but in some cases it might be required to import additional
                projects into runner's workspace -->
           <!--
           <projects>
@@ -317,7 +317,7 @@
           <!-- Sometimes it might be useful to skip a test case
                (for instance because of some unresolved bug). RCPTT
                can skip tests based on its tags. By default RCPTT skips
-               tests with tag 'skipExecution' (this value has been 
+               tests with tag 'skipExecution' (this value has been
                chosen because on one hand it is descriptive enough,
                on another hand it is unlikely that this tag name
                will collide with some user's tag)
diff --git a/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/spec/SpecTest.java b/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/spec/SpecTest.java
index 9f409a57a84756a92ea647fdae8caa09e7280b0b..96fdb86546765543583ce64099d0509a4ab50113 100644
--- a/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/spec/SpecTest.java
+++ b/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/spec/SpecTest.java
@@ -46,6 +46,7 @@ import org.lamport.tla.toolbox.util.pref.IPreferenceConstants;
 import org.lamport.tla.toolbox.util.pref.PreferenceStoreHelper;
 
 import junit.framework.TestCase;
+import util.TLAConstants;
 
 public class SpecTest extends TestCase {
 
@@ -61,7 +62,7 @@ public class SpecTest extends TestCase {
 	 */
 	public void testCreateSpecStoreRelativePath() throws IOException, CoreException {
 		// Create...
-		final File tempFile = File.createTempFile("TestCreateSpecStoreRelativePath", ".tla");
+		final File tempFile = File.createTempFile("TestCreateSpecStoreRelativePath", TLAConstants.Files.TLA_EXTENSION);
 		final Spec spec = Spec.createNewSpec("TestCreateSpecStoreRelativePath", tempFile.getAbsolutePath(), false, new NullProgressMonitor());
 		
 		// ...check it's correct.
@@ -88,7 +89,9 @@ public class SpecTest extends TestCase {
 	public void testCreateSpecInReadOnlyDirectory() throws IOException {
 		// Create...
 		final Path tempDirectory = Files.createTempDirectory("ReadOnlyDirectory" + System.currentTimeMillis());
-		final File tempFile = Files.createTempFile(tempDirectory, "TestCreateSpecInReadOnlyDirectory", ".tla").toFile();
+		final File tempFile = Files
+				.createTempFile(tempDirectory, "TestCreateSpecInReadOnlyDirectory", TLAConstants.Files.TLA_EXTENSION)
+				.toFile();
 
 //		Assume.assumeTrue(tempDirectory.toFile().setReadOnly());
 		if (!tempDirectory.toFile().setReadOnly()) {
@@ -127,7 +130,7 @@ public class SpecTest extends TestCase {
 
 	private void createDelete(final String specName, boolean forget) throws IOException, CoreException {
 		// Create...
-		final File tempFile = File.createTempFile(specName, ".tla");
+		final File tempFile = File.createTempFile(specName, TLAConstants.Files.TLA_EXTENSION);
 		final Spec spec = Spec.createNewSpec("TestCreateDeleteSpec", tempFile.getAbsolutePath(), false, new NullProgressMonitor());
 		final IProject project = spec.getProject();
 		
diff --git a/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/ui/handler/NewSpecHandlerTest.java b/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/ui/handler/NewSpecHandlerTest.java
index 1cd81c1e2619eeb1adeba7ea7978655a7c96c307..674b9b2ee7ab6a357a5c25f509dd981a058b18b5 100644
--- a/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/ui/handler/NewSpecHandlerTest.java
+++ b/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/ui/handler/NewSpecHandlerTest.java
@@ -43,6 +43,7 @@ import org.lamport.tla.toolbox.spec.Spec;
 import org.lamport.tla.toolbox.ui.handler.NewSpecHandler.NewSpecHandlerJob;
 
 import junit.framework.TestCase;
+import util.TLAConstants;
 
 public class NewSpecHandlerTest extends TestCase {
 
@@ -84,7 +85,7 @@ public class NewSpecHandlerTest extends TestCase {
 
 	private IStatus runJob(String specName) throws IOException, InterruptedException {
 		final NewSpecHandlerJob job = new NewSpecHandlerJob(specName,
-				Files.createTempFile(specName, ".tla").toFile().getAbsolutePath(), false);
+				Files.createTempFile(specName, TLAConstants.Files.TLA_EXTENSION).toFile().getAbsolutePath(), false);
 		MyJobChangeAdapter listener = new MyJobChangeAdapter();
 		job.addJobChangeListener(listener);
 		job.schedule();
diff --git a/org.lamport.tla.toolbox.tool.prover/plugin.xml b/org.lamport.tla.toolbox.tool.prover/plugin.xml
index ada4e6516e212c7a2398e4fd7afe671d907d14ad..da21debb21e239ee895e4e7c286ef216dae13f6e 100644
--- a/org.lamport.tla.toolbox.tool.prover/plugin.xml
+++ b/org.lamport.tla.toolbox.tool.prover/plugin.xml
@@ -660,15 +660,23 @@
          point="org.eclipse.ui.preferencePages">
       <page
             category="toolbox.ui.preferences.GeneralPreferencePage"
-            class="org.lamport.tla.toolbox.tool.prover.ui.preference.ProverPreferencePage"
-            id="org.lamport.tla.toolbox.tool.prover.ProverPreferencePage"
+            class="org.lamport.tla.toolbox.tool.prover.ui.preference.MainProverPreferencePage"
+            id="org.lamport.tla.toolbox.tool.prover.MainProverPreferencePage"
             name="TLAPS">
       </page>
       <page
-            category="org.lamport.tla.toolbox.tool.prover.ProverPreferencePage"
-            class="org.lamport.tla.toolbox.tool.prover.ui.preference.ProverSecondPreferencePage"
-            id="org.lamport.tla.toolbox.tool.prover.ProverSecondPreferencePage"
-            name="Additional Preferences">
+            category="org.lamport.tla.toolbox.tool.prover.MainProverPreferencePage"
+            class="org.lamport.tla.toolbox.tool.prover.ui.preference.ColorPredicatePreferencePage"
+            id="org.lamport.tla.toolbox.tool.prover.ColorPredicatePreferencePage"
+            name="Color Predicates">
+      </page>
+      <!-- This was originally called "Additional Preferences" but the wizards at Eclipse thought to themselves
+      		'No one will ever need to order preference pages beyond natural ordering by title!' -->
+      <page
+            category="org.lamport.tla.toolbox.tool.prover.MainProverPreferencePage"
+            class="org.lamport.tla.toolbox.tool.prover.ui.preference.AdditionalPreferencesPage"
+            id="org.lamport.tla.toolbox.tool.prover.AdditionalPreferencesPage"
+            name="Other Preferences">
       </page>
    </extension>
    <extension
diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ProverPreferenceInitializer.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ProverPreferenceInitializer.java
index 4d55dae9488a969463a3122a98b2ad818b0172fa..8d47ecc466cb88857b2ec25e37bc354831183804 100644
--- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ProverPreferenceInitializer.java
+++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ProverPreferenceInitializer.java
@@ -5,8 +5,9 @@ import org.eclipse.jface.preference.IPreferenceStore;
 import org.lamport.tla.toolbox.tool.prover.ui.ProverUIActivator;
 import org.lamport.tla.toolbox.tool.prover.ui.dialog.LaunchProverDialog;
 import org.lamport.tla.toolbox.tool.prover.ui.output.data.ColorPredicate;
-import org.lamport.tla.toolbox.tool.prover.ui.preference.ProverPreferencePage;
-import org.lamport.tla.toolbox.tool.prover.ui.preference.ProverSecondPreferencePage;
+import org.lamport.tla.toolbox.tool.prover.ui.preference.AdditionalPreferencesPage;
+import org.lamport.tla.toolbox.tool.prover.ui.preference.ColorPredicatePreferencePage;
+import org.lamport.tla.toolbox.tool.prover.ui.preference.MainProverPreferencePage;
 
 /**
  * This class can be used to set default preferences for any preference
@@ -37,34 +38,35 @@ public class ProverPreferenceInitializer extends AbstractPreferenceInitializer
         store.setDefault(LaunchProverDialog.FP_NORMAL_KEY, true);
         store.setDefault(LaunchProverDialog.FP_FORGET_ALL_KEY, false);
         store.setDefault(LaunchProverDialog.FP_FORGET_CURRENT_KEY, false);
-        store.setDefault(ProverSecondPreferencePage.NUM_THREADS_KEY, "");
-        store.setDefault(ProverSecondPreferencePage.SOLVER_KEY, "");
-        store.setDefault(ProverSecondPreferencePage.SAFEFP_KEY, false);
+        store.setDefault(MainProverPreferencePage.EXECUTABLE_LOCATION_KEY, "");
+        store.setDefault(MainProverPreferencePage.NUM_THREADS_KEY, "");
+        store.setDefault(MainProverPreferencePage.SOLVER_KEY, "");
+        store.setDefault(MainProverPreferencePage.SAFEFP_KEY, false);
         
         /*
          * The following sets the default color predicates for the colors. First argument
          * is the key for each predicate for the logical color, and the second argument is
          * the predicate string (not the macro name).
          */
-        store.setDefault(ProverPreferencePage.getColorPredPrefName(1), ColorPredicate.PREDICATE_NONE);
-        store.setDefault(ProverPreferencePage.getColorPredPrefName(2), ColorPredicate.PREDICATE_NONE);
-        store.setDefault(ProverPreferencePage.getColorPredPrefName(3), ColorPredicate.PREDICATE_BEING_PROVED);
-        store.setDefault(ProverPreferencePage.getColorPredPrefName(4), ColorPredicate.PREDICATE_STOPPED);
-        store.setDefault(ProverPreferencePage.getColorPredPrefName(5), ColorPredicate.PREDICATE_FAILED);
-        store.setDefault(ProverPreferencePage.getColorPredPrefName(6), ColorPredicate.PREDICATE_PROVED);
-        store.setDefault(ProverPreferencePage.getColorPredPrefName(7), ColorPredicate.PREDICATE_PROVED_OR_OMITTED);
-        store.setDefault(ProverPreferencePage.getColorPredPrefName(8), ColorPredicate.PREDICATE_PROVED_OR_OMITTED_OR_MISSING);
-        store.setDefault(ProverPreferencePage.getColorPredPrefName(9), ColorPredicate.PREDICATE_NONE);
-        store.setDefault(ProverPreferencePage.getColorPredPrefName(10), ColorPredicate.PREDICATE_NONE);
-        store.setDefault(ProverPreferencePage.getColorPredPrefName(11), ColorPredicate.PREDICATE_NONE);
-        store.setDefault(ProverPreferencePage.getColorPredPrefName(12), ColorPredicate.PREDICATE_NONE);
+        store.setDefault(ColorPredicatePreferencePage.getColorPredPrefName(1), ColorPredicate.PREDICATE_NONE);
+        store.setDefault(ColorPredicatePreferencePage.getColorPredPrefName(2), ColorPredicate.PREDICATE_NONE);
+        store.setDefault(ColorPredicatePreferencePage.getColorPredPrefName(3), ColorPredicate.PREDICATE_BEING_PROVED);
+        store.setDefault(ColorPredicatePreferencePage.getColorPredPrefName(4), ColorPredicate.PREDICATE_STOPPED);
+        store.setDefault(ColorPredicatePreferencePage.getColorPredPrefName(5), ColorPredicate.PREDICATE_FAILED);
+        store.setDefault(ColorPredicatePreferencePage.getColorPredPrefName(6), ColorPredicate.PREDICATE_PROVED);
+        store.setDefault(ColorPredicatePreferencePage.getColorPredPrefName(7), ColorPredicate.PREDICATE_PROVED_OR_OMITTED);
+        store.setDefault(ColorPredicatePreferencePage.getColorPredPrefName(8), ColorPredicate.PREDICATE_PROVED_OR_OMITTED_OR_MISSING);
+        store.setDefault(ColorPredicatePreferencePage.getColorPredPrefName(9), ColorPredicate.PREDICATE_NONE);
+        store.setDefault(ColorPredicatePreferencePage.getColorPredPrefName(10), ColorPredicate.PREDICATE_NONE);
+        store.setDefault(ColorPredicatePreferencePage.getColorPredPrefName(11), ColorPredicate.PREDICATE_NONE);
+        store.setDefault(ColorPredicatePreferencePage.getColorPredPrefName(12), ColorPredicate.PREDICATE_NONE);
      
         
        /*
         * Set the defaults for the user-specified color predicates
         */
-        for (int i = 0; i < ProverSecondPreferencePage.USER_DEFINED_PREDICATE.length; i++) {
-            store.setDefault(ProverSecondPreferencePage.USER_DEFINED_PREDICATE[i], "some");
+        for (int i = 0; i < AdditionalPreferencesPage.USER_DEFINED_PREDICATE.length; i++) {
+            store.setDefault(AdditionalPreferencesPage.USER_DEFINED_PREDICATE[i], "some");
         }     
     }
 
diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/job/ProverJob.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/job/ProverJob.java
index f98d8ed6d3983ee6474ea4ea2e3125f3dd98146d..0b3f159aeec63554503d6d6c0aafe3b4709fa6b3 100644
--- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/job/ProverJob.java
+++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/job/ProverJob.java
@@ -47,7 +47,7 @@ import org.lamport.tla.toolbox.tool.prover.ui.output.data.ObligationStatus;
 import org.lamport.tla.toolbox.tool.prover.ui.output.data.ObligationStatusMessage;
 import org.lamport.tla.toolbox.tool.prover.ui.output.data.StepStatusMessage;
 import org.lamport.tla.toolbox.tool.prover.ui.output.data.StepTuple;
-import org.lamport.tla.toolbox.tool.prover.ui.preference.ProverPreferencePage;
+import org.lamport.tla.toolbox.tool.prover.ui.preference.ColorPredicatePreferencePage;
 import org.lamport.tla.toolbox.tool.prover.ui.util.ProverHelper;
 import org.lamport.tla.toolbox.tool.prover.ui.util.TLAPMExecutableLocator;
 import org.lamport.tla.toolbox.tool.prover.ui.view.ObligationsView;
@@ -272,14 +272,14 @@ public class ProverJob extends Job {
          * 
          * Note that color numbers for the preference page are 1-based.
          */
-        colorPredicates = new ColorPredicate[ProverPreferencePage.NUM_STATUS_COLORS];
+        colorPredicates = new ColorPredicate[ColorPredicatePreferencePage.NUM_STATUS_COLORS];
 
         // the preference store containing color predicate preferences
         IPreferenceStore store = ProverUIActivator.getDefault().getPreferenceStore();
         for (int i = 1; i <= colorPredicates.length; i++)
         {
-            String predicate = store.getString(ProverPreferencePage.getColorPredPrefName(i));
-            boolean appliesToLeafOnly = store.getBoolean(ProverPreferencePage.getAppliesToLeafPrefName(i));
+            String predicate = store.getString(ColorPredicatePreferencePage.getColorPredPrefName(i));
+            boolean appliesToLeafOnly = store.getBoolean(ColorPredicatePreferencePage.getAppliesToLeafPrefName(i));
             colorPredicates[i - 1] = new ColorPredicate((appliesToLeafOnly ? "leaf " : "") + predicate);
         }
 
@@ -497,13 +497,13 @@ public class ProverJob extends Job {
                             && proverProcess.getExitValue() != 1)
                     {
                         return new Status(IStatus.ERROR, ProverUIActivator.PLUGIN_ID,
-                                "Error running tlapm. Report a bug with the error code to the developers at https://tlaplus.codeplex.com/workitem/list/basic."
+                                "Error running tlapm. Report a bug with the error code to the developers at https://github.com/tlaplus/tlapm/issues."
                                         + "\n \n Error code: " + proverProcess.getExitValue());
                     }
                 } catch (DebugException e)
                 {
                     return new Status(IStatus.ERROR, ProverUIActivator.PLUGIN_ID,
-                            "Error getting exit code for tlapm process. This is a bug. Report it to the developers at https://tlaplus.codeplex.com/workitem/list/basic");
+                            "Error getting exit code for tlapm process. This is a bug. Report it to the developers at https://github.com/tlaplus/tlapm/issues");
                 }
 
                 // successful termination
@@ -650,6 +650,19 @@ public class ProverJob extends Job {
 
         command.add(tlapmPath.toOSString());
 
+		// Use Windows Subsystem for Linux instead of Cygwin. This is experimental and
+		// a hack.  A user has to enter wsl.exe or C:\Windows\system32\wsl.exe on the
+        // Toolbox's preference page.  The next if block the appends 'tlapm'. 
+        final boolean useWSL = tlapmPath.toOSString().contains("wsl.exe");
+        if (useWSL) {
+			// Assume tlapm is on PATH in the Linux subsystem. With this, prefixing the
+			// command with 'wsl' tells Windows to invoke the binary (tlapm) via WSL. I
+			// expect this to only work with a single WSL distro installed (otherwise, we
+			// probably have to choose a distro). More information and how to install WSL is
+			// at https://docs.microsoft.com/en-us/windows/wsl/wsl2-install.
+    		command.add("tlapm");
+        }
+
         if (toolboxMode)
         {
             command.add("--toolbox");
@@ -721,12 +734,26 @@ public class ProverJob extends Job {
         if (pathList != null) {
             for (int i=0; i < pathList.length; i++) {
                 command.add("-I") ;
-                command.add(pathList[pathList.length - i - 1]) ;
+                if (useWSL) {
+					// 'wslpath' is executed inside the Linux subsystem. It converts an UNC (?) path
+					// such as "C:\\Users\\markus\\Library\\dir\\" to something that can be resolved
+					// in the Linux subsystem. Unfortunately, pathList[n] =
+					// "C:\Users\markus\Library\dir" which is why we replace \\ with \\\\
+					// backslashes.
+    				command.add(String.format("$(wslpath %s)", pathList[pathList.length - i - 1].replace("\\", "\\\\")));
+                } else {
+                    command.add(pathList[pathList.length - i - 1]) ;
+                }
             }
         }
         
-        // why just the last segment?
-        command.add(module.getLocation().toOSString());
+        if (useWSL) {
+        	// See pathList above about wslpath.  This path here is the actual spec to be verified.
+    		command.add(String.format("$(wslpath %s)", module.getLocation().toOSString().replace("\\", "\\\\")));
+        } else {
+            // why just the last segment?
+            command.add(module.getLocation().toOSString());
+        }
      
         // for debugging
         // for (int i=0; i<command.size(); i++) {
diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/AbstractProverHandler.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/AbstractProverHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..db5a5a60dada94b77aa046f964bb8cb1d5654335
--- /dev/null
+++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/AbstractProverHandler.java
@@ -0,0 +1,25 @@
+package org.lamport.tla.toolbox.tool.prover.ui.handler;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.lamport.tla.toolbox.Activator;
+import org.lamport.tla.toolbox.editor.basic.util.EditorUtil;
+import org.lamport.tla.toolbox.spec.Spec;
+import org.lamport.tla.toolbox.spec.parser.IParseConstants;
+import org.lamport.tla.toolbox.tool.prover.ui.util.TLAPMExecutableLocator;
+
+/**
+ * All of our prover handlers have the same {@link #setEnabled(Object)} logic, so we abstract it out here.
+ */
+public abstract class AbstractProverHandler extends AbstractHandler {
+	/**
+	 * The handler is enabled if there is a TLA editor with focus, a TLAPM executable exists, and the spec
+	 * 	has been parsed successfully.
+	 */
+	public void setEnabled(Object context) {
+		final TLAPMExecutableLocator locator = TLAPMExecutableLocator.INSTANCE;
+		final Spec spec = Activator.getSpecManager().getSpecLoaded();
+
+		setBaseEnabled((EditorUtil.getTLAEditorWithFocus() != null) && locator.tlapmDoesExist()
+				&& (spec.getStatus() == IParseConstants.PARSED));
+	}
+}
diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/CheckProofHandler.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/CheckProofHandler.java
index 68eb574177ea93177541d94a1791e2126d08d372..0c1e1e1dc32b2d8f471abaa2e34c30581f89873b 100644
--- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/CheckProofHandler.java
+++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/CheckProofHandler.java
@@ -1,42 +1,24 @@
 package org.lamport.tla.toolbox.tool.prover.ui.handler;
 
-import org.eclipse.core.commands.AbstractHandler;
 import org.eclipse.core.commands.ExecutionEvent;
 import org.eclipse.core.commands.ExecutionException;
 import org.eclipse.core.commands.IHandler;
-import org.lamport.tla.toolbox.editor.basic.util.EditorUtil;
 import org.lamport.tla.toolbox.tool.prover.ui.util.ProverHelper;
-import org.lamport.tla.toolbox.tool.prover.ui.util.TLAPMExecutableLocator;
 
 /**
  * Launches TLAPM on the proof step currently containing the caret or on the
  * entire module if the caret is not at a proof step. See 
- * @link ProverHelper#runProverForActiveSelection(boolean, boolean)} to see how it works.
+ * {@link ProverHelper#runProverForActiveSelection(boolean, boolean)} to see how it works.
  * 
  * @author Daniel Ricketts
- *
  */
-public class CheckProofHandler extends AbstractHandler implements IHandler
-{
+public class CheckProofHandler extends AbstractProverHandler implements IHandler {
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		/*
+		 * See the comments for the following method for its effect and implementation.
+		 */
+		ProverHelper.runProverForActiveSelection(false, true);
 
-    public Object execute(ExecutionEvent event) throws ExecutionException
-    {
-        /*
-         * See the comments for the following method for its
-         * effect and implementation.
-         */
-        ProverHelper.runProverForActiveSelection(false, true);
-
-        return null;
-    }
-
-    /**
-     * This handler is enabled if there is a TLA editor with focus and a TLAPM executable exists.
-     */
-    public void setEnabled(Object context)
-    {
-        final TLAPMExecutableLocator locator = TLAPMExecutableLocator.INSTANCE;
-
-        setBaseEnabled((EditorUtil.getTLAEditorWithFocus() != null) && locator.tlapmDoesExist());
-    }
+		return null;
+	}
 }
diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/GeneralLaunchProverHandler.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/GeneralLaunchProverHandler.java
index 369621c5503d88831e008b09b0120fbb63e548d5..f65ab93088a9f846c2467990de2c3b366761e9e9 100644
--- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/GeneralLaunchProverHandler.java
+++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/GeneralLaunchProverHandler.java
@@ -1,12 +1,9 @@
 package org.lamport.tla.toolbox.tool.prover.ui.handler;
 
-import org.eclipse.core.commands.AbstractHandler;
 import org.eclipse.core.commands.ExecutionEvent;
 import org.eclipse.core.commands.ExecutionException;
 import org.eclipse.core.commands.IHandler;
-import org.lamport.tla.toolbox.editor.basic.util.EditorUtil;
 import org.lamport.tla.toolbox.tool.prover.ui.dialog.LaunchProverDialog;
-import org.lamport.tla.toolbox.tool.prover.ui.util.TLAPMExecutableLocator;
 import org.lamport.tla.toolbox.util.UIHelper;
 
 /**
@@ -15,33 +12,19 @@ import org.lamport.tla.toolbox.util.UIHelper;
  * class for a more detailed explanation of the dialog.
  * 
  * @author Daniel Ricketts
- *
  */
-public class GeneralLaunchProverHandler extends AbstractHandler implements IHandler
-{
-    public Object execute(ExecutionEvent event) throws ExecutionException
-    {
-    	/*
-    	 * Check for dirty module added by LL on 14 Dec 2010
-    	 */
-        boolean proceed = UIHelper.promptUserForDirtyModules();
-        if (!proceed)
-        {
-            // the user cancelled
-            return null;
-        }
-        LaunchProverDialog dialog = new LaunchProverDialog(UIHelper.getShellProvider());
-        dialog.open();
-        return null;
-    }
-
-    /**
-     * This handler is enabled if there is a TLA editor with focus and a TLAPM executable exists.
-     */
-    public void setEnabled(Object context)
-    {
-        final TLAPMExecutableLocator locator = TLAPMExecutableLocator.INSTANCE;
-
-        setBaseEnabled((EditorUtil.getTLAEditorWithFocus() != null) && locator.tlapmDoesExist());
-    }
+public class GeneralLaunchProverHandler extends AbstractProverHandler implements IHandler {
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		/*
+		 * Check for dirty module added by LL on 14 Dec 2010
+		 */
+		boolean proceed = UIHelper.promptUserForDirtyModules();
+		if (!proceed) {
+			// the user cancelled
+			return null;
+		}
+		LaunchProverDialog dialog = new LaunchProverDialog(UIHelper.getShellProvider());
+		dialog.open();
+		return null;
+	}
 }
diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/StatusStepHandler.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/StatusStepHandler.java
index 0f245e0aca6f4b660558a878403fec9910c01bfe..972cb95ff847f9b7528a0da02779118842d2699c 100644
--- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/StatusStepHandler.java
+++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/handler/StatusStepHandler.java
@@ -1,12 +1,9 @@
 package org.lamport.tla.toolbox.tool.prover.ui.handler;
 
-import org.eclipse.core.commands.AbstractHandler;
 import org.eclipse.core.commands.ExecutionEvent;
 import org.eclipse.core.commands.ExecutionException;
 import org.eclipse.core.commands.IHandler;
-import org.lamport.tla.toolbox.editor.basic.util.EditorUtil;
 import org.lamport.tla.toolbox.tool.prover.ui.util.ProverHelper;
-import org.lamport.tla.toolbox.tool.prover.ui.util.TLAPMExecutableLocator;
 
 /**
  * Runs the prover to simply get the status of the step containing
@@ -16,24 +13,11 @@ import org.lamport.tla.toolbox.tool.prover.ui.util.TLAPMExecutableLocator;
  * for more information.
  * 
  * @author Daniel Ricketts
- *
  */
-public class StatusStepHandler extends AbstractHandler implements IHandler
-{
-    public Object execute(ExecutionEvent event) throws ExecutionException
-    {
-        ProverHelper.runProverForActiveSelection(true, false);
+public class StatusStepHandler extends AbstractProverHandler implements IHandler {
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		ProverHelper.runProverForActiveSelection(true, false);
 
-        return null;
-    }
-
-    /**
-     * This handler is enabled if there is a TLA editor with focus and a TLAPM executable exists.
-     */
-    public void setEnabled(Object context)
-    {
-        final TLAPMExecutableLocator locator = TLAPMExecutableLocator.INSTANCE;
-
-        setBaseEnabled((EditorUtil.getTLAEditorWithFocus() != null) && locator.tlapmDoesExist());
-    }
+		return null;
+	}
 }
diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/ColorPredicate.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/ColorPredicate.java
index 2bd0af1dabb6bd157c032d1f2936f734115638d0..bc6d34fe98331ea12e68080322fb085366c01fcf 100644
--- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/ColorPredicate.java
+++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/ColorPredicate.java
@@ -67,7 +67,7 @@ package org.lamport.tla.toolbox.tool.prover.ui.output.data;
 
 import org.lamport.tla.toolbox.Activator;
 import org.lamport.tla.toolbox.tool.prover.ui.ProverUIActivator;
-import org.lamport.tla.toolbox.tool.prover.ui.preference.ProverSecondPreferencePage;
+import org.lamport.tla.toolbox.tool.prover.ui.preference.AdditionalPreferencesPage;
 
 /**
  * @author lamport
@@ -225,7 +225,7 @@ public class ColorPredicate
             if (macroName.equalsIgnoreCase(USER_DEFINED[i]))
             {
                 return ProverUIActivator.getDefault().getPreferenceStore().getString(
-                        ProverSecondPreferencePage.USER_DEFINED_PREDICATE[i]);
+                        AdditionalPreferencesPage.USER_DEFINED_PREDICATE[i]);
             }
         }
         return null;
diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/StepTuple.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/StepTuple.java
index b32e373400a268c2e5c15c7c8ed8f74dea4f2d98..e58c92410c9548049b44592016c6ac7e3eaacab8 100644
--- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/StepTuple.java
+++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/output/data/StepTuple.java
@@ -7,7 +7,7 @@ import java.util.List;
 import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.runtime.Assert;
 import org.lamport.tla.toolbox.tool.prover.job.ProverJob;
-import org.lamport.tla.toolbox.tool.prover.ui.preference.ProverPreferencePage;
+import org.lamport.tla.toolbox.tool.prover.ui.preference.ColorPredicatePreferencePage;
 import org.lamport.tla.toolbox.tool.prover.ui.util.ProverHelper;
 
 import tla2sany.st.Location;
@@ -141,7 +141,7 @@ public class StepTuple
          */
         if (predicateChanged)
         {
-            int newMinimum = ProverPreferencePage.NUM_STATUS_COLORS + 1;
+            int newMinimum = ColorPredicatePreferencePage.NUM_STATUS_COLORS + 1;
             for (int i = 0; i < colorPredicateValues.length; i++)
             {
                 if (colorPredicateValues[i])
@@ -176,7 +176,7 @@ public class StepTuple
         this.proverJob = proverJob;
         children = new ArrayList();
         ColorPredicate[] colorPredicates = proverJob.getColorPredicates();
-        colorPredicateValues = new boolean[ProverPreferencePage.NUM_STATUS_COLORS];
+        colorPredicateValues = new boolean[ColorPredicatePreferencePage.NUM_STATUS_COLORS];
         for (int i = 0; i < colorPredicateValues.length; i++)
         {
             colorPredicateValues[i] = !colorPredicates[i].isSome;
diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/AdditionalPreferencesPage.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/AdditionalPreferencesPage.java
new file mode 100644
index 0000000000000000000000000000000000000000..47e91f41bb81b920170aaac8283a458b78ae7e01
--- /dev/null
+++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/AdditionalPreferencesPage.java
@@ -0,0 +1,45 @@
+/**
+ * 
+ */
+package org.lamport.tla.toolbox.tool.prover.ui.preference;
+
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.lamport.tla.toolbox.tool.prover.ui.ProverUIActivator;
+
+/**
+ * @author lamport
+ */
+public class AdditionalPreferencesPage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+    /*
+     * The names of the preferences for the user-defined predicates.
+     */
+    public static final String[] USER_DEFINED_PREDICATE = { "UserDefinedPredicateA", "UserDefinedPredicateB",
+            "UserDefinedPredicateC", "UserDefinedPredicateD", "UserDefinedPredicateE", "UserDefinedPredicateF"};
+    public static final String[] UPPER_CASE_LETTERS = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L" };
+
+	public AdditionalPreferencesPage() {
+        super(GRID);
+        setPreferenceStore(ProverUIActivator.getDefault().getPreferenceStore());
+        setDescription("User-Defined Color Predicates");
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.jface.preference.FieldEditorPreferencePage#createFieldEditors()
+     */
+	protected void createFieldEditors() {
+        // To change the number of user-defined predicates, look up all uses of
+        // USER_DEFINED_PREDICATE and USER_DEFINED.
+        for (int i = 0; i < USER_DEFINED_PREDICATE.length; i++)
+        {
+            addField(new ColorPredicateFieldEditor(USER_DEFINED_PREDICATE[i],
+                    "     Predicate " + UPPER_CASE_LETTERS[i], getFieldEditorParent()));
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
+     */
+	public void init(IWorkbench workbench) { }
+}
diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/ProverPreferencePage.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/ColorPredicatePreferencePage.java
similarity index 96%
rename from org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/ProverPreferencePage.java
rename to org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/ColorPredicatePreferencePage.java
index cd6ed3031751eb7876e443b31a3f2fdc3e8403c9..4bd582f9debbe7dc50c50e0c5a62fab8e16b5157 100644
--- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/ProverPreferencePage.java
+++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/ColorPredicatePreferencePage.java
@@ -91,7 +91,7 @@ import org.lamport.tla.toolbox.tool.prover.ui.output.data.ColorPredicate;
  * @author Daniel Ricketts
  *
  */
-public class ProverPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage
+public class ColorPredicatePreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage
 {
 
     public static final String PREDICATE = "predicate";
@@ -112,7 +112,7 @@ public class ProverPreferencePage extends FieldEditorPreferencePage implements I
      */
     public static final String COLOR_PREF_KEY_PREFIX = STEP_STATUS_COLOR;
 
-    public ProverPreferencePage()
+    public ColorPredicatePreferencePage()
     {
         super(GRID);
         // Using somebody's else PreferenceStore is not a good idea!
diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/MainProverPreferencePage.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/MainProverPreferencePage.java
new file mode 100644
index 0000000000000000000000000000000000000000..37f645bfc30d0c581dcf29e1787eefcafecc0488
--- /dev/null
+++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/MainProverPreferencePage.java
@@ -0,0 +1,175 @@
+package org.lamport.tla.toolbox.tool.prover.ui.preference;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.preference.BooleanFieldEditor;
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.jface.preference.FileFieldEditor;
+import org.eclipse.jface.preference.StringFieldEditor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.lamport.tla.toolbox.tool.prover.ui.ProverUIActivator;
+import org.lamport.tla.toolbox.tool.prover.ui.util.TLAPMExecutableLocator;
+
+public class MainProverPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+	public static final String EXECUTABLE_LOCATION_KEY = "tlapm_filepath";
+    public static final String NUM_THREADS_KEY = "num_threads";
+    public static final String SOLVER_KEY = "solver";
+    public static final String SAFEFP_KEY = "safefp";
+
+    
+    private TLAPMLocationEditor locationFieldEditor;
+    private Label tlapmWarningLabel;
+    
+	public MainProverPreferencePage() {
+        super(GRID);
+        setPreferenceStore(ProverUIActivator.getDefault().getPreferenceStore());
+    }
+
+	public void init(final IWorkbench workbench) { }
+
+	@Override
+	protected void createFieldEditors() {
+		final Composite parent = getFieldEditorParent();
+		
+		locationFieldEditor = new TLAPMLocationEditor(EXECUTABLE_LOCATION_KEY, "Location of tlapm", parent);
+		addField(locationFieldEditor);
+		tlapmWarningLabel = new Label(getFieldEditorParent(), SWT.CENTER);
+        GridData gd = new GridData();
+        gd.horizontalSpan = 3;  // Because this is the max of all field editor component counts
+        gd.horizontalAlignment = SWT.CENTER;
+        gd.grabExcessHorizontalSpace = true;
+        gd.exclude = true;
+        tlapmWarningLabel.setLayoutData(gd);
+        tlapmWarningLabel.setForeground(tlapmWarningLabel.getDisplay().getSystemColor(SWT.COLOR_RED));
+        tlapmWarningLabel.setText("The tlapm executable is not present or cannot be found.");
+        tlapmWarningLabel.setVisible(false);
+		
+        Label lbl = new Label(getFieldEditorParent(), SWT.NONE);
+        gd = new GridData();
+        gd.horizontalSpan = 3;
+        lbl.setLayoutData(gd);
+        
+        lbl = new Label(getFieldEditorParent(), SWT.NONE);
+        lbl.setLayoutData(gd);
+        lbl.setText("Advanced Execution Preferences");
+
+        addField(new ThreadsFieldEditor(NUM_THREADS_KEY, "  Num. of Threads", parent));
+        addField(new SolverFieldEditor(SOLVER_KEY, "  SMT Solver Command", parent));
+        addField(new BooleanFieldEditor(SAFEFP_KEY, "Do not trust previous results from earlier versions of provers.",
+        		parent));
+	}
+	
+	@Override
+	public void setVisible(final boolean flag) {
+		if (flag) {
+			final TLAPMExecutableLocator locator = TLAPMExecutableLocator.INSTANCE;
+			
+			updateLocationWarningLabelForPath(locator.getTLAPMPath());
+			
+			final String pathPreference = ProverUIActivator.getDefault().getPreferenceStore().getString(MainProverPreferencePage.EXECUTABLE_LOCATION_KEY);
+			if ((pathPreference.trim().length() == 0) && locator.tlapmDoesExist()) {
+				locationFieldEditor.setStringValue(locator.getTLAPMPath().toFile().getAbsolutePath());
+			}
+		}
+		
+		super.setVisible(flag);
+	}
+	
+	private void updateLocationWarningLabelForPath(final IPath path) {
+		if (TLAPMExecutableLocator.pathForExecutableIsUsable(path)) {
+			final GridData gd = (GridData)tlapmWarningLabel.getLayoutData();
+			tlapmWarningLabel.setVisible(false);
+			gd.exclude = true;
+			// in case there is copy-set-ing
+			tlapmWarningLabel.setLayoutData(gd);
+			
+			tlapmWarningLabel.getParent().layout(true, true);
+		} else {
+			showTLAPMWarningLabel();
+		}
+	}
+	
+	private void showTLAPMWarningLabel() {
+		final GridData gd = (GridData)tlapmWarningLabel.getLayoutData();
+		
+		tlapmWarningLabel.setVisible(true);
+		gd.exclude = false;
+		// in case there is copy-set-ing
+		tlapmWarningLabel.setLayoutData(gd);
+		
+		tlapmWarningLabel.getParent().layout(true, true);
+	}
+
+	
+	private static class SolverFieldEditor extends StringFieldEditor {
+		public SolverFieldEditor(final String name, final String labelText, final Composite parent) {
+			super(name, labelText, parent);
+		}
+
+		@Override
+		public boolean doCheckState() {
+			/*
+			 * Changed by DD: accept any string. String value = this.getStringValue();
+			 * return value.indexOf('"') == -1;
+			 */
+			return true;
+		}
+	}
+
+	
+	// this is really IntegerFieldEditor - except it allows us to have a blank as a non-specification instead of a zero
+	//		or other nonsense value which conveys the wrong idea to the user.
+	private static class ThreadsFieldEditor extends StringFieldEditor {
+		public ThreadsFieldEditor(final String name, final String labelText, final Composite parent) {
+			super(name, labelText, parent);
+		}
+
+		@Override
+		public boolean doCheckState() {
+			final String value = this.getStringValue().trim();
+			if (value.length() == 0) {
+				return true;
+			}
+			
+			try {
+				final int numThreads = Integer.parseInt(value);
+				return numThreads > 0;
+			} catch (NumberFormatException e) {
+				return false;
+			}
+		}
+	}
+	
+	
+	private class TLAPMLocationEditor extends FileFieldEditor {
+		public TLAPMLocationEditor(final String name, final String labelText, final Composite parent) {
+			super(name, labelText, parent);
+			
+			setErrorMessage("Selected file must be an executable.");
+		}
+		
+		// The superclass' implementation of checkState prevents us from getting messaged in doCheckState() in certain
+		//		failure cases - so we take our cue from this.
+		@Override
+	    protected void showErrorMessage(final String msg) {
+			showTLAPMWarningLabel();
+			
+			super.showErrorMessage(msg);
+		}
+
+		@Override
+		public boolean doCheckState() {
+			final String textFieldValue = getStringValue().trim();
+			final IPath path = new Path(textFieldValue);
+			
+			updateLocationWarningLabelForPath(path);
+
+			return (textFieldValue.length() == 0) || TLAPMExecutableLocator.pathForExecutableIsUsable(path);
+		}
+	}
+}
diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/ProverSecondPreferencePage.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/ProverSecondPreferencePage.java
deleted file mode 100644
index fe647ebca4d732b61f30b914e0667525bfa33bc4..0000000000000000000000000000000000000000
--- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/ProverSecondPreferencePage.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/**
- * 
- */
-package org.lamport.tla.toolbox.tool.prover.ui.preference;
-
-import org.eclipse.jface.preference.BooleanFieldEditor;
-import org.eclipse.jface.preference.FieldEditorPreferencePage;
-import org.eclipse.jface.preference.StringFieldEditor;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.ui.IWorkbench;
-import org.eclipse.ui.IWorkbenchPreferencePage;
-import org.lamport.tla.toolbox.tool.prover.ui.ProverUIActivator;
-
-/**
- * @author lamport
- *
- */
-public class ProverSecondPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage
-{
-
-    /*
-     * The names of the preferences for the user-defined predicates.
-     */
-    public static final String[] USER_DEFINED_PREDICATE = { "UserDefinedPredicateA", "UserDefinedPredicateB",
-            "UserDefinedPredicateC", "UserDefinedPredicateD", "UserDefinedPredicateE", "UserDefinedPredicateF"};
-    public static final String[] UPPER_CASE_LETTERS = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L" };
-    public static final String NUM_THREADS_KEY = "num_threads";
-    public static final String SOLVER_KEY = "solver";
-    public static final String SAFEFP_KEY = "safefp";
-
-    public ProverSecondPreferencePage()
-    {
-        super(GRID);
-        setPreferenceStore(ProverUIActivator.getDefault().getPreferenceStore());
-        setDescription("User-Defined Color Predicates");
-    }
-
-    /* (non-Javadoc)
-     * @see org.eclipse.jface.preference.FieldEditorPreferencePage#createFieldEditors()
-     */
-    protected void createFieldEditors()
-    {
-        // To change the number of user-defined predicates, look up all uses of
-        // USER_DEFINED_PREDICATE and USER_DEFINED.
-        for (int i = 0; i < USER_DEFINED_PREDICATE.length; i++)
-        {
-            addField(new ColorPredicateFieldEditor(USER_DEFINED_PREDICATE[i],
-                    "     Predicate " + UPPER_CASE_LETTERS[i], getFieldEditorParent()));
-        }
-
-        /*
-         * Add some space and a heading. We seem to need to add two labels to avoid screwing
-         * up the formatting.
-         */
-
-        Label lbl = new Label(getFieldEditorParent(), SWT.NONE);
-        GridData gd = new GridData();
-        gd.horizontalSpan = 2;
-        lbl.setLayoutData(gd);
-        
-        lbl = new Label(getFieldEditorParent(), SWT.NONE);
-        lbl.setLayoutData(gd);
-        lbl.setText("Advanced Execution Preferences");
-
-        addField(new ThreadsFieldEditor(NUM_THREADS_KEY, "  Num. of Threads", getFieldEditorParent()));
-        addField(new SolverFieldEditor(SOLVER_KEY, "  SMT Solver", getFieldEditorParent()));
-        // Label cpLabel = new Label(getFieldEditorParent(), SWT.NONE);
-        // cpLabel.setText("Do not trust previous results from earlier versions of provers?");
-        // GridData gd = new GridData();
-        // gd.horizontalSpan = 2;
-        // cpLabel.setLayoutData(gd);
-
-        // new Label(getFieldEditorParent(), SWT.NONE);
-        // new Label(getFieldEditorParent(), SWT.NONE);
-
-        addField(new BooleanFieldEditor(SAFEFP_KEY, "Do not trust previous results from earlier versions of provers.",
-                getFieldEditorParent()));
-        
-
-
-    }
-
-    /* (non-Javadoc)
-     * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
-     */
-    public void init(IWorkbench workbench)
-    {
-        // TODO Auto-generated method stub
-
-    }
-
-    public class ThreadsFieldEditor extends StringFieldEditor
-    {
-        public ThreadsFieldEditor(String arg0, String arg1, Composite arg2)
-        {
-            super(arg0, arg1, arg2);
-        }
-
-        public boolean doCheckState()
-        {
-            String value = this.getStringValue();
-            value = value.trim();
-            if (value.length() == 0)
-            {
-                return true;
-            }
-            try
-            {
-                int numThreads = Integer.parseInt(value);
-                return numThreads > 0;
-            } catch (NumberFormatException e)
-            {
-                return false;
-            }
-        }
-    }
-
-    public class SolverFieldEditor extends StringFieldEditor
-
-    {
-        public SolverFieldEditor(String arg0, String arg1, Composite arg2)
-        {
-            super(arg0, arg1, arg2);
-        }
-
-        public boolean doCheckState()
-        {
-        	/* Changed by DD: accept any string.
-            String value = this.getStringValue();
-            return value.indexOf('"') == -1;
-            */
-        	return true;
-        }
-    }
-
-}
diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/TLCChainedPreferenceStore.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/TLCChainedPreferenceStore.java
index 809d03bb87164bc72e74d9f7126d66dda38ca7ec..2c8bf4980754416e1332cfc3751bb0ff7455f2ba 100644
--- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/TLCChainedPreferenceStore.java
+++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/preference/TLCChainedPreferenceStore.java
@@ -37,7 +37,7 @@ public class TLCChainedPreferenceStore implements IPreferenceStore {
 	private IPreferenceStore[] fPreferenceStores;
 
 	/** Listeners on this chained preference store. */
-	private ListenerList fClientListeners= new ListenerList(ListenerList.IDENTITY);
+	private ListenerList<IPropertyChangeListener> fClientListeners= new ListenerList<IPropertyChangeListener>(ListenerList.IDENTITY);
 
 	/** Listeners on the child preference stores. */
 	private List<PropertyChangeListener> fChildListeners= new ArrayList<PropertyChangeListener>();
@@ -504,13 +504,13 @@ public class TLCChainedPreferenceStore implements IPreferenceStore {
 		if (thisValue instanceof Boolean)
 			return store.getBoolean(property) ? Boolean.TRUE : Boolean.FALSE;
 		else if (thisValue instanceof Double)
-			return new Double(store.getDouble(property));
+			return Double.valueOf(store.getDouble(property));
 		else if (thisValue instanceof Float)
-			return new Float(store.getFloat(property));
+			return Float.valueOf(store.getFloat(property));
 		else if (thisValue instanceof Integer)
-			return new Integer(store.getInt(property));
+			return Integer.valueOf(store.getInt(property));
 		else if (thisValue instanceof Long)
-			return new Long(store.getLong(property));
+			return Long.valueOf(store.getLong(property));
 		else if (thisValue instanceof String)
 			return store.getString(property);
 
@@ -529,9 +529,9 @@ public class TLCChainedPreferenceStore implements IPreferenceStore {
 		// Redirect to the corresponding preference store based on key
 		// while assuming the texteditor pref is at array pos 0
 		if ((property.toLowerCase().contains("color") && !property
-				.endsWith(ProverPreferencePage.PREDICATE))
-				|| property.contains(ProverPreferencePage.APPLIES_TO_LEAF_ONLY)
-				|| property.contains(ProverPreferencePage.STEP_STATUS_OVERVIEW)) {
+				.endsWith(ColorPredicatePreferencePage.PREDICATE))
+				|| property.contains(ColorPredicatePreferencePage.APPLIES_TO_LEAF_ONLY)
+				|| property.contains(ColorPredicatePreferencePage.STEP_STATUS_OVERVIEW)) {
 			return fPreferenceStores[0];
 		} else {
 			return fPreferenceStores[1];
diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/util/ProverHelper.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/util/ProverHelper.java
index 2f095b17f9a834445aab17275d52a13f515919a5..0cee89455e01b800108901a80e390b34dd828cc0 100644
--- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/util/ProverHelper.java
+++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/util/ProverHelper.java
@@ -39,8 +39,7 @@ import org.lamport.tla.toolbox.tool.prover.ui.output.data.ObligationStatusMessag
 import org.lamport.tla.toolbox.tool.prover.ui.output.data.StepStatusMessage;
 import org.lamport.tla.toolbox.tool.prover.ui.output.data.StepTuple;
 import org.lamport.tla.toolbox.tool.prover.ui.output.data.WarningMessage;
-import org.lamport.tla.toolbox.tool.prover.ui.preference.ProverPreferencePage;
-import org.lamport.tla.toolbox.tool.prover.ui.preference.ProverSecondPreferencePage;
+import org.lamport.tla.toolbox.tool.prover.ui.preference.MainProverPreferencePage;
 import org.lamport.tla.toolbox.tool.prover.ui.view.ObligationsView;
 import org.lamport.tla.toolbox.ui.dialog.InformationDialog;
 import org.lamport.tla.toolbox.util.AdapterFactory;
@@ -743,7 +742,7 @@ public class ProverHelper
 
             if (marker.getAttribute(SANY_IS_LEAF_ATR, false)) {
                 if (proverJob.getLeafStepMap().put(
-                        new Integer(locForAttr.beginLine()), stepTuple) != null) {
+                		Integer.valueOf(locForAttr.beginLine()), stepTuple) != null) {
                     // If there are two proof steps that begin at the same line,
                     // then raise a warning. Added by LL on 14 Feb 2013. 
                     System.out.println("Two steps start on line " + locForAttr.beginLine());
@@ -1031,7 +1030,7 @@ public class ProverHelper
                             IMarker obMarker = createObligationMarker(message.getID(), message.getLocation());
                             ObligationStatus obStatus = new ObligationStatus(null, obMarker,
                                     ColorPredicate.TO_BE_PROVED_STATE, message.getLocation(), message.getID());
-                            proverJob.getObsMap().put(new Integer(message.getID()), obStatus);
+                            proverJob.getObsMap().put(Integer.valueOf(message.getID()), obStatus);
                         }
                     }
                 };
@@ -1050,8 +1049,7 @@ public class ProverHelper
              * Update the state of the obligation. The obligation will
              * inform its parents step that its status should be updated.
              */
-            final ObligationStatus obStatus = (ObligationStatus) proverJob.getObsMap()
-                    .get(new Integer(message.getID()));
+            final ObligationStatus obStatus = (ObligationStatus) proverJob.getObsMap().get(Integer.valueOf(message.getID()));
 
             /*
              * If the obligation does not yet have a parent, then
@@ -1086,7 +1084,7 @@ public class ProverHelper
                     // and to raise an error if insanity is found.
                     while (searchLine >= 0)
                     {
-                        StepTuple stepTuple = proverJob.getLeafStepMap().get(new Integer(searchLine));
+                        StepTuple stepTuple = proverJob.getLeafStepMap().get(Integer.valueOf(searchLine));
                         if (stepTuple != null)
                         {
                             obligation.setParent(stepTuple);
@@ -1175,7 +1173,7 @@ public class ProverHelper
 
                 // the marker created
                 Map<String, Integer> markerAttributes = new HashMap<String, Integer>();
-                markerAttributes.put(OBLIGATION_ID, new Integer(id));
+                markerAttributes.put(OBLIGATION_ID, Integer.valueOf(id));
                 // markerAttributes.put(OBLIGATION_STATE, new Integer(initialState));
                 // markerAttributes.put(OBLIGATION_LOCATION, locToString(location));
 
@@ -1186,8 +1184,8 @@ public class ProverHelper
                  * For marking a region that starts at offset o and has length l, the
                  * start character is o and the end character is o+l.
                  */
-                markerAttributes.put(IMarker.CHAR_START, new Integer(obRegion.getOffset()));
-                markerAttributes.put(IMarker.CHAR_END, new Integer(obRegion.getOffset() + obRegion.getLength()));
+                markerAttributes.put(IMarker.CHAR_START, Integer.valueOf(obRegion.getOffset()));
+                markerAttributes.put(IMarker.CHAR_END, Integer.valueOf(obRegion.getOffset() + obRegion.getLength()));
 
                 IMarker marker = module.createMarker(OBLIGATION_MARKER);
                 marker.setAttributes(markerAttributes);
@@ -1234,7 +1232,7 @@ public class ProverHelper
      */
     public static void newStepStatusMessage(StepStatusMessage status, ProverJob proverJob)
     {
-        proverJob.getStepMessageMap().put(new Integer(status.getLocation().beginLine()), status);
+        proverJob.getStepMessageMap().put(Integer.valueOf(status.getLocation().beginLine()), status);
 
         /*
          * The following was commented out because the proof step status markers are now always
@@ -1503,9 +1501,9 @@ public class ProverHelper
                     {
                         // the attributes for the new marker to be created
                         Map<String, Integer> markerAttributes = new HashMap<String, Integer>(2);
-                        markerAttributes.put(IMarker.CHAR_START, new Integer(newCharStart));
-                        markerAttributes.put(IMarker.CHAR_END, new Integer(newCharEnd));
-                        markerAttributes.put(IMarker.LINE_NUMBER, new Integer(stringToLoc(
+                        markerAttributes.put(IMarker.CHAR_START, Integer.valueOf(newCharStart));
+                        markerAttributes.put(IMarker.CHAR_END, Integer.valueOf(newCharEnd));
+                        markerAttributes.put(IMarker.LINE_NUMBER, Integer.valueOf(stringToLoc(
                                 sanyMarker.getAttribute(SANY_LOC_ATR, "")).beginLine()));
 
                         // create the new marker and set its attributes
@@ -1918,7 +1916,7 @@ public class ProverHelper
     public static void setThreadsOption(List<String> command)
     {
         String numThreadsText = ProverUIActivator.getDefault().getPreferenceStore().getString(
-                ProverSecondPreferencePage.NUM_THREADS_KEY);
+        		MainProverPreferencePage.NUM_THREADS_KEY);
         if (numThreadsText.trim().length() == 0)
         {
             return;
@@ -1935,7 +1933,7 @@ public class ProverHelper
     public static void setSolverOption(List<String> command)
     {
         String solverText = ProverUIActivator.getDefault().getPreferenceStore().getString(
-                ProverSecondPreferencePage.SOLVER_KEY);
+        		MainProverPreferencePage.SOLVER_KEY);
         if (solverText.trim().length() == 0)
         {
             return;
@@ -1952,7 +1950,7 @@ public class ProverHelper
     public static void setSafeFPOption(List<String> command)
     {
         boolean safefp = ProverUIActivator.getDefault().getPreferenceStore().getBoolean(
-                ProverSecondPreferencePage.SAFEFP_KEY);
+        		MainProverPreferencePage.SAFEFP_KEY);
         if (safefp)
         {
             command.add(ITLAPMOptions.SAFEFP);
diff --git a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/util/TLAPMExecutableLocator.java b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/util/TLAPMExecutableLocator.java
index c5e60aad62a9a4773c2f1d75e2e8db48e65f2422..65e610850fcc879adf298009606358389933d72d 100644
--- a/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/util/TLAPMExecutableLocator.java
+++ b/org.lamport.tla.toolbox.tool.prover/src/org/lamport/tla/toolbox/tool/prover/ui/util/TLAPMExecutableLocator.java
@@ -1,79 +1,145 @@
 package org.lamport.tla.toolbox.tool.prover.ui.util;
 
+import java.io.File;
+
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
 import org.lamport.tla.toolbox.Activator;
+import org.lamport.tla.toolbox.tool.prover.ui.ProverUIActivator;
+import org.lamport.tla.toolbox.tool.prover.ui.preference.MainProverPreferencePage;
 
 /**
  * A singleton which provides reference to the {@link IPath} instances for the TLAPM executable, should one exist, and
  * 	the Cygwin path, should the platform be appropriate.
  */
 public class TLAPMExecutableLocator {
+	private static final IPath DEFAULT_NIX_INSTALL_DIRECTORY = new Path("/usr/local/bin");
+	private static final String NIX_EXECUTABLE_NAME = "tlapm";
+	private static final String WINDOWS_EXECUTABLE_NAME = "tlapm.exe";
+	
 	public static final TLAPMExecutableLocator INSTANCE = new TLAPMExecutableLocator();
 	
+	public static boolean pathForExecutableIsUsable(final IPath path) {
+		if (path == null) {
+			return false;
+		}
+		
+		final File f = path.toFile();
+		return ((f != null)
+				&& f.exists()
+				&& f.canExecute());
+	}
 	
-	private final IPath tlapmPath;
+	
+	private IPath tlapmPath;
 	private final IPath cygwinPath;
 	
+	// The enclosing bundle is still Java 5 for some reason - move this to a lambda with Java 8+
+	private final IPropertyChangeListener preferenceChangeListener = new IPropertyChangeListener() {
+		public void propertyChange(final PropertyChangeEvent event) {
+			if (MainProverPreferencePage.EXECUTABLE_LOCATION_KEY.equals(event.getProperty())) {
+				final String location = (String) event.getNewValue();
+
+				// Validation occurred in the preference page, so if we are getting this notification, the path is ok
+				tlapmPath = new Path(location);
+			}
+		}
+	};
+	
 	private TLAPMExecutableLocator() {
-        // the default tlapm command on all systems if no complete tlapm path can be found.
-        IPath tlapm = new Path("tlapm");
-        IPath cygwin = null;
+		final IPreferenceStore ips = ProverUIActivator.getDefault().getPreferenceStore();
+		final String existingTLAPMPath = ips.getString(MainProverPreferencePage.EXECUTABLE_LOCATION_KEY);
 
+        IPath tlapm = null;
+		if (existingTLAPMPath.length() > 0) {
+			final IPath path = new Path(existingTLAPMPath);
+			
+			if (pathForExecutableIsUsable(path)) {
+				tlapm = path;
+			}
+		}
+		
+        IPath cygwin = null;
 		if (Platform.getOS().equals(Platform.OS_WIN32)) {
             /*
              * Check if "C:/cygwin/usr/local/bin/tlapm.exe" exists.
              * If it does exist, that is the path. Else, the path is "tlapm". Setting
              * the path to "tlapm" assumes that it is in the system path.
              */
-            final IPath defaultPath = new Path("C:/cygwin/usr/local/bin/tlapm.exe");
-            final IPath defaultPath64 = new Path("C:/cygwin64/usr/local/bin/tlapm.exe");
+            final IPath defaultPath = new Path("C:/cygwin/usr/local/bin/" + WINDOWS_EXECUTABLE_NAME);
+            final IPath defaultPath64 = new Path("C:/cygwin64/usr/local/bin/" + WINDOWS_EXECUTABLE_NAME);
 
-			if (defaultPath.toFile().exists()) {
-				tlapm = defaultPath;
-
-                /*
-                 * If cygwin path is specified, use that. If not
-                 * use the default cygwin path : 
-                 * "C:\cygwin\bin"
-                 */
-				cygwin = new Path("C:\\cygwin\\bin");
-            }
             /*
              * Nowadays 64bit systems are common, thus also check c:/cygwin64/... preferring to use that
              */
-			else if (defaultPath64.toFile().exists()) {
-				tlapm = defaultPath64;
+			if (defaultPath64.toFile().exists()) {
+				if (tlapm == null) {
+					tlapm = defaultPath64;
+				}
 				cygwin = new Path("C:\\cygwin64\\bin");
+			} else if (defaultPath.toFile().exists()) {
+				if (tlapm == null) {
+					tlapm = defaultPath;
+				}
+				cygwin = new Path("C:\\cygwin\\bin");
+            } else if (tlapm == null) {
+            	// Hopefully the Windows Path will sort it out
+            	tlapm = new Path(WINDOWS_EXECUTABLE_NAME);
             }
-		} else if (Platform.getOS().equals(Platform.OS_MACOSX) || Platform.getOS().equals(Platform.OS_LINUX)) {
-            /*
-             * Check if "/usr/local/bin/tlapm" exists.
-             * If it does exist, that is the path. Else, the path is tlapm. Setting
-             * the path to "tlapm" assumes that it is in the system path.
-             */
-            final IPath defaultPath = new Path("/usr/local/bin/tlapm");
-
-			if (defaultPath.toFile().exists()) {
-				tlapm = defaultPath;
-            }
-		} else {
-			Activator.getDefault().logError("Platform [" + Platform.getOS() + "] is not supported.");
-        }
+		} else if (tlapm == null) {
+			if (Platform.getOS().equals(Platform.OS_MACOSX) || Platform.getOS().equals(Platform.OS_LINUX)) {
+				final String[] paths = System.getenv("PATH").split(":");
+				boolean defaultDirectoryIncluded = false;
+				
+				for (final String path : paths) {
+					final IPath parent = new Path(path);
+					
+					if (parent.equals(DEFAULT_NIX_INSTALL_DIRECTORY)) {
+						defaultDirectoryIncluded = true;
+					}
+					
+					final IPath executable = parent.append(NIX_EXECUTABLE_NAME);
+					if (pathForExecutableIsUsable(executable)) {
+						tlapm = executable;
+						break;
+					}
+				}
+				
+				if (!defaultDirectoryIncluded && (tlapm == null)) {
+					final String fullPath = DEFAULT_NIX_INSTALL_DIRECTORY.toFile().getAbsolutePath()
+							+ File.separatorChar + NIX_EXECUTABLE_NAME;
+					final IPath executable = new Path(fullPath);
+					if (pathForExecutableIsUsable(executable)) {
+						tlapm = executable;
+					}
+				}
+				
+				if (tlapm == null) {
+					// In some miraculous case the ProcessBuilder would get a different PATH environment and then
+					//		find this, but as of 1.6.1 this is moot and will result in the menu items able to launch
+					//		the prover not being enabled anyway...
+					tlapm = new Path(NIX_EXECUTABLE_NAME);
+				}
+			} else {
+				Activator.getDefault().logError("Platform [" + Platform.getOS() + "] is not supported.");
+	        }
+		}
 
 		tlapmPath = tlapm;
 		cygwinPath = cygwin;
+		
+		ips.addPropertyChangeListener(preferenceChangeListener);
 	}
-
+	
 	/**
 	 * @return true if the path to TLAPM exists and there is a file there which can be executed
 	 */
 	public boolean tlapmDoesExist() {
-		return ((tlapmPath != null)
-					&& (tlapmPath.toFile() != null)
-					&& tlapmPath.toFile().exists()
-					&& tlapmPath.toFile().canExecute());
+		return pathForExecutableIsUsable(tlapmPath);
 	}
 	
 	/**
diff --git a/org.lamport.tla.toolbox.tool.tla2tex/.classpath b/org.lamport.tla.toolbox.tool.tla2tex/.classpath
index 64c5e31b7a264082f4c1dfdabb8097de820e66ce..4f83b2397ec8255a7a35e8ab04a3f65a808ccfea 100644
--- a/org.lamport.tla.toolbox.tool.tla2tex/.classpath
+++ b/org.lamport.tla.toolbox.tool.tla2tex/.classpath
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/org.lamport.tla.toolbox.tool.tla2tex/.settings/org.eclipse.jdt.core.prefs b/org.lamport.tla.toolbox.tool.tla2tex/.settings/org.eclipse.jdt.core.prefs
index 932f2e378366d7885d7856f37cb22e6bbf5506a0..87b7a7a3a608ba67a672963449fc325e55a14531 100644
--- a/org.lamport.tla.toolbox.tool.tla2tex/.settings/org.eclipse.jdt.core.prefs
+++ b/org.lamport.tla.toolbox.tool.tla2tex/.settings/org.eclipse.jdt.core.prefs
@@ -1,12 +1,13 @@
-#Mon May 09 12:19:33 CEST 2011
 eclipse.preferences.version=1
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.5
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/TLA2TeXActivator.java b/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/TLA2TeXActivator.java
index ac224a1061d5bf5ee165a8f2472c5348e2b80502..0cb8ed1669466874e48756672aa5713ca832c08a 100644
--- a/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/TLA2TeXActivator.java
+++ b/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/TLA2TeXActivator.java
@@ -1,5 +1,9 @@
 package org.lamport.tla.toolbox.tool.tla2tex;
 
+import java.io.File;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.util.IPropertyChangeListener;
 import org.eclipse.jface.util.PropertyChangeEvent;
 import org.lamport.tla.toolbox.AbstractTLCActivator;
@@ -12,12 +16,13 @@ import com.abstratt.graphviz.GraphVizActivator.DotMethod;
 /**
  * The activator class controls the plug-in life cycle
  */
-public class TLA2TeXActivator extends AbstractTLCActivator
-{
-
+public class TLA2TeXActivator extends AbstractTLCActivator {
     // The plug-in ID
     public static final String PLUGIN_ID = "org.lamport.tla.toolbox.tool.tlatex";
 
+    private static final boolean IS_WINDOWS = Platform.OS_WIN32.equals(Platform.getOS());
+    private static final String USR_LOCAL_BIN_PATH = "/usr/local/bin/dot";
+    
     // The shared instance
     private static TLA2TeXActivator plugin;
 
@@ -36,17 +41,7 @@ public class TLA2TeXActivator extends AbstractTLCActivator
 	private IPropertyChangeListener listener = new IPropertyChangeListener() {
 		public void propertyChange(PropertyChangeEvent event) {
 			if (ITLA2TeXPreferenceConstants.DOT_COMMAND.equals(event.getProperty())) {
-				final String dotCommand = (String) event.getNewValue();
-				if ("dot".equals(dotCommand)) {
-					// Setting it to "dot" implies auto lookup.
-					TLA2TeXActivator.this.logInfo("dot command set to automatic lookup.");
-					GraphVizActivator.getInstance().setDotSearchMethod(DotMethod.AUTO);
-				} else {
-					// Explicit path is given.
-					TLA2TeXActivator.this.logInfo("dot command set to: " + dotCommand);
-					GraphVizActivator.getInstance().setDotSearchMethod(DotMethod.MANUAL);
-					GraphVizActivator.getInstance().setManualDotPath(dotCommand);
-				}
+				configureGraphViz((String)event.getNewValue());
 			}
 		}
 	};
@@ -54,8 +49,7 @@ public class TLA2TeXActivator extends AbstractTLCActivator
     /**
      * The constructor
      */
-    public TLA2TeXActivator()
-    {
+    public TLA2TeXActivator() {
     	super(PLUGIN_ID);
     }
 
@@ -63,12 +57,13 @@ public class TLA2TeXActivator extends AbstractTLCActivator
      * (non-Javadoc)
      * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
      */
-    public void start(BundleContext context) throws Exception
-    {
+    public void start(BundleContext context) throws Exception {
         super.start(context);
         plugin = this;
         
-		getPreferenceStore().addPropertyChangeListener(listener);
+		final IPreferenceStore preferenceStore = getPreferenceStore();
+		preferenceStore.addPropertyChangeListener(listener);
+		configureGraphViz(preferenceStore.getString(ITLA2TeXPreferenceConstants.DOT_COMMAND));
     }
 
     /*
@@ -90,4 +85,32 @@ public class TLA2TeXActivator extends AbstractTLCActivator
     {
         return plugin;
     }
+    
+    private void configureGraphViz(final String dotLocationPreferenceValue) {
+    	// This will be blank if the user has never entered a value in the preference panel
+		String dotCommand = dotLocationPreferenceValue;
+		
+		// Per GitHub #412
+		if (!IS_WINDOWS
+					&& ((dotCommand == null)
+							|| (dotCommand.trim().length() == 0)
+							|| "dot".equals(dotCommand))) {
+			final File f = new File(USR_LOCAL_BIN_PATH);
+			
+			if (f.exists() && f.canExecute()) {
+				dotCommand = USR_LOCAL_BIN_PATH;
+			}
+		}
+		
+		if ("dot".equals(dotCommand)) {
+			// Setting it to "dot" implies auto lookup.
+			logInfo("dot command set to automatic lookup.");
+			GraphVizActivator.getInstance().setDotSearchMethod(DotMethod.AUTO);
+		} else {
+			// Explicit path is given.
+			logInfo("dot command set to: " + dotCommand);
+			GraphVizActivator.getInstance().setDotSearchMethod(DotMethod.MANUAL);
+			GraphVizActivator.getInstance().setManualDotPath(dotCommand);
+		}
+    }
 }
diff --git a/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/handler/OperatingSystemPDFRunnable.java b/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/handler/OperatingSystemPDFRunnable.java
new file mode 100644
index 0000000000000000000000000000000000000000..1e9d4eb5ea3719b6be2c8dbea233c59a33f03206
--- /dev/null
+++ b/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/handler/OperatingSystemPDFRunnable.java
@@ -0,0 +1,25 @@
+package org.lamport.tla.toolbox.tool.tla2tex.handler;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.lamport.tla.toolbox.tool.tla2tex.TLA2TeXActivator;
+
+public class OperatingSystemPDFRunnable extends AbstractPDFViewerRunnable {
+	/** We have no need for any of these parameters but our superclass is coded to assert their non-null-ness. **/
+	public OperatingSystemPDFRunnable(final ProducePDFHandler handler, final IWorkbenchPartSite site, final IResource aSpecFile) {
+		super(handler, site, aSpecFile);
+	}
+
+	public void run() {
+        monitor.subTask("Opening PDF File");
+        
+		final String openCommand = "open " + outputFileName;
+		try {
+			Runtime.getRuntime().exec(openCommand);
+		} catch (final Exception e) {
+			TLA2TeXActivator.getDefault().logError("Unable to execute 'open' command on PDF.", e);
+		}
+
+        monitor.worked(1);
+	}
+}
diff --git a/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/handler/ProducePDFHandler.java b/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/handler/ProducePDFHandler.java
index e8f782cacd1ad13be9841f1edb952e63a64eb2ed..83ef180793fe7ac20a42a40939e76e4ce76a0b7d 100644
--- a/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/handler/ProducePDFHandler.java
+++ b/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/handler/ProducePDFHandler.java
@@ -13,8 +13,13 @@ import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.PreferencesUtil;
 import org.lamport.tla.toolbox.tool.tla2tex.TLA2TeXActivator;
 import org.lamport.tla.toolbox.tool.tla2tex.preference.ITLA2TeXPreferenceConstants;
 import org.lamport.tla.toolbox.ui.handler.SaveDirtyEditorAbstractHandler;
@@ -42,27 +47,30 @@ public class ProducePDFHandler extends SaveDirtyEditorAbstractHandler {
 	 * org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands
 	 * .ExecutionEvent)
 	 */
-	public Object execute(ExecutionEvent event) {
+	public Object execute(final ExecutionEvent event) {
 		if (!saveDirtyEditor(event)) {
 			return null;
 		}
 
-		boolean useEmbeddedViewer = TLA2TeXActivator.getDefault()
-				.getPreferenceStore()
-				.getBoolean(ITLA2TeXPreferenceConstants.EMBEDDED_VIEWER);
+		final IPreferenceStore preferenceStore = TLA2TeXActivator.getDefault().getPreferenceStore();
+		final boolean useEmbeddedViewer = preferenceStore.getBoolean(ITLA2TeXPreferenceConstants.EMBEDDED_VIEWER);
+		final boolean osHandlesPDF = preferenceStore.getBoolean(ITLA2TeXPreferenceConstants.HAVE_OS_OPEN_PDF);
 		
-		IEditorInput editorInput = activeEditor.getEditorInput();
+		final IEditorInput editorInput = activeEditor.getEditorInput();
 		if (editorInput instanceof IFileEditorInput) {
-			final IResource fileToTranslate = ((IFileEditorInput) editorInput)
-					.getFile();
-			if (fileToTranslate != null
-					&& ResourceHelper.isModule(fileToTranslate)) {
-				if (useEmbeddedViewer) {
-					runPDFJob(new EmbeddedPDFViewerRunnable(this, activeEditor.getSite(), fileToTranslate),
-							fileToTranslate);
+			final IResource fileToTranslate = ((IFileEditorInput) editorInput).getFile();
+			if ((fileToTranslate != null) && ResourceHelper.isModule(fileToTranslate)) {
+				final AbstractPDFViewerRunnable pdfViewer;
+				
+				if (osHandlesPDF) {
+					pdfViewer = new OperatingSystemPDFRunnable(this, activeEditor.getSite(), fileToTranslate);
+				} else if (useEmbeddedViewer) {
+					pdfViewer = new EmbeddedPDFViewerRunnable(this, activeEditor.getSite(), fileToTranslate);
 				} else {
-					runPDFJob(new StandalonePDFViewerRunnable(this, activeEditor.getSite(), fileToTranslate), fileToTranslate);
+					pdfViewer = new StandalonePDFViewerRunnable(this, activeEditor.getSite(), fileToTranslate);
 				}
+				
+				runPDFJob(pdfViewer, fileToTranslate);
 			}
 		}
 
@@ -88,18 +96,12 @@ public class ProducePDFHandler extends SaveDirtyEditorAbstractHandler {
 	 * @param tlaEditorAndPDFViewer
 	 * @param fileToTranslate
 	 */
-	void runPDFJob(final AbstractPDFViewerRunnable runnable, 
-			final IResource fileToTranslate) {
+	void runPDFJob(final AbstractPDFViewerRunnable runnable, final IResource fileToTranslate) {
 		Job tla2TexJob = new WorkspaceJob("Produce PDF") {
-
 			public IStatus runInWorkspace(final IProgressMonitor monitor) {
-
 				try {
-
-					Vector<String> tla2texArgs = new Vector<String>();
-
-					IPreferenceStore preferenceStore = TLA2TeXActivator
-							.getDefault().getPreferenceStore();
+					final Vector<String> tla2texArgs = new Vector<String>();
+					final IPreferenceStore preferenceStore = TLA2TeXActivator.getDefault().getPreferenceStore();
 
 					if (preferenceStore
 							.getBoolean(ITLA2TeXPreferenceConstants.SHADE_COMMENTS)) {
@@ -175,50 +177,18 @@ public class ProducePDFHandler extends SaveDirtyEditorAbstractHandler {
 						// to the user.
 						UIHelper.runUISync(runnable);
 					} else {
-						UIHelper.runUISync(new Runnable() {
-
-							public void run() {
-								MessageDialog
-										.openError(UIHelper.getShellProvider()
-												.getShell(),
-												"PDF file not found",
-												"Could not locate a pdf file for the module.");
-							}
-						});
+						final Runnable r = () -> {
+							MessageDialog.openError(UIHelper.getShellProvider().getShell(), "PDF file not found",
+									"Could not locate a pdf file for the module.");
+						};
+						
+						UIHelper.runUIAsync(r);
 					}
-				} catch (final TLA2TexException e) {
-					TLA2TeXActivator.getDefault()
-							.logError(
-									"Error while producing pdf file: "
-											+ e.getMessage(), e);
-					UIHelper.runUISync(new Runnable() {
-
-						public void run() {
-							MessageDialog.openError(UIHelper.getShellProvider()
-									.getShell(), "PDF Production Error", e
-									.getMessage());
-						}
-					});
-
-				} catch (final CoreException e) {
-					TLA2TeXActivator.getDefault()
-					.logError(
-							"Error while producing pdf file: "
-									+ e.getMessage(), e);
-					UIHelper.runUISync(new Runnable() {
-
-						public void run() {
-							MessageDialog.openError(UIHelper.getShellProvider()
-									.getShell(), "PDF Production Error", e
-									.getMessage());
-						}
-					});
-				} finally {
-
+				} catch (final TLA2TexException | CoreException e) {
+					handleJobException(e);
 				}
 				return Status.OK_STATUS;
 			}
-
 		};
 
 		// setUser(false) to not popup a modal dialog on each PDF generation.
@@ -226,4 +196,25 @@ public class ProducePDFHandler extends SaveDirtyEditorAbstractHandler {
 		tla2TexJob.setPriority(Job.LONG);
 		tla2TexJob.schedule();
 	}
+	
+	private void handleJobException(final Exception e) {
+		TLA2TeXActivator.getDefault().logError("Error while producing pdf file: " + e.getMessage(), e);
+
+		final Runnable r = () -> {
+			final Shell s = PlatformUI.getWorkbench().getDisplay().getActiveShell();
+			final int response = MessageDialog.open(MessageDialog.ERROR, s, "PDF Production Problem",
+					"The following error was encountered while attempting to generate the PDF - perhaps you "
+						+ "have not set a full path to pdflatex in the preferences?\n\n" + e.getMessage(),
+					SWT.NONE, "Open Preferences", "Ok");
+			
+			if (response == 0) {
+				final PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn(s, 
+						"toolbox.tool.tla2tex.preference.TLA2TeXPreferencePage",
+						new String[] { "toolbox.tool.tla2tex.preference.TLA2TeXPreferencePage" }, null);
+				dialog.open();
+			}
+		};
+		
+		UIHelper.runUIAsync(r);
+	}
 }
diff --git a/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/handler/StandalonePDFViewerRunnable.java b/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/handler/StandalonePDFViewerRunnable.java
index c6e320d9a295980be19aeeef53681bf5c2589060..ea507e94202ded12638ddfc199b8a40fd871f64b 100644
--- a/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/handler/StandalonePDFViewerRunnable.java
+++ b/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/handler/StandalonePDFViewerRunnable.java
@@ -29,6 +29,7 @@ public class StandalonePDFViewerRunnable extends AbstractPDFViewerRunnable {
 	/* (non-Javadoc)
 	 * @see org.lamport.tla.toolbox.tool.tla2tex.handler.AbstractPDFViewerRunnable#preUpdate()
 	 */
+	@Override
 	protected void preUpdate() {
 		((PDFBrowser) part).setBlank();
 	}
diff --git a/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/preference/ITLA2TeXPreferenceConstants.java b/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/preference/ITLA2TeXPreferenceConstants.java
index d0ab35515f2c5e708cc94a34b8463bb1175e7822..03fc5a279d3e0e3dcf9fd42aefd4a2c8e99c870d 100644
--- a/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/preference/ITLA2TeXPreferenceConstants.java
+++ b/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/preference/ITLA2TeXPreferenceConstants.java
@@ -43,6 +43,11 @@ public interface ITLA2TeXPreferenceConstants
      */
     public static final String EMBEDDED_VIEWER = "embeddedViewer";
 
+    /**
+     * True if the operating system should open the PDF - currently only used on macOS
+     */
+    public static final String HAVE_OS_OPEN_PDF = "osHandlesPDF";
+
 	/**
 	 * Specify the full qualified path to GraphViz's dot executable.
 	 */
diff --git a/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/preference/TLA2TeXPreferenceInitializer.java b/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/preference/TLA2TeXPreferenceInitializer.java
index daf862690193274250d7792264948f11f5460a7a..ff065ef9ee3fc616541c1236e2469568b91bf19a 100644
--- a/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/preference/TLA2TeXPreferenceInitializer.java
+++ b/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/preference/TLA2TeXPreferenceInitializer.java
@@ -21,12 +21,14 @@ public class TLA2TeXPreferenceInitializer extends AbstractPreferenceInitializer
 		store.setDefault(ITLA2TeXPreferenceConstants.DOT_COMMAND, "dot");
 		store.setDefault(ITLA2TeXPreferenceConstants.LATEX_COMMAND, "pdflatex");
 		store.setDefault(ITLA2TeXPreferenceConstants.GRAY_LEVEL, "0.85");
+		store.setDefault(ITLA2TeXPreferenceConstants.HAVE_OS_OPEN_PDF, false);
 		if (Platform.getOS().equals(Platform.OS_MACOSX)) {
 			// Support for the built-in viewer has ended on MACOSX, thus disable
 			// even if user enabled it in an earlier Toolbox release.
 			store.setValue(ITLA2TeXPreferenceConstants.EMBEDDED_VIEWER, false);
 		} else {
 			store.setDefault(ITLA2TeXPreferenceConstants.EMBEDDED_VIEWER, true);
+			store.setValue(ITLA2TeXPreferenceConstants.HAVE_OS_OPEN_PDF, false);
 		}
 	}
 }
diff --git a/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/preference/TLA2TeXPreferencePage.java b/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/preference/TLA2TeXPreferencePage.java
index 479777961943a0bbd992c03f5c074bc175dc3c1b..8d3ca495620a46045d27f99d6d9c2bb78bc910f3 100644
--- a/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/preference/TLA2TeXPreferencePage.java
+++ b/org.lamport.tla.toolbox.tool.tla2tex/src/org/lamport/tla/toolbox/tool/tla2tex/preference/TLA2TeXPreferencePage.java
@@ -37,11 +37,16 @@ public class TLA2TeXPreferencePage extends FieldEditorPreferencePage implements
 	}
 
 	protected void createFieldEditors() {
-		if (!Platform.getOS().equals(Platform.OS_MACOSX)) {
+		if (Platform.getOS().equals(Platform.OS_MACOSX)) {
+			addField(new BooleanFieldEditor(
+					ITLA2TeXPreferenceConstants.HAVE_OS_OPEN_PDF,
+					"Have your OS open PDFs", getFieldEditorParent()));
+		} else {
 			addField(new BooleanFieldEditor(
 					ITLA2TeXPreferenceConstants.EMBEDDED_VIEWER,
 					"&Use built-in PDF viewer", getFieldEditorParent()));
 		}
+		
 		// Preference to regenerate PDF upon spec save?
 		addField(new BooleanFieldEditor(
 				ITLA2TeXPreferenceConstants.AUTO_REGENERATE, "&Regenerate pretty-printed PDF on spec save (takes effect once spec re-opened).",
diff --git a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/util/ModelHelperTest.java b/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/util/ModelHelperTest.java
index 339c3bf6b9dd8b06a2a0f0d221f8ecb0d75ddbb3..8dfcf2b16349afb88377dae71c7cdd246d55ec61 100644
--- a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/util/ModelHelperTest.java
+++ b/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/util/ModelHelperTest.java
@@ -46,9 +46,9 @@ import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
 import org.eclipse.debug.core.ILaunchDelegate;
 import org.junit.Assert;
 import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants;
-import org.lamport.tla.toolbox.tool.tlc.model.Assignment;
 
 import junit.framework.TestCase;
+import tlc2.model.Assignment;
 
 /**
  * Test for toolkit methods
diff --git a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/util/OutputRegexTest.java b/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/util/OutputRegexTest.java
index 7713f8d49f90f76b2206baa2c7abc42b2b46961d..7f6253141a52201232592e267e82db0ca0334790 100755
--- a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/util/OutputRegexTest.java
+++ b/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/util/OutputRegexTest.java
@@ -5,18 +5,17 @@ import java.util.regex.Matcher;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.Document;
 import org.eclipse.jface.text.IRegion;
-import org.lamport.tla.toolbox.tool.tlc.model.ModelWriter;
 
 import junit.framework.TestCase;
 import tla2sany.st.Location;
+import tlc2.output.SpecWriterUtilities;
+import util.TLAConstants;
 
 /**
  * Tests the regex matcher for generated ids
  * @author Simon Zambrovski
  */
-public class OutputRegexTest extends TestCase
-{
-
+public class OutputRegexTest extends TestCase {
     private String id;
     private final String random = " ksj fhksd hfskd hfsdk hsdk hj ";
     private final String random2 = " lksjfh ksfh ksdhf sdkhf sdk hj ";
@@ -26,18 +25,18 @@ public class OutputRegexTest extends TestCase
     protected void setUp() throws Exception
     {
         super.setUp();
-        id = ModelWriter.getValidIdentifier(ModelWriter.CONSTANT_SCHEME);
+        id = SpecWriterUtilities.getValidIdentifier(TLAConstants.Schemes.CONSTANT_SCHEME);
     }
 
     public void testRegexMatchId()
     {
         // exact match
-        assertTrue(ModelWriter.ID_MATCHER.matcher(id).matches());
+        assertTrue(SpecWriterUtilities.ID_MATCHER.matcher(id).matches());
     }
 
     public void testRegexFindId()
     {
-        Matcher matcher = ModelWriter.ID_MATCHER.matcher(random + id + random2);
+        Matcher matcher = SpecWriterUtilities.ID_MATCHER.matcher(random + id + random2);
         // find the id inside of the text
         assertTrue(matcher.find());
         // start points to the beginning
@@ -47,12 +46,12 @@ public class OutputRegexTest extends TestCase
         // here is how the content can be extracted
         assertEquals(id, (random + id + random2).substring(matcher.start(), matcher.end()));
         // not a false positive
-        assertFalse(ModelWriter.ID_MATCHER.matcher(random + random2).find());
+        assertFalse(SpecWriterUtilities.ID_MATCHER.matcher(random + random2).find());
     }
 
     public void testRegexFindManyIds()
     {
-        Matcher matcher = ModelWriter.ID_MATCHER.matcher(random + id + random2 + id + random);
+        Matcher matcher = SpecWriterUtilities.ID_MATCHER.matcher(random + id + random2 + id + random);
         // find the id inside of the text
         assertTrue(matcher.find());
         // start points to the beginning
@@ -68,7 +67,7 @@ public class OutputRegexTest extends TestCase
      */
     public void testFindIds()
     {
-        IRegion[] regions = ModelWriter.findIds(random + id + random2 + id + random);
+        IRegion[] regions = ModelHelper.findIds(random + id + random2 + id + random);
         assertEquals(2, regions.length);
         // start points to the beginning
         assertEquals(random.length(), regions[0].getOffset());
@@ -82,7 +81,7 @@ public class OutputRegexTest extends TestCase
     
     public void testFindIds2()
     {
-        IRegion[] regions = ModelWriter.findIds(random + id + random2 + id + random);
+        IRegion[] regions = ModelHelper.findIds(random + id + random2 + id + random);
         Document doc = new Document(random + id + random2 + id + random);
         
         try
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/.settings/org.eclipse.jdt.core.prefs b/org.lamport.tla.toolbox.tool.tlc.ui.test/.settings/org.eclipse.jdt.core.prefs
index 641952ff4fbdf96b83dd1e9972087361a7222f45..3a21537071bf4118b9e1ee864cb4bc258aa48211 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui.test/.settings/org.eclipse.jdt.core.prefs
+++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/.settings/org.eclipse.jdt.core.prefs
@@ -1,12 +1,11 @@
-#Fri May 06 14:24:07 CEST 2011
 eclipse.preferences.version=1
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.compliance=1.8
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.5
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.tool.tlc.ui.test/META-INF/MANIFEST.MF
index 021ac3a01b0e951c18ebc634bc0461e7feaa93b0..5adedd499276a9a4f543b6adaeea3c67b48bf8ef 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui.test/META-INF/MANIFEST.MF
+++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/META-INF/MANIFEST.MF
@@ -7,9 +7,10 @@ Bundle-Version: 1.0.0.qualifier
 Require-Bundle: org.lamport.tla.toolbox;bundle-version="1.0.0",
  org.eclipse.jface.text;bundle-version="3.6.1",
  org.junit;bundle-version="3.8.2",
- org.easymock;bundle-version="2.4.0"
+ org.easymock;bundle-version="2.4.0",
+ org.eclipse.core.resources
 Import-Package: org.osgi.framework;version="1.3.0"
-Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-Vendor: Leslie Lamport, Markus Alexander Kuppe
 Bundle-ActivationPolicy: lazy
 Automatic-Module-Name: org.lamport.tla.toolbox.tool.tlc.ui.test
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformationTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..eb94a5d95911ce4f206d6c91d41864ee152ea3ab
--- /dev/null
+++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformationTest.java
@@ -0,0 +1,301 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package org.lamport.tla.toolbox.tool.tlc.output.data;
+
+import static org.junit.Assert.assertTrue;
+import static org.lamport.tla.toolbox.tool.tlc.output.data.Representation.*;
+import static org.lamport.tla.toolbox.tool.tlc.output.data.Representation.Grouping.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.TreeSet;
+import java.util.function.Function;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jface.text.TextPresentation;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.lamport.tla.toolbox.tool.tlc.output.data.Representation.Grouping;
+
+public class CoverageInformationTest {
+
+	private static ModuleCoverageInformation mci;
+
+	@BeforeClass
+	public static void setup() throws IOException, CoreException {
+		// Create an IFile instance (this is a witness of why the Eclipse Resource API
+		// is probably one of the worst APIs ever with the exception of those that I've
+		// written).
+		final String name = "CoverageInformationTestProject";
+		final IProjectDescription desc = ResourcesPlugin.getWorkspace().newProjectDescription(name);
+		final IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(name);
+		project.create(desc, new NullProgressMonitor());
+		project.open(new NullProgressMonitor());
+		final IFile file = project.getFile("Simple.tla");
+		final InputStream source = CoverageInformationTest.class.getResourceAsStream("Simple.tla");
+		file.create(source, IFile.FORCE, null);
+
+		final CoverageInformation ci = new CoverageInformation(Arrays.asList(new IFile[] { file }));
+
+		ci.add(ActionInformationItem.parseInit("<Init line 28, col 1 to line 28, col 4 of module Simple>: 3:3", "M"));
+		ci.add(CoverageInformationItem.parse("line 29, col 12 to line 29, col 35 of module Simple: 1", "M"));
+		ci.add(CoverageInformationItem.parse("line 30, col 12 to line 30, col 35 of module Simple: 1", "M"));
+		ci.add(CoverageInformationItem.parse("line 31, col 12 to line 31, col 21 of module Simple: 1", "M"));
+		ci.add(CoverageInformationItem.parse("line 32, col 12 to line 32, col 42 of module Simple: 3", "M"));
+
+		ci.add(ActionInformationItem.parseNext("<a line 34, col 1 to line 34, col 7 of module Simple>: 63:99", "M"));
+		ci.add(CoverageInformationItem.parse("line 34, col 15 to line 34, col 28 of module Simple: 558", "M"));
+		ci.add(CoverageInformationItem.parse("|line 34, col 15 to line 34, col 22 of module Simple: 459", "M"));
+		ci.add(CoverageInformationItem.parse("line 35, col 15 to line 35, col 41 of module Simple: 99", "M"));
+		ci.add(CoverageInformationItem.parse("line 36, col 15 to line 36, col 45 of module Simple: 99", "M"));
+		ci.add(CoverageInformationItem.parse("line 37, col 15 to line 37, col 30 of module Simple: 99", "M"));
+		ci.add(CoverageInformationItem.parse("line 38, col 15 to line 38, col 27 of module Simple: 99", "M"));
+		ci.add(CoverageInformationItem.parse("|line 7, col 15 to line 7, col 65 of module Simple: 99", "M"));
+		ci.add(CoverageInformationItem.parse("||line 7, col 35 to line 7, col 65 of module Simple: 792", "M"));
+		ci.add(CoverageInformationItem.parse("|||line 7, col 35 to line 7, col 41 of module Simple: 792", "M"));
+		ci.add(CoverageInformationItem.parse("|||line 7, col 46 to line 7, col 65 of module Simple: 693", "M"));
+		ci.add(CoverageInformationItem.parse("||||line 7, col 59 to line 7, col 65 of module Simple: 1188", "M"));
+		ci.add(CoverageInformationItem.parse("||||line 7, col 55 to line 7, col 56 of module Simple: 693", "M"));
+		ci.add(CoverageInformationItem.parseCost("||line 7, col 25 to line 7, col 32 of module Simple: 99:1881", "M"));
+		ci.add(CoverageInformationItem.parse("|line 38, col 23 to line 38, col 26 of module Simple: 99", "M"));
+
+		ci.add(ActionInformationItem.parseNext("<b line 40, col 1 to line 40, col 7 of module Simple>: 87:261", "M"));
+		ci.add(CoverageInformationItem.parse("line 40, col 15 to line 40, col 25 of module Simple: 720", "M"));
+		ci.add(CoverageInformationItem.parse("|line 40, col 15 to line 40, col 21 of module Simple: 459", "M"));
+		ci.add(CoverageInformationItem.parse("line 40, col 30 to line 40, col 40 of module Simple: 621", "M"));
+		ci.add(CoverageInformationItem.parse("|line 40, col 30 to line 40, col 36 of module Simple: 360", "M"));
+		ci.add(CoverageInformationItem.parse("line 41, col 15 to line 41, col 55 of module Simple: 261", "M"));
+		ci.add(CoverageInformationItem.parse("line 42, col 15 to line 42, col 48 of module Simple: 261", "M"));
+		ci.add(CoverageInformationItem.parse("line 43, col 15 to line 43, col 30 of module Simple: 261", "M"));
+		ci.add(CoverageInformationItem.parse("line 44, col 15 to line 44, col 27 of module Simple: 261", "M"));
+		ci.add(CoverageInformationItem.parse("|line 7, col 15 to line 7, col 65 of module Simple: 261", "M"));
+		ci.add(CoverageInformationItem.parse("||line 7, col 35 to line 7, col 65 of module Simple: 8352", "M"));
+		ci.add(CoverageInformationItem.parse("|||line 7, col 35 to line 7, col 41 of module Simple: 8352", "M"));
+		ci.add(CoverageInformationItem.parse("|||line 7, col 46 to line 7, col 65 of module Simple: 8091", "M"));
+		ci.add(CoverageInformationItem.parse("||||line 7, col 59 to line 7, col 65 of module Simple: 20880", "M"));
+		ci.add(CoverageInformationItem.parse("||||line 7, col 55 to line 7, col 56 of module Simple: 8091", "M"));
+		ci.add(CoverageInformationItem.parseCost("||line 7, col 25 to line 7, col 32 of module Simple: 261:28971",
+				"M"));
+		ci.add(CoverageInformationItem.parse("|line 44, col 23 to line 44, col 26 of module Simple: 261", "M"));
+
+		ci.add(ActionInformationItem.parseNext("<Terminating line 49, col 1 to line 49, col 11 of module Simple>: 0:21",
+				"M"));
+		ci.add(CoverageInformationItem.parse("line 49, col 40 to line 49, col 56 of module Simple: 330", "M"));
+		ci.add(CoverageInformationItem.parse("|line 49, col 40 to line 49, col 47 of module Simple: 267", "M"));
+		ci.add(CoverageInformationItem.parse("line 49, col 31 to line 49, col 37 of module Simple: 153", "M"));
+		ci.add(CoverageInformationItem.parse("line 50, col 19 to line 50, col 32 of module Simple: 21", "M"));
+
+		mci = ci.projectionFor(file);
+		mci.getRoot(); // initialize AII to CII parent-child relationship.
+	}
+
+	private static void monotonicallyIncreasing(TreeSet<CoverageInformationItem> set, Representation rep, Grouping grp,
+			Function<CoverageInformationItem, Long> f) {
+		long value = -1L;
+		float hue = 240f;
+		for (final CoverageInformationItem cii : set) {
+			assertTrue(rep.getValue(cii, grp) == f.apply(cii));
+			assertTrue(value <= f.apply(cii));
+			value = f.apply(cii);
+
+			// hue inversely correlates (non-linear relationship) with value, ie. value goes
+			// up and hue goes down (but hue's actual value dependents on the set of all
+			// values).
+			final float h = rep.getColor(cii, grp).getRGB().getHSB()[0];
+			assertTrue(hue >= h);
+			hue = h;
+		}
+		assertTrue("legend was empty", value >= 0L);
+	}
+
+	private TreeSet<CoverageInformationItem> getNode(final int offset, final Representation rep) {
+		final CoverageInformationItem node = mci.getNode(offset);
+		// Style implicitly activates the children of node which getLegend requires.
+		node.style(new TextPresentation(), rep);
+		return node.getLegend(rep);
+	}
+
+	@Test
+	public void rootLegendStates() {
+		monotonicallyIncreasing(mci.getLegend(STATES), STATES, COMBINED, CoverageInformationItem::getCount);
+		monotonicallyIncreasing(mci.getLegend(STATES), STATES, COMBINED, CoverageInformationItem::getTotalCount);
+	}
+
+	@Test
+	public void rootLegendDistinctStates() {
+		monotonicallyIncreasing(mci.getLegend(STATES_DISTINCT), STATES_DISTINCT, COMBINED,
+				CoverageInformationItem::getCost);
+		monotonicallyIncreasing(mci.getLegend(STATES_DISTINCT), STATES_DISTINCT, COMBINED,
+				CoverageInformationItem::getTotalCost);
+	}
+
+	@Test
+	public void rootLegendInvocations() {
+		monotonicallyIncreasing(mci.getLegend(INV), INV, COMBINED, CoverageInformationItem::getTotalCount);
+	}
+
+	@Test
+	public void rootLegendCost() {
+		monotonicallyIncreasing(mci.getLegend(COST), COST, COMBINED, CoverageInformationItem::getTotalCost);
+	}
+
+	@Test
+	public void rootLegendInvCost() {
+		monotonicallyIncreasing(mci.getLegend(INVCOST), INVCOST, COMBINED,
+				CoverageInformationItem::getTotalCountAndCost);
+	}
+
+	// Init predicate
+	private static final int init = 775;
+
+	@Test
+	public void initLegendInv() {
+		monotonicallyIncreasing(getNode(init, INV), INV, CoverageInformationItem::getCount);
+	}
+
+	@Test
+	public void initLegendInvCost() {
+		monotonicallyIncreasing(getNode(init, COST), COST, CoverageInformationItem::getCost);
+	}
+
+	@Test
+	public void initLegendCost() {
+		monotonicallyIncreasing(getNode(init, INVCOST), INVCOST, CoverageInformationItem::getCountAndCost);
+	}
+
+	@Test
+	public void initLegendStates() {
+		monotonicallyIncreasing(getNode(init, STATES), STATES, CoverageInformationItem::getCount);
+		monotonicallyIncreasing(getNode(init, STATES), STATES, CoverageInformationItem::getTotalCount);
+	}
+
+	@Test
+	public void initLegendDistStates() {
+		monotonicallyIncreasing(getNode(init, STATES_DISTINCT), STATES_DISTINCT, CoverageInformationItem::getCost);
+		monotonicallyIncreasing(getNode(init, STATES_DISTINCT), STATES_DISTINCT, CoverageInformationItem::getTotalCost);
+	}
+
+	// sub-action a
+	private static final int suba = 944;
+
+	@Test
+	public void aLegendInv() {
+		monotonicallyIncreasing(getNode(suba, INV), INV, CoverageInformationItem::getCount);
+	}
+
+	@Test
+	public void aLegendInvCost() {
+		monotonicallyIncreasing(getNode(suba, COST), COST, CoverageInformationItem::getCost);
+	}
+
+	@Test
+	public void aLegendCost() {
+		monotonicallyIncreasing(getNode(suba, INVCOST), INVCOST, CoverageInformationItem::getCountAndCost);
+	}
+
+	@Test
+	public void aLegendStates() {
+		monotonicallyIncreasing(getNode(suba, STATES), STATES, CoverageInformationItem::getCount);
+		monotonicallyIncreasing(getNode(suba, STATES), STATES, CoverageInformationItem::getTotalCount);
+	}
+
+	@Test
+	public void aLegendDistStates() {
+		monotonicallyIncreasing(getNode(suba, STATES_DISTINCT), STATES_DISTINCT, CoverageInformationItem::getCost);
+		monotonicallyIncreasing(getNode(suba, STATES_DISTINCT), STATES_DISTINCT, CoverageInformationItem::getTotalCost);
+	}
+
+	// sub-action b
+	private static final int subb = 1121;
+
+	@Test
+	public void bLegendInv() {
+		monotonicallyIncreasing(getNode(subb, INV), INV, CoverageInformationItem::getCount);
+	}
+
+	@Test
+	public void bLegendInvCost() {
+		monotonicallyIncreasing(getNode(subb, COST), COST, CoverageInformationItem::getCost);
+	}
+
+	@Test
+	public void bLegendCost() {
+		monotonicallyIncreasing(getNode(subb, INVCOST), INVCOST, CoverageInformationItem::getCountAndCost);
+	}
+
+	@Test
+	public void bLegendStates() {
+		monotonicallyIncreasing(getNode(subb, STATES), STATES, CoverageInformationItem::getCount);
+		monotonicallyIncreasing(getNode(subb, STATES), STATES, CoverageInformationItem::getTotalCount);
+	}
+
+	@Test
+	public void bLegendDistStates() {
+		monotonicallyIncreasing(getNode(subb, STATES_DISTINCT), STATES_DISTINCT, CoverageInformationItem::getCost);
+		monotonicallyIncreasing(getNode(subb, STATES_DISTINCT), STATES_DISTINCT, CoverageInformationItem::getTotalCost);
+	}
+
+	// Termination
+	private static final int term = 1447;
+
+	@Test
+	public void termLegendInv() {
+		monotonicallyIncreasing(getNode(term, INV), INV, CoverageInformationItem::getCount);
+	}
+
+	@Test
+	public void termLegendInvCost() {
+		monotonicallyIncreasing(getNode(term, COST), COST, CoverageInformationItem::getCost);
+	}
+
+	@Test
+	public void termLegendCost() {
+		monotonicallyIncreasing(getNode(term, INVCOST), INVCOST, CoverageInformationItem::getCountAndCost);
+	}
+
+	@Test
+	public void termLegendStates() {
+		monotonicallyIncreasing(getNode(term, STATES), STATES, CoverageInformationItem::getCount);
+		monotonicallyIncreasing(getNode(term, STATES), STATES, CoverageInformationItem::getTotalCount);
+	}
+
+	@Test
+	public void termLegendDistStates() {
+		monotonicallyIncreasing(getNode(term, STATES_DISTINCT), STATES_DISTINCT, CoverageInformationItem::getCost);
+		monotonicallyIncreasing(getNode(term, STATES_DISTINCT), STATES_DISTINCT, CoverageInformationItem::getTotalCost);
+	}
+
+	private static void monotonicallyIncreasing(TreeSet<CoverageInformationItem> set, Representation rep,
+			Function<CoverageInformationItem, Long> f) {
+		monotonicallyIncreasing(set, rep, INDIVIDUAL, f);
+	}
+}
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/Simple.tla b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/Simple.tla
new file mode 100644
index 0000000000000000000000000000000000000000..ec5f8f4734c9ee002cc62d8b8ce547dbe5d4ca4a
--- /dev/null
+++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/Simple.tla
@@ -0,0 +1,61 @@
+----------------------------- MODULE Simple --------------------------
+EXTENDS Integers
+
+CONSTANT N
+ASSUME NAssump ==  (N \in Nat) /\ (N > 0)
+
+ExpTaut(S) == \A ss \in SUBSET S: ss = {} \/ \A e \in ss: e \in S
+
+(****************************************************************************
+--algorithm Simple {
+    variables x = [i \in 0..N-1 |-> 0],
+              y = [i \in 0..N-1 |-> 0],
+              z \in 1..3;
+
+    process (proc \in 0..N-1) {
+      a: x[self] := 1 ;
+      b: y[self] := x[(self-1) % N]
+    }
+}
+****************************************************************************)
+\* BEGIN TRANSLATION  This is the TLA+ translation of the PlusCal code. PCal-5c58e1a73855a22c06f78d78d4dfc2a3
+VARIABLES x, y, z, pc
+
+vars == << x, y, z, pc >>
+
+ProcSet == (0..N-1)
+
+Init == (* Global variables *)
+        /\ y = [i \in 0..N-1 |-> 0]
+        /\ x = [i \in 0..N-1 |-> 0]
+        /\ z \in 1..3
+        /\ pc = [self \in ProcSet |-> "a"]
+
+a(self) == /\ pc[self] = "a"
+           /\ x' = [x EXCEPT ![self] = 1]
+           /\ pc' = [pc EXCEPT ![self] = "b"]
+           /\ y' = y /\ z' = z
+           /\ ExpTaut(1..3)
+
+b(self) == /\ x[self] = 1 /\ y[self] = 0 \* pc[self] = "b"
+           /\ y' = [y EXCEPT ![self] = x[(self-1) % N]]
+           /\ pc' = [pc EXCEPT ![self] = "Done"]
+           /\ x' = x /\ z' = z
+           /\ ExpTaut(1..5)
+
+proc(self) == a(self) \/ b(self)
+
+(* Allow infinite stuttering to prevent deadlock on termination. *)
+Terminating == /\ \A self \in ProcSet: pc[self] = "Done"
+               /\ UNCHANGED vars
+
+Next == (\E self \in 0..N-1: proc(self))
+           \/ Terminating
+
+Spec == Init /\ [][Next]_vars
+
+Termination == <>(\A self \in ProcSet: pc[self] = "Done")
+
+\* END TRANSLATION TLA-0e9e0633cd25a2a6c948e18f4aa9ab0c
+
+==========================================================
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCErrorTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCErrorTest.java
index d2574fe6aa789ce854126383b358e928e7dcb1d5..e00cf5974c8b7ce8f7c58ff6c3d4a66173a7cd93 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCErrorTest.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCErrorTest.java
@@ -33,10 +33,12 @@ import java.util.List;
 import java.util.Map;
 
 import org.junit.Test;
-import org.lamport.tla.toolbox.tool.tlc.launch.TraceExpressionInformationHolder;
-import org.lamport.tla.toolbox.tool.tlc.model.Formula;
 import org.lamport.tla.toolbox.tool.tlc.output.data.TLCError.Order;
 
+import tlc2.model.Formula;
+import tlc2.model.TraceExpressionInformationHolder;
+import util.TLAConstants;
+
 public class TLCErrorTest {
 	
 	@Test
@@ -102,7 +104,7 @@ public class TLCErrorTest {
 		assertEquals(mcInitState.getVariableCount(1) + 2, teInitState.getVariableCount(1));
 		final Map<String, TLCVariable> teInitDiff = teInitState.getDiff(mcInitState);
 		assertEquals(2, teInitDiff.size());
-		assertEquals(teInitDiff.get("_TEPosition").toString(), "1");
+		assertEquals(teInitDiff.get(TLAConstants.TraceExplore.POSITION).toString(), "1");
 		assertEquals(teInitDiff.get("store = <<>>").toString(), "TRUE");
 
 		final TLCState teNextState = teStates.get(next);
@@ -112,13 +114,13 @@ public class TLCErrorTest {
 		assertEquals(mcNextState.getVariableCount(1) + 2, teNextState.getVariableCount(1));
 		final Map<String, TLCVariable> teNextDiff = teNextState.getDiff(mcNextState);
 		assertEquals(2, teNextDiff.size());
-		assertEquals(teNextDiff.get("_TEPosition").toString(), "2");
+		assertEquals(teNextDiff.get(TLAConstants.TraceExplore.POSITION).toString(), "2");
 		assertEquals(teNextDiff.get("store = <<>>").toString(), "FALSE");
 	}
 
 	private static final Hashtable<String, TraceExpressionInformationHolder> getTraceExpressionDataTable() {
 		final Hashtable<String, TraceExpressionInformationHolder> hashtable = new Hashtable<String, TraceExpressionInformationHolder>();
-		hashtable.put("__trace_var_155717784845014000", new TraceExpressionInformationHolder("_TEPosition", null, "__trace_var_155717784845014000"));
+		hashtable.put("__trace_var_155717784845014000", new TraceExpressionInformationHolder(TLAConstants.TraceExplore.POSITION, null, "__trace_var_155717784845014000"));
 
 		final TraceExpressionInformationHolder value = new TraceExpressionInformationHolder("store = <<>>", null, "__trace_var_155717784845012000");
 		value.setLevel(1);
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/source/Bug267Listener.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/source/Bug267Listener.java
index c97eee3202811c63ee7900c78f80b93de12d1789..2bb2e0115763ad618cd6fc909edbf8b4f39ef659 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/source/Bug267Listener.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/source/Bug267Listener.java
@@ -69,8 +69,8 @@ public class Bug267Listener extends TLCModelLaunchDataProvider implements
 	/* (non-Javadoc)
 	 * @see org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider#connectToSourceRegistry()
 	 */
-	public void connectToSourceRegistry() {
-		// intentionally noop
+	public boolean connectToSourceRegistry() {
+		return false;
 	}
 	
 	private static class DummyModel extends Model {
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/source/TagBasedTLCOutputIncrementalParserTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/source/TagBasedTLCOutputIncrementalParserTest.java
index bb1cbd1fc8f4db36fa18556763d6efe4b50329e4..4fb21979b09a85def13e9e5d59e2d0cdc2d19248 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/source/TagBasedTLCOutputIncrementalParserTest.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/source/TagBasedTLCOutputIncrementalParserTest.java
@@ -18,6 +18,7 @@ import org.junit.Test;
 import org.lamport.tla.toolbox.tool.tlc.model.Model;
 
 import tlc2.output.MP;
+import util.TLAConstants;
 
 public class TagBasedTLCOutputIncrementalParserTest {
 
@@ -218,11 +219,11 @@ public class TagBasedTLCOutputIncrementalParserTest {
 			parser.addIncrement("@!@!@STARTMSG 2220:0 @!@!@\n");
 			parser.addIncrement("Starting SANY...\n");
 			parser.addIncrement("@!@!@ENDMSG 2220 @!@!@\n");
-			parser.addIncrement("Parsing file MC.tla\n");
-			parser.addIncrement("Parsing file Test.tla\n");
-			parser.addIncrement("Parsing file /toolbox/plugins/org.lamport.tla.toolbox_1.0.0/StandardModules/TLC.tla\n");
-			parser.addIncrement("Parsing file /tla/toolbox/plugins/org.lamport.tla.toolbox_1.0.0/StandardModules/Naturals.tla\n");
-			parser.addIncrement("Parsing file /tla/toolbox/plugins/org.lamport.tla.toolbox_1.0.0/StandardModules/Sequences.tla\n");
+			parser.addIncrement(TLAConstants.LoggingAtoms.PARSING_FILE + " MC.tla\n");
+			parser.addIncrement(TLAConstants.LoggingAtoms.PARSING_FILE + " Test.tla\n");
+			parser.addIncrement(TLAConstants.LoggingAtoms.PARSING_FILE + " /toolbox/plugins/org.lamport.tla.toolbox_1.0.0/StandardModules/TLC.tla\n");
+			parser.addIncrement(TLAConstants.LoggingAtoms.PARSING_FILE + " /tla/toolbox/plugins/org.lamport.tla.toolbox_1.0.0/StandardModules/Naturals.tla\n");
+			parser.addIncrement(TLAConstants.LoggingAtoms.PARSING_FILE + " /tla/toolbox/plugins/org.lamport.tla.toolbox_1.0.0/StandardModules/Sequences.tla\n");
 			parser.addIncrement("Semantic processing of module Naturals\n");
 			parser.addIncrement("Semantic processing of module Sequences\n");
 			parser.addIncrement("Semantic processing of module TLC\n");
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/ui/view/TLCErrorViewTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/ui/view/TLCErrorViewTest.java
index 3dace7264db35bbb2eb4316b5d62ecbd9313e72a..c4ded71e9f6d4a75bc50690c6656dd483a45bc35 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/ui/view/TLCErrorViewTest.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/ui/view/TLCErrorViewTest.java
@@ -53,6 +53,7 @@ import org.lamport.tla.toolbox.tool.tlc.output.data.TLCError.Order;
 import org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider;
 import org.lamport.tla.toolbox.tool.tlc.output.data.TLCState;
 import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
+import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor;
 import org.lamport.tla.toolbox.tool.tlc.ui.preference.ITLCPreferenceConstants;
 import org.lamport.tla.toolbox.util.UIHelper;
 
@@ -110,7 +111,7 @@ public class TLCErrorViewTest  {
 		final long before = System.currentTimeMillis();
 		UIHelper.runUISync(new Runnable() {
 			public void run() {
-				TLCErrorView.updateErrorView(provider, dummyModel, true);
+				TLCErrorView.updateErrorView(provider, new ModelEditor(dummyModel), true);
 			}
 		});
 		assertTrue(before - System.currentTimeMillis() <= 10 * 1000); // maximally ten seconds
@@ -203,7 +204,7 @@ public class TLCErrorViewTest  {
 		/*
 		 * Feed error trace to view.
 		 */
-		view.setTraceInput(error);
+		view.setTraceInput(error, true);
 		
 		/*
 		 * Expand all items to force coloring (expect test to fail otherwise).
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/tool/tlc/ui/test/AbstractTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/tool/tlc/ui/test/AbstractTest.java
index 41a43564312f006796ef41e774add23a727695d5..3d780878f5a0c4ce4fdbb1a6f4e65b7bd4ad9076 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/tool/tlc/ui/test/AbstractTest.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/tool/tlc/ui/test/AbstractTest.java
@@ -23,10 +23,12 @@ import org.lamport.tla.toolbox.test.RCPTestSetupHelper;
 import org.lamport.tla.toolbox.tool.tlc.model.Model;
 import org.lamport.tla.toolbox.tool.tlc.model.TLCSpec;
 
+import util.TLAConstants;
+
 public abstract class AbstractTest {
 
 	protected static final String SPEC_EXPLORER = "Spec Explorer";
-	protected static final String TLA_SUFFIX = ".tla";
+	protected static final String TLA_SUFFIX = TLAConstants.Files.TLA_EXTENSION;
 
 	/**
 	 * workbench handle used by tests to access UI elements 
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/CloneModelTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/CloneModelTest.java
index 1a463c1408aa2ae7527e33b71e06c1ccdd76466a..1b46f8ea41a760899990948d570e8260e1d3bcfb 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/CloneModelTest.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/CloneModelTest.java
@@ -18,7 +18,6 @@ import org.lamport.tla.toolbox.tool.tlc.ui.test.ModelEditorOpenCondition;
 @RunWith(SWTBotJunit4ClassRunner.class)
 public class CloneModelTest extends AbstractTest {
 
-	private static final String TLA_SUFFIX = ".tla";
 	private static final String TEST_SPEC = "ToBeClonedSpec";
 	private static final String TEST_MODEL = "Model_1";
 	private static final String TEST_MODEL_RENAME = "Model_2";
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/RenameSpecHandlerTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/RenameSpecHandlerTest.java
index 55b7276a1f85b68537049ed5abc3c1e4a7c51f08..067d688a1231e0d9e028ef0bae0ddcf4402b1d75 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/RenameSpecHandlerTest.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/RenameSpecHandlerTest.java
@@ -88,7 +88,7 @@ public class RenameSpecHandlerTest extends AbstractTest {
 	public void renameSpec() throws InterruptedException {
 		openSpecExplorer();
 
-		SWTBotTreeItem treeItem = bot.tree().getTreeItem(TEST_SPEC + " [ " + TEST_SPEC + TLA_SUFFIX + " ]");
+		SWTBotTreeItem treeItem = bot.tree().getTreeItem(TEST_SPEC);
 		checkForModelExistenceUI(treeItem);
 
 		SWTBotMenu contextMenu = treeItem.contextMenu("Rename");
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/trace_filter.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/trace_filter.png
new file mode 100644
index 0000000000000000000000000000000000000000..c833b50f72e48badff476f4cbb65caf15c795521
Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/trace_filter.png differ
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/trace_filter@2x.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/trace_filter@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..5e18ef8360b69d3921253dedb29857fe54cdd93c
Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/elcl16/trace_filter@2x.png differ
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/lrun_obj.gif b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/lrun_obj.gif
deleted file mode 100644
index 57f410224cf0e125fefdfbfd424b34ca32650ac4..0000000000000000000000000000000000000000
Binary files a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/lrun_obj.gif and /dev/null differ
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/run_exc.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/run_exc.png
new file mode 100644
index 0000000000000000000000000000000000000000..08571c1f22ed976c9cc9333c892c8f43a6219f4a
Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/run_exc.png differ
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/run_exc@2x.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/run_exc@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..156df21c3f427299e2499c4dd06bd39c27ba6c04
Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/run_exc@2x.png differ
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/plugin.xml b/org.lamport.tla.toolbox.tool.tlc.ui/plugin.xml
index b12e5cd2c517db8897871899e4ecd4db9b4e7e35..9910c4b3b275d51862f9336bfb9db9d5aa0b7a6f 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/plugin.xml
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/plugin.xml
@@ -286,7 +286,7 @@
          <!-- Run model menu bar command in TLC Model Checker menu -->
          <command
                commandId="toolbox.tool.tlc.commands.model.run"
-               icon="icons/full/lrun_obj.gif"
+               icon="icons/full/run_exc.png"
                id="toolbox.menu.runmodel"
                label="Run model"
                mnemonic="R"
@@ -424,7 +424,7 @@
              is RunAction, a nested class in BasicFormPage.-->
          <!-- command
                commandId="toolbox.tool.tlc.commands.model.run"
-               icon="icons/full/lrun_obj.gif"
+               icon="icons/full/run_exc.png"
                id="toolbox.popupmenu.model.run"
                label="Run model"
                style="push">
@@ -802,6 +802,12 @@ Console Facory
    </extension>
    <extension
          point="org.eclipse.ui.preferencePages">
+      <page
+            category="toolbox.ui.preferences.GeneralPreferencePage"
+            class="org.lamport.tla.toolbox.tool.tlc.ui.editor.preference.ModelEditorPreferencePage"
+            id="toolbox.ui.preferences.ModelEditorPreferencePage"
+            name="Model Editor">
+      </page>
       <page
             category="toolbox.ui.preferences.GeneralPreferencePage"
             class="org.lamport.tla.toolbox.tool.tlc.ui.preference.TLCPreferencePage"
@@ -812,8 +818,9 @@ Console Facory
    <extension
          point="org.eclipse.core.runtime.preferences">
       <initializer
-            class="org.lamport.tla.toolbox.tool.tlc.ui.preference.TLCPreferenceInitializer">
-      </initializer>
+            class="org.lamport.tla.toolbox.tool.tlc.ui.editor.preference.ModelEditorPreferenceInitializer" />
+      <initializer
+            class="org.lamport.tla.toolbox.tool.tlc.ui.preference.TLCPreferenceInitializer" />
    </extension>
    <extension
          point="org.lamport.tla.toolbox.tlc.processResultPresenter">
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/NewModelHandler.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/NewModelHandler.java
index a592159b1b978d5c136025f74fce50b7786196f5..312f84949b2edfe7cc5adfa7d620ca36b9e1b03e 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/NewModelHandler.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/NewModelHandler.java
@@ -33,7 +33,6 @@ import org.lamport.tla.toolbox.tool.ToolboxHandle;
 import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants;
 import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationDefaults;
 import org.lamport.tla.toolbox.tool.tlc.launch.TLCModelLaunchDelegate;
-import org.lamport.tla.toolbox.tool.tlc.model.Assignment;
 import org.lamport.tla.toolbox.tool.tlc.model.Model;
 import org.lamport.tla.toolbox.tool.tlc.model.TLCSpec;
 import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
@@ -53,6 +52,7 @@ import tla2sany.semantic.ModuleNode;
 import tla2sany.semantic.OpApplNode;
 import tla2sany.semantic.OpDefNode;
 import tla2sany.semantic.SubstInNode;
+import tlc2.model.Assignment;
 
 /**
  * Handler for creation of new models
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/OpenTLCErrorViewHandler.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/OpenTLCErrorViewHandler.java
index b5a684b4c66720b225f2f04c6025126bd547675f..75635bc5019716ae243f8589214ce7c7a8239ab1 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/OpenTLCErrorViewHandler.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/OpenTLCErrorViewHandler.java
@@ -8,40 +8,29 @@ import org.eclipse.core.commands.ExecutionEvent;
 import org.eclipse.core.commands.ExecutionException;
 import org.eclipse.core.commands.IHandler;
 import org.eclipse.ui.IEditorPart;
-import org.lamport.tla.toolbox.tool.tlc.model.Model;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor;
 import org.lamport.tla.toolbox.tool.tlc.ui.view.TLCErrorView;
 import org.lamport.tla.toolbox.ui.handler.OpenViewHandler;
 import org.lamport.tla.toolbox.util.UIHelper;
 
-public class OpenTLCErrorViewHandler extends AbstractHandler implements IHandler
-{
-
-    public Object execute(ExecutionEvent event) throws ExecutionException
-    {
-        Map<String, String> params = new HashMap<String, String>();
+public class OpenTLCErrorViewHandler extends AbstractHandler implements IHandler {
+	public Object execute(final ExecutionEvent event) throws ExecutionException {
+        final Map<String, String> params = new HashMap<String, String>();
         params.put(OpenViewHandler.PARAM_VIEW_NAME, TLCErrorView.ID);
+        
         UIHelper.runCommand(OpenViewHandler.COMMAND_ID, params);
 
-        IEditorPart activeEditor = UIHelper.getActiveEditor();
-        if (activeEditor != null)
-        {
-            if (activeEditor instanceof ModelEditor)
-            {
-                ModelEditor activeModelEditor = (ModelEditor) activeEditor;
-                final Model model = activeModelEditor.getModel();
-                if (model != null)
-                {
-                    UIHelper.runUISync(new Runnable() {
-
-                        public void run()
-                        {
-                            TLCErrorView.updateErrorView(model);
-                        }
-                    });
-                }
-            }
-        }
+        final IEditorPart activeEditor = UIHelper.getActiveEditor();
+		if (activeEditor != null) {
+			if (activeEditor instanceof ModelEditor) {
+				final ModelEditor activeModelEditor = (ModelEditor) activeEditor;
+				if (activeModelEditor.getModel() != null) {
+					UIHelper.runUISync(() -> {
+						TLCErrorView.updateErrorView(activeModelEditor);
+					});
+				}
+			}
+		}
 
         return null;
     }
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/RenameModelHandlerDelegate.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/RenameModelHandlerDelegate.java
index ce7066ac9d9dfc5cde32113d5f1fba7087b49aff..cd20471e207514182ceaed0c22d226f5076f1b50 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/RenameModelHandlerDelegate.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/RenameModelHandlerDelegate.java
@@ -3,12 +3,14 @@ package org.lamport.tla.toolbox.tool.tlc.handlers;
 import java.lang.reflect.InvocationTargetException;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.eclipse.core.commands.AbstractHandler;
 import org.eclipse.core.commands.ExecutionEvent;
 import org.eclipse.core.commands.ExecutionException;
 import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.expressions.IEvaluationContext;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jface.dialogs.IInputValidator;
@@ -119,4 +121,31 @@ public class RenameModelHandlerDelegate extends AbstractHandler implements IHand
         }
         return null;
     }
-}
+    
+    @SuppressWarnings("unchecked")	// generics casting...
+	@Override
+	public void setEnabled(final Object evaluationContext) {
+		final Object selection = ((IEvaluationContext)evaluationContext).getDefaultVariable();
+		
+		if (selection instanceof List) {
+			final List<Object> list = (List<Object>)selection;
+
+			boolean modelEncountered = false; // Will always go to true on given current XML definitions; future proofing
+			for (final Object element : list) {
+				if (element instanceof Model) {
+					if (((Model)element).isSnapshot()) {
+						setBaseEnabled(false);
+						
+						return;
+					}
+					
+					modelEncountered = true;
+				}
+			}
+			
+			setBaseEnabled(modelEncountered);
+		} else {
+			setBaseEnabled(false);
+		}
+	}
+}
\ No newline at end of file
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/ConsoleProcessOutputSink.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/ConsoleProcessOutputSink.java
index abef46b86ac4a5df52571eece05879a3eb6a4d8e..9c1d3b18e4ea198273b0244a18bb2c630af52beb 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/ConsoleProcessOutputSink.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/ConsoleProcessOutputSink.java
@@ -3,56 +3,53 @@ package org.lamport.tla.toolbox.tool.tlc.output;
 import java.io.IOException;
 
 import org.eclipse.ui.console.IOConsoleOutputStream;
-import org.eclipse.ui.console.MessageConsole;
 import org.lamport.tla.toolbox.tool.tlc.model.Model;
 import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
 import org.lamport.tla.toolbox.tool.tlc.ui.console.ConsoleFactory;
 
+import tlc2.output.MP;
+
 /**
- * A sink writing to a console
+ * A sink writing to a console. In plain English, this causes the Toolbox's
+ * console to show TLC's output (stdout/stderr).
+ * 
  * @author Simon Zambrovski
  */
-public class ConsoleProcessOutputSink implements IProcessOutputSink
-{
-
-    private MessageConsole console;
-    private IOConsoleOutputStream outputStream;
-
-    public ConsoleProcessOutputSink()
-    {
-        this.console = ConsoleFactory.getTLCConsole();
-        this.outputStream = this.console.newOutputStream();
-        // this.console.activate();
-    }
-
-    public synchronized void appendText(String text)
-    {
-
-        try
-        {
-            this.outputStream.write(text.getBytes());
-        } catch (IOException e)
-        {
-            TLCUIActivator.getDefault().logError("Error printing a console message: >" + text + "<", e);
-        }
-    }
-
-    public void initializeSink(Model model, int sinkType)
-    {
-
-    }
-
-    public void processFinished()
-    {
-
-    }
-
-    /**
-     * Initializes the console and shows the view 
-     */
-    protected void initConsole()
-    {
-
-    }
-
+public class ConsoleProcessOutputSink implements IProcessOutputSink {
+
+	private final IOConsoleOutputStream outputStream;
+
+	public ConsoleProcessOutputSink() {
+		this.outputStream = ConsoleFactory.getTLCConsole().newOutputStream();
+	}
+
+	@Override
+	public synchronized void appendText(final String text) {
+		try {
+			// Remove TLC's "-tool" markers for better readability by a human.
+			if (Boolean.getBoolean(ConsoleProcessOutputSink.class.getName() + ".tool")) {
+				this.outputStream.write(text.getBytes());
+			} else {
+				final String[] lines = text.split(MP.CR);
+				for (String line : lines) {
+					if (!line.startsWith(MP.DELIM) && !line.trim().isEmpty()) {
+						line += MP.CR;
+						this.outputStream.write(line.getBytes());
+					}
+				}
+			}
+		} catch (IOException e) {
+			TLCUIActivator.getDefault().logError("Error printing a console message: >" + text + "<", e);
+		}
+	}
+
+	@Override
+	public void initializeSink(Model model, int sinkType) {
+		// No-op (The why has been lost in time).
+	}
+
+	@Override
+	public void processFinished() {
+		// No-op (The why has been lost in time).
+	}
 }
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/ActionInformationItem.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/ActionInformationItem.java
index 0c345abb51e4b5fcd4faa244b5a18ce1f13b53c0..937578e3262a864844b82fcfa1ea7b652b26ab7c 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/ActionInformationItem.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/ActionInformationItem.java
@@ -220,6 +220,14 @@ public class ActionInformationItem extends CoverageInformationItem {
 			child.style(textPresentation, c, rep);
 		}
 	}
+	
+	@Override
+	protected boolean addThisToLegend() {
+		// Do not add ActionInformationItem to the legend of non state-based statistics
+		// (inv, cost, cost+inv). Otherwise, the legend (heatmap) will contain the value
+		// and color of the AII which is bogus.
+		return false;
+	}
 
 	@Override
 	Color colorItem(TreeSet<Long> counts, final Representation ignored) {
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformation.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformation.java
index f48aa98e8054b94e237c862f6bc1e89c8501c752..874717789eaf1e1d0125549d1cb5db45e9286ce7 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformation.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformation.java
@@ -41,6 +41,7 @@ import org.eclipse.ui.part.FileEditorInput;
 import org.lamport.tla.toolbox.util.AdapterFactory;
 
 import tlc2.tool.coverage.ActionWrapper.Relation;
+import util.TLAConstants;
 
 public class CoverageInformation {
 	
@@ -70,7 +71,7 @@ public class CoverageInformation {
 
 	public void add(final CoverageInformationItem item) {
 		try {
-			final String filename = item.getModuleLocation().source() + ".tla";
+			final String filename = item.getModuleLocation().source() + TLAConstants.Files.TLA_EXTENSION;
 			if (nameToDocument.containsKey(filename)) {
 				final IDocument document = nameToDocument.get(filename);
 				final IRegion region = AdapterFactory.locationToRegion(document , item.getModuleLocation());
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformationItem.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformationItem.java
index 6f0c6f3ce463325c2e1aeabcc19996247b34c927..914adcd6897ff3a2750059c479106256193dda39 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformationItem.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageInformationItem.java
@@ -48,6 +48,7 @@ import org.lamport.tla.toolbox.tool.tlc.ui.util.IModuleLocatable;
 
 import tla2sany.st.Location;
 import tlc2.TLCGlobals;
+import util.TLAConstants;
 
 public class CoverageInformationItem implements IModuleLocatable
 {
@@ -109,7 +110,7 @@ public class CoverageInformationItem implements IModuleLocatable
     }
     
     public final boolean isInFile(IFile f) {
-    	final String nameWithoutSuffix = f.getName().replace(".tla", "");
+    	final String nameWithoutSuffix = f.getName().replace(TLAConstants.Files.TLA_EXTENSION, "");
 		return nameWithoutSuffix.equalsIgnoreCase(location.source());
     }
 
@@ -399,7 +400,9 @@ public class CoverageInformationItem implements IModuleLocatable
 	}
 	
 	protected TreeSet<CoverageInformationItem> collectActive(final TreeSet<CoverageInformationItem> legend) {
-		legend.add(this);
+		if (addThisToLegend()) {
+			legend.add(this);
+		}
 		for (CoverageInformationItem child : childs) {
 			if (child.isActive()) {
 				child.collectActive(legend);
@@ -407,4 +410,8 @@ public class CoverageInformationItem implements IModuleLocatable
 		}
 		return legend;
 	}
+
+	protected boolean addThisToLegend() {
+		return true;
+	}
 }
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageUINotification.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageUINotification.java
index f9e17e10ec6287d6e8621f6d3409448260426f11..09639cae63cffb9fab09f664ee94554b68e33c52 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageUINotification.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/CoverageUINotification.java
@@ -41,8 +41,7 @@ public class CoverageUINotification extends TLCUINotification {
 
 	public CoverageUINotification(final ModelEditor editor) {
 		super("Performance Hint",
-				  "TLC has for some time been\n"
-				+ "running with profiling enabled\n"
+				  "TLC is running with profiling enabled.\n"
 				+ "Please be advised that profiling\n"
 				+ "negatively impacts performance.\n"
 				+ "For this reason, please consider\n"
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCError.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCError.java
index 5de7fe25e8bc9a4718dcf5bbde9043a01c4a1e0f..2c04b7e5b659e64fef881b95a19b1c0107038b76 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCError.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCError.java
@@ -36,8 +36,10 @@ import java.util.List;
 import java.util.Map;
 
 import org.eclipse.core.runtime.Assert;
-import org.lamport.tla.toolbox.tool.tlc.launch.TraceExpressionInformationHolder;
-import org.lamport.tla.toolbox.tool.tlc.model.Formula;
+
+import tlc2.model.Formula;
+import tlc2.model.TraceExpressionInformationHolder;
+import util.TLAConstants;
 
 /**
  * Representation of the TLC error
@@ -194,6 +196,10 @@ public class TLCError
 		}
 		return states;
 	}
+	
+	public void removeStates(final List<TLCState> statesToRemove) {
+		states.removeAll(statesToRemove);
+	}
 
 	public boolean isTraceEmpty() {
 		return numberOfStatesToShow == 0 || states.isEmpty();
@@ -231,6 +237,36 @@ public class TLCError
 		}
 	}
 
+	public String toSequenceOfRecords(final boolean includeHeaders) {
+		final StringBuffer buf = new StringBuffer();
+		buf.append(TLAConstants.BEGIN_TUPLE);
+		buf.append(TLAConstants.CR);
+		
+		for (int i = 0; i < states.size(); i++) {
+			final TLCState tlcState = states.get(i);
+			if (tlcState.isBackToState() || tlcState.isStuttering()) {
+				//TODO How to represent these two types of states?
+				continue;
+			}
+			if (tlcState.getVariablesAsList().isEmpty() && includeHeaders == false) {
+				// When an user has used filtering to hide all variables, the error trace here
+				// has no variables. In this case just return empty sequence <<>> by breaking
+				// from the loop.
+				break;
+			}
+			
+			if (i > 0) {
+				// Append a comma if a record is going to be added below.
+				buf.append(TLAConstants.COMMA).append(TLAConstants.CR);
+			}
+			buf.append(tlcState.asRecord(includeHeaders));
+		}
+			
+		buf.append(TLAConstants.CR);
+		buf.append(TLAConstants.END_TUPLE);
+		return buf.toString();
+	}
+
 	public void applyFrom(final TLCError originalErrorWithTrace, final Map<String, Formula> traceExplorerExpressions,
 			final Hashtable<String, TraceExpressionInformationHolder> traceExpressionDataTable,
 			final String modelName) {
@@ -465,4 +501,20 @@ public class TLCError
 			}
 		}
 	}
+	
+	/**
+	 * This clone includes clones of each TLCState held.
+	 */
+	@Override
+	public TLCError clone() {
+		final TLCError clone = new TLCError(stateSortDirection);
+		
+		clone.message = message;
+		clone.cause = cause;
+		clone.errorCode = errorCode;
+		clone.numberOfStatesToShow =  numberOfStatesToShow;
+		states.stream().forEach((state) -> clone.states.add(state.clone()));
+		
+		return clone;
+	}
 }
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCModelLaunchDataProvider.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCModelLaunchDataProvider.java
index b19d085111d55d2127efb59d3095b05cc9806dd0..839437ea1a5636f39e447322a47835b419763176 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCModelLaunchDataProvider.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCModelLaunchDataProvider.java
@@ -35,6 +35,7 @@ import java.util.List;
 import java.util.Vector;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -57,10 +58,7 @@ import org.eclipse.ui.editors.text.FileDocumentProvider;
 import org.eclipse.ui.part.FileEditorInput;
 import org.lamport.tla.toolbox.Activator;
 import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants;
-import org.lamport.tla.toolbox.tool.tlc.model.Assignment;
-import org.lamport.tla.toolbox.tool.tlc.model.Formula;
 import org.lamport.tla.toolbox.tool.tlc.model.Model;
-import org.lamport.tla.toolbox.tool.tlc.model.ModelWriter;
 import org.lamport.tla.toolbox.tool.tlc.output.ITLCOutputListener;
 import org.lamport.tla.toolbox.tool.tlc.output.data.TLCError.Order;
 import org.lamport.tla.toolbox.tool.tlc.output.source.TLCOutputSourceRegistry;
@@ -72,8 +70,11 @@ import org.lamport.tla.toolbox.util.AdapterFactory;
 import org.lamport.tla.toolbox.util.UIHelper;
 
 import tla2sany.st.Location;
+import tlc2.model.Assignment;
+import tlc2.model.Formula;
 import tlc2.output.EC;
 import tlc2.output.MP;
+import util.TLAConstants;
 
 /**
  * Container for the data about the model launch
@@ -104,10 +105,10 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener
     public static final String SIMULATION_MODE = "Simulation";
 
     // pattern for the output of evaluating constant expressions
-    public static final Pattern CONSTANT_EXPRESSION_OUTPUT_PATTERN = Pattern.compile("(?s)" + ModelWriter.BEGIN_TUPLE
-            + "[\\s]*" + Pattern.quote(ModelWriter.CONSTANT_EXPRESSION_EVAL_IDENTIFIER) + "[\\s]*" + ModelWriter.COMMA
+    public static final Pattern CONSTANT_EXPRESSION_OUTPUT_PATTERN = Pattern.compile("(?s)" + TLAConstants.BEGIN_TUPLE
+            + "[\\s]*" + Pattern.quote(TLAConstants.CONSTANT_EXPRESSION_EVAL_IDENTIFIER) + "[\\s]*" + TLAConstants.COMMA
             + "(.*)"/*calc output group*/
-            + ModelWriter.END_TUPLE);
+            + TLAConstants.END_TUPLE);
 
     
     
@@ -161,6 +162,10 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener
 	private int fpIndex;
 
 	private boolean isSymmetryWithLiveness = false;
+	private boolean isConstraintsWithLiveness = false;
+	
+	private final Object parsingLock;
+	private final AtomicBoolean parsing;
 	
 	public TLCModelLaunchDataProvider(final Model tlcModel) {
     	Assert.isNotNull(tlcModel);
@@ -171,11 +176,26 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener
         // init provider, but not connect it to the source!
         initialize();
 
-        /*
-         *  interested in the output for the model
-         */
-        connectToSourceRegistry();
+        parsingLock = new Object();
+        parsing = new AtomicBoolean(true);
+
+		synchronized (parsingLock) {
+			/*
+			 * interested in the output for the model
+			 */
+			parsing.set(connectToSourceRegistry());
+        }
     }
+	
+	public void waitForParsingFinish() {
+		if (parsing.get()) {
+			synchronized (parsingLock) {
+				try {
+					parsingLock.wait();
+				} catch (final Exception e) { }
+			}
+		}
+	}
 
     /**
      * Resets the values to defaults
@@ -201,6 +221,7 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener
         userOutput = new Document(NO_OUTPUT_AVAILABLE);
         constantExprEvalOutput = "";
         isSymmetryWithLiveness = false;
+        zeroCoverage = false;
     }
 
     /**
@@ -230,8 +251,7 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener
         return model;
     }
 
-    public void onDone()
-    {
+	public void onDone() {
         /*
          * If the last message output by TLC
          * was an error, then this error will not
@@ -247,16 +267,29 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener
          * to the list errors. It must be added to this list to
          * be shown to the user.
          */
-        if (lastDetectedError != null)
-        {
-            this.errors.add(lastDetectedError);
-            informPresenter(ITLCModelLaunchDataPresenter.ERRORS);
-        }
+		if (lastDetectedError != null) {
+			this.errors.add(lastDetectedError);
+			informPresenter(ITLCModelLaunchDataPresenter.ERRORS);
+		}
 
         // TLC is no longer running
         this.setCurrentStatus(NOT_RUNNING);
         informPresenter(ITLCModelLaunchDataPresenter.CURRENT_STATUS);
         isDone = true;
+        if (zeroCoverage) {
+        	// the logic for whatever reason in ResultPage doesn't display zero coverage information unless 
+        	//		the data provider is done.
+            informPresenter(ITLCModelLaunchDataPresenter.COVERAGE);
+        }
+        
+        synchronized (parsingLock) {
+        	try {
+        		parsingLock.notifyAll();
+        	} catch (final Exception e) { }
+        	finally {
+        		parsing.set(false);
+        	}
+        }
     }
 
     public void onNewSource()
@@ -266,8 +299,7 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener
         populate();
     }
 
-    public void onOutput(ITypedRegion region, String text)
-    {
+	public void onOutput(final ITypedRegion region, final String text) {
         // restarting
         if (isDone)
         {
@@ -307,6 +339,11 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener
                     setDocumentText(this.progressOutput, outputMessage, true);
                     informPresenter(ITLCModelLaunchDataPresenter.WARNINGS);
                     break;
+                case EC.TLC_FEATURE_LIVENESS_CONSTRAINTS:
+                	this.isConstraintsWithLiveness = true;
+                    setDocumentText(this.progressOutput, outputMessage, true);
+                    informPresenter(ITLCModelLaunchDataPresenter.WARNINGS);
+                    break;
                     
                 // usual errors
                 default:
@@ -473,7 +510,7 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener
                     CoverageInformationItem item = CoverageInformationItem.parseCost(outputMessage, getModelName());
                     this.coverageInfo.add(item);
                     if (item.getCount() == 0) {
-                    	this.zeroCoverage = true;
+                    	zeroCoverage = true;
                     }
                     informPresenter(ITLCModelLaunchDataPresenter.COVERAGE);
                     break;
@@ -481,7 +518,7 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener
                 	item = CoverageInformationItem.parse(outputMessage, getModelName());
                     this.coverageInfo.add(item);
                     if (item.getCount() == 0) {
-                    	this.zeroCoverage = true;
+                    	zeroCoverage = true;
                     }
                     informPresenter(ITLCModelLaunchDataPresenter.COVERAGE);
                     break;
@@ -754,7 +791,7 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener
                                     } else
                                     {
                                         // invariants and properties
-                                        List<Formula> valueList = ModelHelper.deserializeFormulaList(attributeValue);
+                                        final List<Formula> valueList = Formula.deserializeFormulaList(attributeValue);
                                         
                                         // @see bug #98 (if root cause has been fixed, remove if/else)
                                         if (valueList.size() >= (attributeNumber + 1)) {
@@ -807,9 +844,8 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener
 							}
                             Location location = Location.parseLocation(locationString);
                             // look only for location in the MC file
-                            if (location.source().equals(
-                                    mcFile.getName().substring(0, mcFile.getName().length() - ".tla".length())))
-                            {
+							if (location.source().equals(mcFile.getName().substring(0,
+									mcFile.getName().length() - TLAConstants.Files.TLA_EXTENSION.length()))) {
                                 IRegion region = AdapterFactory.locationToRegion(mcDocument, location);
                                 regionContent[j] = mcDocument.get(region.getOffset(), region.getLength());
                                 // replace the location statement in the error message
@@ -945,10 +981,8 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener
      *  one for trace exploration and one for model checking. This
      *  connects to the one for model checking.
      */
-    protected void connectToSourceRegistry()
-    {
-
-        TLCOutputSourceRegistry.getModelCheckSourceRegistry().connect(this);
+	protected boolean connectToSourceRegistry() {
+		return TLCOutputSourceRegistry.getModelCheckSourceRegistry().connect(this);
     }
 
     /**
@@ -1009,7 +1043,7 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener
     }
 
     public boolean hasZeroCoverage() {
-    	return this.zeroCoverage;
+    	return zeroCoverage;
     }
     
     public List<StateSpaceInformationItem> getProgressInformation()
@@ -1125,7 +1159,10 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener
 	public boolean isSymmetryWithLiveness() {
 		return isSymmetryWithLiveness;
 	}
-	
+
+	public boolean isConstraintsWithLiveness() {
+		return isConstraintsWithLiveness;
+	}
 
 	private final static SimpleDateFormat SDF = new SimpleDateFormat(
 			"yyyy-MM-dd HH:mm:ss");
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCState.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCState.java
index cab3e51bac1329451d795b244bdc7046d681c09e..d36996433b22f3d9eababe3a404462b48316e484 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCState.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCState.java
@@ -30,26 +30,24 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 
 import org.lamport.tla.toolbox.tool.tlc.ui.util.IModuleLocatable;
 
 import tla2sany.st.Location;
+import util.TLAConstants;
 
 /**
  * Representation of the TLC state
+ * 
+ * TODO 393 MCState
+ * 
  * @author Simon Zambrovski
  */
 public class TLCState implements IModuleLocatable
 {
-    private static final String COLON = ":";
-    private static final String CR = "\n";
-    private static final String STUTTERING = " Stuttering"; // See tlc2.output.MP
-    private static final String AND = "/\\";
-    private static final String EQ = " = ";
-    private static final String BACK_TO_STATE = " Back to state"; // See tlc2.output.MP
+	private static final String BACK_TO_STATE = " " + TLAConstants.BACK_TO_STATE;
 
     /**
      * A factory for stuttering states
@@ -84,9 +82,9 @@ public class TLCState implements IModuleLocatable
     public static TLCState parseState(String input, String modelName)
     {
         // state number
-        int index = input.indexOf(COLON);
+        int index = input.indexOf(TLAConstants.COLON);
         // multi line
-        int index2 = input.indexOf(CR, index);
+        int index2 = input.indexOf(TLAConstants.CR, index);
         if (index2 == -1)
         {
             index2 = input.length();
@@ -94,7 +92,7 @@ public class TLCState implements IModuleLocatable
 
         int number = Integer.parseInt(input.substring(0, index));
         String label = input.substring(index + 1, index2);
-        if (label.indexOf(STUTTERING) == 0)
+        if (label.indexOf(TLAConstants.STUTTERING) == 0)
         {
             return STUTTERING_STATE(number, modelName);
         } else if (label.indexOf(BACK_TO_STATE) == 0)
@@ -120,7 +118,7 @@ public class TLCState implements IModuleLocatable
      * @return
      */
 	private static List<TLCVariable> parseVariables(String variablesText) {
-        String[] lines = variablesText.split(CR);
+        String[] lines = variablesText.split(TLAConstants.CR);
 		List<TLCVariable> vars = new ArrayList<TLCVariable>();
         int index;
 
@@ -131,7 +129,7 @@ public class TLCState implements IModuleLocatable
         for (int j = 0; j < lines.length; j++)
         {
             // find the index of the first /\ in the line
-            index = lines[j].indexOf(AND);
+            index = lines[j].indexOf(TLAConstants.TLA_AND);
 
             // adding the current line to the previous lines
             if (index != -1)
@@ -144,7 +142,7 @@ public class TLCState implements IModuleLocatable
                     vars.add(var);
                 }
 
-                stateVarString = lines[j].substring(index + AND.length()).split(EQ);
+                stateVarString = lines[j].substring(index + TLAConstants.TLA_AND.length()).split(TLAConstants.EQ);
             } else
             {
                 // no index
@@ -152,12 +150,12 @@ public class TLCState implements IModuleLocatable
                 if (stateVarString != null)
                 {
                     // either an empty line
-                    stateVarString[1] += CR;
+                    stateVarString[1] += TLAConstants.CR;
                     stateVarString[1] += lines[j];
                 } else
                 {
                     // the state has one variable only
-                    stateVarString = lines[j].split(EQ);
+                    stateVarString = lines[j].split(TLAConstants.EQ);
                 }
             }
         }
@@ -204,7 +202,7 @@ public class TLCState implements IModuleLocatable
      * is a state.
      */
 	private final String modelName;
-	private boolean wasDiffed= false;
+	private boolean wasDiffed = false;
 
     /**
      * 
@@ -240,6 +238,19 @@ public class TLCState implements IModuleLocatable
         return number;
     }
 
+    public final String getName() {
+    	// <Name line 154, col 15 to line 163, col 40 of module DijkstraMutex>
+    	if (label != null && label.length() > 3) {
+			// strip off "<" and ">"
+			return label.substring(2, label.length() - 1)
+					// strip off location if any (none with initial predicate)
+					.replaceAll(getModuleLocation().toString(), "")
+					// extra whitespaces
+					.trim();
+    	}
+    	return label;
+    }
+    
     public final String getLabel()
     {
         return label;
@@ -250,6 +261,9 @@ public class TLCState implements IModuleLocatable
         this.label = label;
     }
 
+    /*
+     * Note to developers: in TLCErrorView, we rely on the fact that this method returns the internal collection instance.
+     */
 	public final List<TLCVariable> getVariablesAsList() {
 		return this.variables;
 	}
@@ -274,56 +288,117 @@ public class TLCState implements IModuleLocatable
     }
 
     /**
-     * Returns a string describing the state with the
-     * variables representing trace explorer expressions
-     * replaced with the expressions.
+     * The returns a conjunction list of variables.
+     * 
+     * For variables representing trace explorer expressions, if {@code includeTraceExpressions} is true,
+     * the returned string has:
      * 
+     * /\ expr = value
+     * 
+     * where expr is the single line form of the trace explorer expression as shown in the Name column of
+     * the trace viewer.
+     *  
+     * For all other variables, this method attempts to display them as TLC does.
+     * 
+     * @param includeTraceExpressions whether trace expressions should be included.
      * @return
      */
-    public String getDescriptionWithTraceExpressions()
-    {
-        /*
-         * The returns a conjunction list of variables.
-         * 
-         * For variables representing trace explorer expressions,
-         * the returned string has:
-         * 
-         * /\ expr = value
-         * 
-         *  where expr is the single line form of the trace explorer expression
-         *  as shown in the Name column of the trace viewer.
-         *  
-         *  For all other variables, this method attempts to display them as TLC
-         *  does.
-         */
-        StringBuffer result = new StringBuffer();
+    public String getConjunctiveDescription(final boolean includeTraceExpressions) {
+        final StringBuilder result = new StringBuilder();
+        
 		for (int i = 0; i < variables.size(); i++) {
-			TLCVariable var = variables.get(i);
+			final TLCVariable var = variables.get(i);
+			
+			if (var.isTraceExplorerVar() && !includeTraceExpressions) {
+				continue;
+			}
+			
             result.append("/\\ ");
-            if (var.isTraceExplorerVar())
-            {
-                result.append(var.getSingleLineName());
-            } else
-            {
-                result.append(var.getName());
-            }
+			if (var.isTraceExplorerVar()) {
+				result.append(var.getSingleLineName());
+			} else {
+				result.append(var.getName());
+			}
 
             result.append(" = ");
 
-            if (var.getValue().toString() != null)
-            {
-                result.append(var.getValue().toString());
-            } else
-            {
-                result.append(var.getValue().toSimpleString());
-            }
-
-            result.append("\n");
+			if (var.getValue().toString() != null) {
+				result.append(var.getValue().toString());
+			} else {
+				result.append(var.getValue().toSimpleString());
+			}
 
+            result.append('\n');
         }
+		
         return result.toString();
     }
 
+	public String asRecord(final boolean includeHeader) {
+		final StringBuffer result = new StringBuffer();
+		result.append(TLAConstants.L_SQUARE_BRACKET);
+		result.append(TLAConstants.CR);
+		
+		if (includeHeader) {
+			result.append(TLAConstants.SPACE);
+			result.append(TLAConstants.TraceExplore.ACTION);
+			result.append(TLAConstants.RECORD_ARROW);
+			
+			result.append(TLAConstants.L_SQUARE_BRACKET);
+			result.append(TLAConstants.CR);
+			result.append(TLAConstants.SPACE).append(TLAConstants.SPACE).append(TLAConstants.SPACE);
+				result.append("position");
+				result.append(TLAConstants.RECORD_ARROW);
+				result.append(getStateNumber());
+				result.append(TLAConstants.COMMA).append(TLAConstants.CR);
+			
+				result.append(TLAConstants.SPACE).append(TLAConstants.SPACE).append(TLAConstants.SPACE);
+				result.append("name");
+				result.append(TLAConstants.RECORD_ARROW);
+				result.append(TLAConstants.QUOTE);
+				result.append(getName());
+				result.append(TLAConstants.QUOTE);
+				result.append(TLAConstants.COMMA).append(TLAConstants.CR);
+				
+				result.append(TLAConstants.SPACE).append(TLAConstants.SPACE).append(TLAConstants.SPACE);
+				result.append("location");
+				result.append(TLAConstants.RECORD_ARROW);
+				result.append(TLAConstants.QUOTE);
+				result.append(getModuleLocation());
+				result.append(TLAConstants.QUOTE);
+				
+			result.append(TLAConstants.CR);
+			result.append(TLAConstants.SPACE).append(TLAConstants.R_SQUARE_BRACKET);
+			if (!variables.isEmpty() ) {
+				// only append comma for additional records iff there are any variables to
+				// append.
+				result.append(TLAConstants.COMMA).append(TLAConstants.CR);
+			}
+		}
+		
+		for (int i = 0; i < variables.size(); i++) {
+			TLCVariable var = variables.get(i);
+			if (var.isTraceExplorerVar()) {
+				result.append(var.getSingleLineName());
+			} else {
+				result.append(var.getName());
+			}
+
+			result.append(TLAConstants.RECORD_ARROW);
+
+			if (var.getValue().toString() != null) {
+				result.append(var.getValue().toString());
+			} else {
+				result.append(var.getValue().toSimpleString());
+			}
+			if (i < variables.size() - 1) {
+				result.append(TLAConstants.COMMA).append(TLAConstants.CR);
+			}
+		}
+		result.append(TLAConstants.CR).append(TLAConstants.R_SQUARE_BRACKET);
+		return result.toString();
+	}
+
     public String getModelName()
     {
         return modelName;
@@ -374,4 +449,22 @@ public class TLCState implements IModuleLocatable
 		}
 		return 0;
 	}
+	
+	/**
+	 * This clone includes a shallow copy of the variables list.
+	 */
+	@Override
+	public TLCState clone() {
+		final TLCState clone = new TLCState(number, modelName);
+		
+		clone.stuttering = stuttering;
+		clone.isBackToState = isBackToState;
+		clone.label = label;
+		clone.variablesAsString = variablesAsString;
+		clone.location = location;
+		clone.wasDiffed = wasDiffed;
+		clone.variables.addAll(variables);
+		
+		return clone;
+	}
 }
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCVariable.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCVariable.java
index 19b52756f091da24327f7a6248ea610b6ae52663..4146af58e4f914350fafa34faa3e56b226cd7843 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCVariable.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCVariable.java
@@ -26,6 +26,8 @@
 
 package org.lamport.tla.toolbox.tool.tlc.output.data;
 
+import java.util.Objects;
+
 public class TLCVariable
 {
     private String name;
@@ -108,4 +110,11 @@ public class TLCVariable
 	public final boolean isChanged() {
 		return value.isAdded() || value.isDeleted() || value.isChanged();
 	}
+	
+	/**
+	 * This compares against name and the value of {@code isTraceExplorerVar}
+	 */
+	public boolean representsTheSameAs(final TLCVariable other) {
+		return (isTraceExplorerVar == other.isTraceExplorerVar) && Objects.equals(name, other.name);
+	}
 }
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCVariableValue.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCVariableValue.java
index 73042280cc0825359f027bf50cda1a7476da5f1b..5dec75312a49e5b6f394821ddef56337c3e269c8 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCVariableValue.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCVariableValue.java
@@ -481,7 +481,7 @@ public abstract class TLCVariableValue
 
     public int getChildCount() {
     	if (this.value instanceof List) {
-    		return ((List) this.value).size();
+    		return ((List<?>) this.value).size();
     	} else if (this.value instanceof TLCVariableValue) {
     		return ((TLCVariableValue) this.value).getChildCount();
     	}
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TraceExplorerDataProvider.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TraceExplorerDataProvider.java
index f17b3ada84a9a579f47dc2245f573fa6c8064dfe..e7dcb007820da0f1bdcec00e92e11fc60b9be6ff 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TraceExplorerDataProvider.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TraceExplorerDataProvider.java
@@ -16,24 +16,26 @@ import org.eclipse.jface.text.FindReplaceDocumentAdapter;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.IRegion;
 import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.ui.IEditorPart;
 import org.eclipse.ui.editors.text.FileDocumentProvider;
 import org.eclipse.ui.part.FileEditorInput;
 import org.lamport.tla.toolbox.Activator;
-import org.lamport.tla.toolbox.tool.tlc.launch.TraceExpressionInformationHolder;
-import org.lamport.tla.toolbox.tool.tlc.model.Formula;
 import org.lamport.tla.toolbox.tool.tlc.model.Model;
-import org.lamport.tla.toolbox.tool.tlc.model.ModelWriter;
 import org.lamport.tla.toolbox.tool.tlc.output.data.TLCError.Order;
 import org.lamport.tla.toolbox.tool.tlc.output.source.TLCOutputSourceRegistry;
 import org.lamport.tla.toolbox.tool.tlc.output.source.TLCRegion;
 import org.lamport.tla.toolbox.tool.tlc.output.source.TLCRegionContainer;
 import org.lamport.tla.toolbox.tool.tlc.traceexplorer.TraceExplorerHelper;
 import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
+import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor;
 import org.lamport.tla.toolbox.tool.tlc.ui.view.TLCErrorView;
 import org.lamport.tla.toolbox.util.LegacyFileDocumentProvider;
 import org.lamport.tla.toolbox.util.UIHelper;
 
+import tlc2.model.Formula;
+import tlc2.model.TraceExpressionInformationHolder;
 import tlc2.output.EC;
+import util.TLAConstants;
 
 /**
  * A data provider for runs of the trace explorer. This mostly uses the methods from
@@ -44,14 +46,15 @@ import tlc2.output.EC;
  */
 public class TraceExplorerDataProvider extends TLCModelLaunchDataProvider
 {
+    private static String TE_ERROR_HEADER = "Error(s) from running the Trace Explorer:\n";
 
+    
     // a hashmap containing information about trace expressions if this
     // provider is for a run of the trace explorer
     // the key is the variable name used for the expression, the value
     // is an instance of TraceExpressionInformationHolder corresponding
     // to the expression.
     private Hashtable<String, TraceExpressionInformationHolder> traceExpressionDataTable;
-    private static String TE_ERROR_HEADER = "Error(s) from running the Trace Explorer:\n";
 
     public TraceExplorerDataProvider(Model model)
     {
@@ -65,9 +68,8 @@ public class TraceExplorerDataProvider extends TLCModelLaunchDataProvider
      * one for trace exploration and one for model checking. This
      * connects to the one for trace exploration.
      */
-    protected void connectToSourceRegistry()
-    {
-        TLCOutputSourceRegistry.getTraceExploreSourceRegistry().connect(this);
+	protected boolean connectToSourceRegistry() {
+		return TLCOutputSourceRegistry.getTraceExploreSourceRegistry().connect(this);
     }
 
     public void onDone()
@@ -78,13 +80,17 @@ public class TraceExplorerDataProvider extends TLCModelLaunchDataProvider
 
         processTraceForTraceExplorer();
 
-        UIHelper.runUIAsync(new Runnable() {
-
-            public void run()
-            {
-                TLCErrorView.updateErrorView(getModel());
-            }
-        });
+        final IEditorPart activeEditor = UIHelper.getActiveEditor();
+		if (activeEditor != null) {
+			if (activeEditor instanceof ModelEditor) {
+				final ModelEditor activeModelEditor = (ModelEditor) activeEditor;
+				if (activeModelEditor.getModel() != null) {
+					UIHelper.runUIAsync(() -> {
+						TLCErrorView.updateErrorView(activeModelEditor);
+					});
+				}
+			}
+		}
     }
 
     /**
@@ -130,8 +136,8 @@ public class TraceExplorerDataProvider extends TLCModelLaunchDataProvider
 
             // search for comments containing the information about trace explorer expressions
             String regularExpression = FindReplaceDocumentAdapter.escapeForRegExPattern("\\* ") + ":[0-2]:"
-                    + ModelWriter.TRACE_EXPR_VAR_SCHEME + "_[0-9]{17,}:[\\s\\S]*?"
-                    + Pattern.quote(ModelWriter.CONSTANT_EXPRESSION_EVAL_IDENTIFIER) + "\n";
+                    + TLAConstants.Schemes.TRACE_EXPR_VAR_SCHEME + "_[0-9]{17,}:[\\s\\S]*?"
+                    + Pattern.quote(TLAConstants.CONSTANT_EXPRESSION_EVAL_IDENTIFIER) + "\n";
             IRegion region = teSearcher.find(0, regularExpression, true, true, false, true);
 
             while (region != null)
@@ -147,7 +153,7 @@ public class TraceExplorerDataProvider extends TLCModelLaunchDataProvider
                 // should be expr"$!@$!@$!@$!@$!" where "$!@$!@$!@$!@$!" is the delimiter
                 String expressionAndDelimiter = stringSections[3];
                 String expression = expressionAndDelimiter.substring(0, expressionAndDelimiter
-                        .indexOf(ModelWriter.CONSTANT_EXPRESSION_EVAL_IDENTIFIER));
+                        .indexOf(TLAConstants.CONSTANT_EXPRESSION_EVAL_IDENTIFIER));
 
                 TraceExpressionInformationHolder expressionData = new TraceExpressionInformationHolder(expression,
                         null, variableName);
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/source/TLCOutputSourceRegistry.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/source/TLCOutputSourceRegistry.java
index 9c1db294fa474596ebfa59c289506a25e6dffd85..292da433e1053294f36077000a604d8ff0a32c3e 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/source/TLCOutputSourceRegistry.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/source/TLCOutputSourceRegistry.java
@@ -163,8 +163,7 @@ public class TLCOutputSourceRegistry
             }
             IFile logFile = model.getOutputLogFile(isTraceExploreInstance);
             // log file found
-            if (logFile != null && logFile.exists())
-            {
+			if ((logFile != null) && logFile.exists()) {
                 // initialize the reader and read the content
                 // this will create the parser
                 // the parser will create a source and register in the registry
@@ -174,7 +173,6 @@ public class TLCOutputSourceRegistry
                 source = logFileReader.getSource();
                 source.addTLCOutputListener(listener);
 
-                // read in the data
                 // read in the data
                 final Job job = new WorkspaceJob("Logfile reader...") {
 					public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
@@ -188,8 +186,7 @@ public class TLCOutputSourceRegistry
 						return Status.OK_STATUS;
 					}
 				};
-				job.setProperty(IProgressConstants.PROPERTY_IN_DIALOG, true);
-				job.setPriority(Job.LONG);
+				job.setPriority(Job.SHORT);
 				job.setUser(true);
 				job.schedule();
 
@@ -231,7 +228,14 @@ public class TLCOutputSourceRegistry
     }
 
     /**
-     * Retrieves the data provider for the given configuration
+     * Retrieves the data provider for the given configuration.
+     * 
+     * Architecture TODO: it is unclear what we are gaining by keeping the same instance of a launch data provider
+     * 	attached to an instance of Model for the lifespan of the app (except in the following cases:
+     * 		. the model is deleted
+     * 		. loading existing output from the filesystem for the model
+     * )
+     * 
      * @return a data provider for the current model
      */
     public synchronized TLCModelLaunchDataProvider getProvider(Model model)
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/TraceExplorerComposite.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/TraceExplorerComposite.java
index 799bae18889a7ac011a9b434ab7f91812c6601f8..71afbaaed2548475b23772925460537afaddb971 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/TraceExplorerComposite.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/TraceExplorerComposite.java
@@ -29,7 +29,9 @@ package org.lamport.tla.toolbox.tool.tlc.traceexplorer;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 import java.util.Vector;
+import java.util.stream.Collectors;
 
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.resources.WorkspaceJob;
@@ -39,6 +41,8 @@ import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ToolBarManager;
 import org.eclipse.jface.dialogs.IDialogSettings;
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.layout.GridDataFactory;
@@ -72,19 +76,27 @@ import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.forms.widgets.FormToolkit;
 import org.eclipse.ui.forms.widgets.Section;
 import org.lamport.tla.toolbox.Activator;
+import org.lamport.tla.toolbox.spec.Spec;
 import org.lamport.tla.toolbox.tool.ToolboxHandle;
 import org.lamport.tla.toolbox.tool.tlc.launch.TraceExplorerDelegate;
-import org.lamport.tla.toolbox.tool.tlc.model.Formula;
-import org.lamport.tla.toolbox.tool.tlc.model.TraceExpressionModelWriter;
+import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
+import org.lamport.tla.toolbox.tool.tlc.ui.dialog.ExtraModulesDialog;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.provider.FormulaContentProvider;
 import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper;
 import org.lamport.tla.toolbox.tool.tlc.ui.view.TLCErrorView;
 import org.lamport.tla.toolbox.tool.tlc.ui.wizard.FormulaWizard;
 import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper;
+import org.lamport.tla.toolbox.util.RCPNameToFileIStream;
+
+import tlc2.model.Formula;
+import util.FilenameToStream;
+import util.TLAConstants;
 
 /**
  * This is somewhat mislabeled as a composite. Its really
@@ -199,8 +211,69 @@ public class TraceExplorerComposite
 		        dialogSettings.put(EXPANDED_STATE, section.isExpanded());
 			}
         });
+        
+		final ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
+		final ToolBar toolbar = toolBarManager.createControl(section);
+		toolBarManager.add(new ExtraModulesActions());
+		toolBarManager.update(true);
+		section.setTextClient(toolbar);
     }
 
+    private class ExtraModulesActions extends Action {
+
+		public ExtraModulesActions() {
+			super("Extend extra modules in trace expressions which are not extended by the actual spec.", TLCUIActivator
+					.getImageDescriptor("platform:/plugin/org.eclipse.ui/icons/full/etool16/new_fastview.png"));
+		}
+    	
+		@Override
+		public void run() {
+			final Spec currentSpec = ToolboxHandle.getCurrentSpec();
+			if (currentSpec != null && view.getModel() != null) {
+				// From the set of all modules remove those already included in the scope. The
+				// remaining unused modules are the ones a user might potentially be additional
+				// includes.
+				final Set<String> availableModules = currentSpec.getModules().stream().map(m -> m.getModuleName())
+						.collect(Collectors.toSet());
+				final FilenameToStream resolver = currentSpec.getValidRootModule().getResolver();
+				if (resolver instanceof RCPNameToFileIStream) {
+					final RCPNameToFileIStream rcpResolver = (RCPNameToFileIStream) resolver;
+					// Strip off ".tla" file extension.
+					availableModules.addAll(rcpResolver.getAllModules().stream()
+							.map(m -> m.replaceFirst((TLAConstants.Files.TLA_EXTENSION + "$"), ""))
+							.collect(Collectors.toSet()));
+				}
+				final Set<String> includedModules = currentSpec.getValidRootModule().getModuleNames();
+				
+				final Set<String> unusedModules = availableModules.stream()
+						.filter(m -> !includedModules.contains(m)).collect(Collectors.toSet());
+				
+				// Don't offer to extend  those modules which are already extended (implicitly).
+				unusedModules.remove("Toolbox");
+				unusedModules.remove("TLC");
+				
+				final ExtraModulesDialog extraModulesDialog = new ExtraModulesDialog(
+						PlatformUI.getWorkbench().getDisplay().getActiveShell(), unusedModules,
+						view.getModel().getTraceExplorerExtends());
+				if (Window.OK == extraModulesDialog.open()) { 
+					final Set<String> selectedModules = extraModulesDialog.getSelection();
+					
+					// Decouple I/O from UI thread.
+			    	final Job job = new WorkspaceJob("Saving updated model...") {
+						public IStatus runInWorkspace(final IProgressMonitor monitor) throws CoreException {
+							view.getModel().setTraceExplorerExtends(selectedModules);
+							view.getModel().save(monitor);
+							return Status.OK_STATUS;
+						}
+					};
+					job.setRule(ResourcesPlugin.getWorkspace().getRoot());
+					job.setUser(true);
+					job.schedule();
+				}
+			}
+		}
+    }
+    
     /**
      * Constructs the section content
      * 
@@ -735,7 +808,7 @@ public class TraceExplorerComposite
 				"Enter an expression to be evaluated at each state of the trace.",
 				String.format(
 						"The expression may be named and may include the %s and %s operators (click question mark below for details).",
-						TraceExpressionModelWriter.TRACE, TraceExpressionModelWriter.POSITION),
+						TLAConstants.TraceExplore.TRACE, TLAConstants.TraceExplore.POSITION),
 				"ErrorTraceExplorerExpression");
 		wizard.setFormula(formula);
 
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/ResultPresenter.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/ResultPresenter.java
index c38ca902941ac2567a7842062886d80deb12beb8..51c937793ba6fd663f59926ef60d139e678f2ac5 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/ResultPresenter.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/ResultPresenter.java
@@ -10,39 +10,30 @@ import org.lamport.tla.toolbox.util.UIHelper;
 /**
  * Responsible for presenting the TLC launch results
  * 
- * 
  * @author Simon Zambrovski
  */
-public class ResultPresenter implements IResultPresenter
-{
-
-    public void showResults(Model model)
-    {
+public class ResultPresenter implements IResultPresenter {
+	public void showResults(Model model) {
         /*
          * For trace exploration, just update the error view with the data
          * from the run of TLC for trace exploration. For model checking, open
          * the editor for that model, show the result page, and update the
          * data on the result page.
          */
-        if (model.getLastLaunch().getLaunchMode().equals(TraceExplorerDelegate.MODE_TRACE_EXPLORE))
-        {
+		if (model.getLastLaunch().getLaunchMode().equals(TraceExplorerDelegate.MODE_TRACE_EXPLORE)) {
             final ModelEditor modelEditor = model.getAdapter(ModelEditor.class);
-            if (modelEditor != null && modelEditor.getActivePage() != -1)
-            {
+			if ((modelEditor != null) && (modelEditor.getActivePage() != -1)) {
                 // If an editor is open and active on the model, update the error view.
                 // Although the trace explorer only takes a few seconds to run,
                 // the user could still switch to another model.
                 // If so, this code should not be run.
-                TLCErrorView.updateErrorView(model);
+                TLCErrorView.updateErrorView(modelEditor);
             }
-        } else
-        {
-            ModelEditor editor = (ModelEditor) UIHelper.openEditor(ModelEditor.ID, model.getFile());
-            if (editor != null)
-            {
-                editor.showResultPage();
+		} else {
+			final ModelEditor editor = (ModelEditor) UIHelper.openEditor(ModelEditor.ID, model.getFile());
+			if (editor != null) {
+                editor.addOrShowResultsPage();
             }
         }
     }
-
 }
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/TLCUIActivator.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/TLCUIActivator.java
index ce5fd7346ab98d712494f07e40bbd674c4a9cbaf..9feff1c21af3e062b6f105d899cb3159ae3021ee 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/TLCUIActivator.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/TLCUIActivator.java
@@ -88,7 +88,7 @@ public class TLCUIActivator extends AbstractTLCActivator
 			final UIJob j = new UIJob(Display.getCurrent(), "TLA+ execution statistics approval.") {
 				@Override
 				public IStatus runInUIThread(final IProgressMonitor monitor) {
-					new ExecutionStatisticsDialog(PlatformUI.createDisplay().getActiveShell()).open();
+					new ExecutionStatisticsDialog(false, PlatformUI.createDisplay().getActiveShell()).open();
 					return Status.OK_STATUS;
 				}
 			};
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/console/ConsoleFactory.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/console/ConsoleFactory.java
index 779ff9b28a69562dd08d19f4f51c0cda8b908daf..ecafa00bf67d1ad4997d25413e06df5bb5872bf0 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/console/ConsoleFactory.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/console/ConsoleFactory.java
@@ -7,13 +7,12 @@ import org.eclipse.ui.console.IConsole;
 import org.eclipse.ui.console.IConsoleConstants;
 import org.eclipse.ui.console.IConsoleFactory;
 import org.eclipse.ui.console.IConsoleManager;
-import org.eclipse.ui.console.MessageConsole;
+import org.eclipse.ui.console.IOConsole;
 import org.lamport.tla.toolbox.util.UIHelper;
 
 /**
  * A TLC console
  * @author Simon Zambrovski
- * @version $Id$
  */
 public class ConsoleFactory implements IConsoleFactory
 {
@@ -34,9 +33,9 @@ public class ConsoleFactory implements IConsoleFactory
         }
     }
 
-    public static MessageConsole getTLCConsole()
+    public static IOConsole getTLCConsole()
     {
-        MessageConsole console = findConsole(TLC_ID);
+    	IOConsole console = findConsole(TLC_ID);
 
         return console;
     }
@@ -46,7 +45,7 @@ public class ConsoleFactory implements IConsoleFactory
      * @param name, name of the console
      * @return
      */
-    private static MessageConsole findConsole(String name)
+    private static IOConsole findConsole(String name)
     {
         if (name == null)
         {
@@ -60,12 +59,12 @@ public class ConsoleFactory implements IConsoleFactory
         {
             if (name.equals(existing[i].getName()))
             {
-                return (MessageConsole) existing[i];
+                return (IOConsole) existing[i];
             }
         }
 
         // no console found, create a new one
-        MessageConsole myConsole = new MessageConsole(name, null);
+        IOConsole myConsole = new IOConsole(name, null);
         consoleManager.addConsoles(new IConsole[] { myConsole });
         return myConsole;
     }
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/ErrorViewTraceFilterDialog.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/ErrorViewTraceFilterDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..a9bf70a5bf89ec0c2283345572b34bd8115ff38d
--- /dev/null
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/ErrorViewTraceFilterDialog.java
@@ -0,0 +1,194 @@
+package org.lamport.tla.toolbox.tool.tlc.ui.dialog;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.lamport.tla.toolbox.tool.tlc.output.data.TLCVariable;
+
+/**
+ * The genesis of this dialog is https://github.com/tlaplus/tlaplus/issues/274 and then further modified to support
+ * https://github.com/tlaplus/tlaplus/issues/360
+ */
+public class ErrorViewTraceFilterDialog extends Dialog {
+	public enum MutatedFilter {
+		NO_FILTER, CHANGED_ALL_FRAMES, CHANGED_CHANGED_FRAMES;
+	}
+	
+	
+	private static final String[] MUTATED_VARIABLE_SELECTIONS = { "Show all variables",
+																  "Show only changed variables",
+																  "Show only changed variables in changed frames" };
+	
+	
+	private CheckboxTableViewer tableViewer;
+	
+	private final List<TLCVariable> variables;
+	private final HashSet<TLCVariable> selection;
+	
+	private Combo mutatedVariablesCombo;
+	private MutatedFilter selectedFilter;
+	
+	/**
+	 * @param parentShell
+	 * @param variableList a copy of this list will be made
+	 */
+	public ErrorViewTraceFilterDialog(final Shell parentShell, final List<TLCVariable> variableList) {
+		super(parentShell);
+		
+		variables = new ArrayList<>(variableList);
+		selection = new HashSet<>();
+	}
+	
+	public Set<TLCVariable> getSelection() {
+		return selection;
+	}
+	
+	public void setSelection(final Set<TLCVariable> newSelection) {
+		selection.clear();
+		
+		if ((newSelection == null) || (newSelection.size() == 0)) {
+			return;
+		}
+		
+		selection.addAll(newSelection);
+		if (tableViewer != null) {
+			tableViewer.setAllChecked(false);
+			selection.stream().forEach((element) -> tableViewer.setChecked(element, true));
+		}
+	}
+	
+	public MutatedFilter getMutatedFilterSelection() {
+		return selectedFilter;
+	}
+	
+    @Override
+    protected final Control createDialogArea(final Composite parent) {
+    	final Composite container = (Composite) super.createDialogArea(parent);
+    	GridLayout gl = new GridLayout(2, false);
+    	gl.verticalSpacing = 9;
+    	container.setLayout(gl);
+
+    	
+    	
+    	Label l = new Label(container, SWT.LEFT);
+    	l.setText("Selected variables and expressions will be hidden from the error trace.");
+    	l.setFont(JFaceResources.getFontRegistry().get(JFaceResources.DIALOG_FONT));
+    	GridData gd = new GridData();
+    	gd.horizontalSpan = 2;
+    	l.setLayoutData(gd);
+    	
+
+    	
+    	tableViewer = CheckboxTableViewer.newCheckList(container, SWT.BORDER | SWT.V_SCROLL | SWT.SINGLE);
+    	tableViewer.setContentProvider(new ArrayContentProvider());
+    	tableViewer.setLabelProvider(new ColumnLabelProvider() {
+    		@Override
+    		public String getText(final Object element) {
+    			return ((TLCVariable)element).getName();
+    		}
+    	});
+    	tableViewer.setInput(variables);
+		selection.stream().forEach((element) -> tableViewer.setChecked(element, true));
+    	gd = new GridData();
+    	gd.horizontalAlignment = SWT.FILL;
+    	gd.grabExcessHorizontalSpace = true;
+    	gd.minimumWidth = 333;
+    	tableViewer.getTable().setLayoutData(gd);
+    	
+    	
+    	final Composite buttonPane = new Composite(container, SWT.NONE);
+    	gl = new GridLayout(1, false);
+    	buttonPane.setLayout(gl);
+    	
+    	Button b = new Button(buttonPane, SWT.PUSH);
+    	b.setText("Select All");
+    	gd = new GridData();
+    	gd.horizontalAlignment = SWT.FILL;
+    	gd.grabExcessHorizontalSpace = true;
+    	b.setLayoutData(gd);
+    	b.addSelectionListener(new SelectionAdapter() {
+    		@Override
+    		public void widgetSelected(final SelectionEvent se) {
+    			tableViewer.setAllChecked(true);
+    		}
+    	});
+    	
+    	b = new Button(buttonPane, SWT.PUSH);
+    	b.setText("Deselect All");
+    	gd = new GridData();
+    	gd.horizontalAlignment = SWT.FILL;
+    	gd.grabExcessHorizontalSpace = true;
+    	b.setLayoutData(gd);
+    	b.addSelectionListener(new SelectionAdapter() {
+    		@Override
+    		public void widgetSelected(final SelectionEvent se) {
+    			tableViewer.setAllChecked(false);
+    		}
+    	});
+    	
+    	
+    	final Composite mutatedVariablesComboPane = new Composite(container, SWT.NONE);
+    	gd = new GridData();
+    	gd.horizontalAlignment = SWT.FILL;
+    	gd.grabExcessHorizontalSpace = true;
+    	gd.horizontalSpan = 2;
+    	mutatedVariablesComboPane.setLayoutData(gd);
+    	gl = new GridLayout(2, false);
+    	mutatedVariablesComboPane.setLayout(gl);
+    	
+    	l = new Label(mutatedVariablesComboPane, SWT.LEFT);
+    	l.setText("Filter by change:");
+    	l.setFont(JFaceResources.getFontRegistry().get(JFaceResources.DIALOG_FONT));
+    	
+    	mutatedVariablesCombo = new Combo(mutatedVariablesComboPane, SWT.READ_ONLY);
+    	mutatedVariablesCombo.setItems(MUTATED_VARIABLE_SELECTIONS);
+    	gd = new GridData();
+    	gd.horizontalAlignment = SWT.FILL;
+    	gd.grabExcessHorizontalSpace = true;
+    	mutatedVariablesCombo.setLayoutData(gd);
+    	mutatedVariablesCombo.setText(MUTATED_VARIABLE_SELECTIONS[0]);
+    	
+        return container;
+    }
+
+    @Override
+    protected void okPressed() {
+    	selection.clear();
+    	
+		Arrays.stream(tableViewer.getCheckedElements()).forEach((element) -> selection.add((TLCVariable)element));
+		selectedFilter = MutatedFilter.values()[mutatedVariablesCombo.getSelectionIndex()];
+		
+        super.okPressed();
+    }
+    
+    @Override
+    protected void createButtonsForButtonBar(Composite parent) {
+        createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
+    }
+    
+	@Override
+	protected void configureShell(Shell shell) {
+		super.configureShell(shell);
+		shell.setText("Error Trace Filter");
+	}
+}
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/ExtraModulesDialog.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/ExtraModulesDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..f9bc98ed01aa67313265eba2bc7bc99b5dc62688
--- /dev/null
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/ExtraModulesDialog.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Loki de Qualer - initial API and implementation
+ *   Markus Alexander Kuppe - Rewrite of ErrorViewTraceFilterDialog 
+ ******************************************************************************/
+package org.lamport.tla.toolbox.tool.tlc.ui.dialog;
+
+import java.util.Arrays;
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+public class ExtraModulesDialog extends Dialog {
+	private CheckboxTableViewer tableViewer;
+	
+	private final Set<String> modules;
+	private final Set<String> selection;
+	
+	/**
+	 * @param parentShell
+	 * @param modules a copy of this list will be made
+	 * @param previouslySelectedModuleNames 
+	 */
+	public ExtraModulesDialog(final Shell parentShell, final Set<String> modules, Set<String> previouslySelectedModuleNames) {
+		super(parentShell);
+		
+		this.modules = modules;
+		this.selection = previouslySelectedModuleNames;
+	}
+	
+	public Set<String> getSelection() {
+		return selection;
+	}
+	
+    @Override
+    protected final Control createDialogArea(final Composite parent) {
+    	final Composite container = (Composite) super.createDialogArea(parent);
+    	GridLayout gl = new GridLayout(2, false);
+    	gl.verticalSpacing = 9;
+    	container.setLayout(gl);
+
+    	
+    	
+    	final Label l = new Label(container, SWT.LEFT);
+    	l.setText("Selected modules to be made available in trace expressions.");
+    	l.setFont(JFaceResources.getFontRegistry().get(JFaceResources.DIALOG_FONT));
+    	GridData gd = new GridData();
+    	gd.horizontalSpan = 2;
+    	l.setLayoutData(gd);
+    	
+
+    	
+    	tableViewer = CheckboxTableViewer.newCheckList(container, SWT.BORDER | SWT.V_SCROLL | SWT.SINGLE);
+    	tableViewer.setContentProvider(new ArrayContentProvider());
+    	tableViewer.setLabelProvider(new ColumnLabelProvider() {
+    		@Override
+    		public String getText(final Object element) {
+    			return (String) element;
+    		}
+    	});
+    	tableViewer.setInput(modules);
+		selection.stream().forEach((element) -> tableViewer.setChecked(element, true));
+    	gd = new GridData();
+    	gd.horizontalAlignment = SWT.FILL;
+    	gd.grabExcessHorizontalSpace = true;
+    	gd.minimumWidth = 333;
+    	tableViewer.getTable().setLayoutData(gd);
+    	
+    	
+    	final Composite buttonPane = new Composite(container, SWT.NONE);
+    	gl = new GridLayout(1, false);
+    	buttonPane.setLayout(gl);
+    	
+    	Button b = new Button(buttonPane, SWT.PUSH);
+    	b.setText("Select All");
+    	gd = new GridData();
+    	gd.horizontalAlignment = SWT.FILL;
+    	gd.grabExcessHorizontalSpace = true;
+    	b.setLayoutData(gd);
+    	b.addSelectionListener(new SelectionAdapter() {
+    		@Override
+    		public void widgetSelected(final SelectionEvent se) {
+    			tableViewer.setAllChecked(true);
+    		}
+    	});
+    	
+    	b = new Button(buttonPane, SWT.PUSH);
+    	b.setText("Deselect All");
+    	gd = new GridData();
+    	gd.horizontalAlignment = SWT.FILL;
+    	gd.grabExcessHorizontalSpace = true;
+    	b.setLayoutData(gd);
+    	b.addSelectionListener(new SelectionAdapter() {
+    		@Override
+    		public void widgetSelected(final SelectionEvent se) {
+    			tableViewer.setAllChecked(false);
+    		}
+    	});
+    	
+    	
+        return container;
+    }
+
+    @Override
+    protected void okPressed() {
+    	selection.clear();
+    	
+		Arrays.stream(tableViewer.getCheckedElements()).forEach((element) -> selection.add((String)element));
+		
+        super.okPressed();
+    }
+    
+    @Override
+    protected void createButtonsForButtonBar(Composite parent) {
+        createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
+    }
+    
+	@Override
+	protected void configureShell(Shell shell) {
+		super.configureShell(shell);
+		shell.setText("Extra Modules");
+	}
+}
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/FilteredDefinitionSelectionDialog.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/FilteredDefinitionSelectionDialog.java
index 707fe89745443263f1b45ed2fd003a1379292dec..b79bb7905f28065af0363ec94007b73a16b5c658 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/FilteredDefinitionSelectionDialog.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/dialog/FilteredDefinitionSelectionDialog.java
@@ -9,6 +9,7 @@ import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.viewers.ILabelProvider;
 import org.eclipse.jface.viewers.LabelProvider;
 import org.eclipse.swt.widgets.Composite;
@@ -18,6 +19,7 @@ import org.eclipse.ui.IMemento;
 import org.eclipse.ui.dialogs.FilteredItemsSelectionDialog;
 import org.lamport.tla.toolbox.tool.ToolboxHandle;
 import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
+import org.lamport.tla.toolbox.tool.tlc.ui.editor.preference.IModelEditorPreferenceConstants;
 import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper;
 
 import tla2sany.modanalyzer.SpecObj;
@@ -115,14 +117,27 @@ public class FilteredDefinitionSelectionDialog extends FilteredItemsSelectionDia
             {
                 if (element instanceof OpDefNode)
                 {
-                    OpDefNode node = (OpDefNode) element;
+                    final OpDefNode node = (OpDefNode) element;
                     if (node.getSource() == node)
                     {
                         return node.getName().toString();
-                    } else
-                    {
-                        return node.getSource().getName().toString() + " ["
-                                + node.getSource().getOriginallyDefinedInModuleNode().getName().toString() + "]";
+					} else {
+						final IPreferenceStore ips = TLCUIActivator.getDefault().getPreferenceStore();
+						final String style = ips
+								.getString(IModelEditorPreferenceConstants.I_OVERRIDDEN_DEFINITION_STYLE);
+						final boolean moduleNameStyle = IModelEditorPreferenceConstants.I_OVERRIDDEN_DEFINITION_STYLE_MODULE_NAME
+								.equals(style);
+						
+						if (moduleNameStyle) {
+	                        return node.getSource().getName().toString() + " ["
+	                                + node.getSource().getOriginallyDefinedInModuleNode().getName().toString() + "]";
+						} else {
+	                        if (node.getSource().getOriginallyDefinedInModuleNode() != null) {
+	                        	return node.getName().toString();
+	                        } else {
+	                        	return node.getSource().getName().toString();
+	                        }
+						}
                     }
                 }
                 return super.getText(element);
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/DataBindingManager.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/DataBindingManager.java
index da891a479b1f874523bb04e58c806eeea6d3ec21..e8dcca4dc048b045e597a2da688cee23d2efe744 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/DataBindingManager.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/DataBindingManager.java
@@ -171,9 +171,10 @@ public class DataBindingManager implements ISectionConstants
     }
     
     /**
-     * Given an attribute name, remove all binding to it and its section.
+     * Given a section id and a page id, remove the binding to that couplet, if one exists.
      * 
-     * @param attributeName
+     * @param sectionId
+     * @param pageId
      */
     public void unbindSectionFromPage(final String sectionId, final String pageId) {
 		final Vector<String> sectionIds = sectionsForPage.get(pageId);
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ModelEditor.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ModelEditor.java
index 6ce26045f793b72d222ac3cf67e1ea74998f0154..95b913b608de6f5adc72528014f253d7efa3ecde 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ModelEditor.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ModelEditor.java
@@ -10,6 +10,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.commons.lang3.tuple.Pair;
 import org.eclipse.core.resources.IFile;
@@ -67,9 +68,11 @@ import org.lamport.tla.toolbox.tool.tlc.TLCActivator;
 import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants;
 import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationDefaults;
 import org.lamport.tla.toolbox.tool.tlc.launch.TLCModelLaunchDelegate;
+import org.lamport.tla.toolbox.tool.tlc.model.AbstractModelStateChangeListener;
 import org.lamport.tla.toolbox.tool.tlc.model.Model;
-import org.lamport.tla.toolbox.tool.tlc.model.Model.StateChangeListener.ChangeEvent.State;
 import org.lamport.tla.toolbox.tool.tlc.model.TLCModelFactory;
+import org.lamport.tla.toolbox.tool.tlc.output.data.CoverageInformation;
+import org.lamport.tla.toolbox.tool.tlc.output.data.ITLCModelLaunchDataPresenter;
 import org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider;
 import org.lamport.tla.toolbox.tool.tlc.output.source.TLCOutputSourceRegistry;
 import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
@@ -80,6 +83,7 @@ import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.advanced.AdvancedModelPag
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.advanced.AdvancedTLCOptionsPage;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results.EvaluateConstantExpressionPage;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results.ResultPage;
+import org.lamport.tla.toolbox.tool.tlc.ui.editor.preference.IModelEditorPreferenceConstants;
 import org.lamport.tla.toolbox.tool.tlc.ui.preference.ITLCPreferenceConstants;
 import org.lamport.tla.toolbox.tool.tlc.ui.util.ModelEditorPartListener;
 import org.lamport.tla.toolbox.tool.tlc.ui.util.SemanticHelper;
@@ -94,6 +98,7 @@ import org.lamport.tla.toolbox.util.UIHelper;
 import com.abstratt.graphviz.GraphViz;
 
 import tla2sany.semantic.ModuleNode;
+import util.TLAConstants;
 
 /**
  * Editor for the model.
@@ -119,75 +124,7 @@ public class ModelEditor extends FormEditor {
      */
     // helper to resolve semantic matches of words
     private SemanticHelper helper;
-    private final Model.StateChangeListener modelStateListener = new Model.StateChangeListener() {
-    	private State m_lastState = State.NOT_RUNNING;
-    	
-		@Override
-		public boolean handleChange(final ChangeEvent event) {
-			if (event.getState().in(State.NOT_RUNNING, State.RUNNING)) {
-				final State lastStateCopy = m_lastState;
-				UIHelper.runUIAsync(new Runnable() {
-					public void run() {
-						for (int i = 0; i < getPageCount(); i++) {
-							final Object object = pages.get(i);
-							if (object instanceof BasicFormPage) {
-								final BasicFormPage bfp = (BasicFormPage) object;
-								bfp.refresh();
-							}
-						}
-						if (event.getState().in(State.RUNNING)) {
-							// Switch to Result Page (put on top) of model editor stack. A user wants to see
-							// the status of a model run she has just started.
-							final IPreferenceStore ips = TLCUIActivator.getDefault().getPreferenceStore();
-							final boolean eceInItsOwnTab = ips.getBoolean(ITLCPreferenceConstants.I_TLC_SHOW_ECE_AS_TAB);
-
-							if (!eceInItsOwnTab || !modelIsConfiguredWithNoBehaviorSpec()) {
-								showResultPage();
-							}
-						} else if (event.getState().in(State.NOT_RUNNING)) {
-							// Model checking finished, lets open state graph if any.
-							if (event.getModel().hasStateGraphDump()) {
-								try {
-									addOrUpdateStateGraphEditor(event.getModel().getStateGraphDump());
-								} catch (CoreException e) {
-									TLCUIActivator.getDefault().logError("Error initializing editor", e);
-								}
-							}
-							
-							if (lastStateCopy.in(State.RUNNING, State.REMOTE_RUNNING)) {
-								final IPreferenceStore ips = TLCUIActivator.getDefault().getPreferenceStore();
-								final boolean eceInItsOwnTab = ips
-										.getBoolean(ITLCPreferenceConstants.I_TLC_SHOW_ECE_AS_TAB);
-								
-								if (eceInItsOwnTab && modelIsConfiguredWithNoBehaviorSpec()) {
-									setActivePage(EvaluateConstantExpressionPage.ID);
-								}
-							}
-							
-							// MAK 01/2018: Re-validate the page because running the model removes or sets
-							// problem markers (Model#setMarkers) which are presented to the user by
-							// ModelEditor#handleProblemMarkers. If we don't re-validate once a model is
-							// done running, the user visible presentation resulting from an earlier run of
-							// handleProblemMarkers gets stale.
-							// This behavior can be triggered by creating a spec (note commented EXTENDS): 
-							//   \* EXTENDS Integers
-							//   VARIABLE s
-							//   Spec == s = 0 /\ [][s'=s]_s
-							// and a model that defines the invariant (s >= 0). Upon the first launch of
-							// the model, the ModelEditor correctly marks the invariant due to the operator
-							// >= being not defined. Uncommenting EXTENDS, saving the spec and rerunning
-							// the model would incorrectly not remove the marker on the invariant.
-							UIHelper.runUISync(validateRunable);
-						}
-					}
-				});
-			}
-			
-			m_lastState = event.getState();
-			
-			return false;
-		}
-	};
+    private ModelStateListener modelStateListener = new ModelStateListener();
 
     /**
      * This runnable is responsible for the validation of the pages.
@@ -199,90 +136,59 @@ public class ModelEditor extends FormEditor {
      */
     private final ValidateRunnable validateRunable = new ValidateRunnable();
 
-    // TODO this is pretty poor design - there is one instance of this inner class per instance of ModelEditor; the 
-    //			code below tweaks the switchToErrorPage ivar and then hands it off to a run async method, i guess just
-    //			hoping that the flag isn't tweaked again before the async method does what was originally intended...
-	private class ValidateRunnable implements Runnable {
-        private boolean switchToErrorPage = false;
+    // data binding manager
+    private DataBindingManager dataBindingManager = new DataBindingManager();
 
-        public void run()
-        {
-            // Re-validate the pages, iff the model is not running.
-			// Also check if the model is nulled by now which
-			// happens if the ModelEditor disposed before a scheduled run gets
-			// executed.
-            if (model != null && !model.isRunning())
-            {
-                /*
-                 * Note that all pages are not necessarily
-                 * instances of BasicFormPage. Some are read
-                 * only editors showing saved versions of
-                 * modules.
-                 */
-                for (int i = 0; i < getPageCount(); i++)
-                {
-                    if (pages.get(i) instanceof BasicFormPage)
-                    {
-                        BasicFormPage page = (BasicFormPage) pages.get(i);
-                        page.resetAllMessages(true);
-                    }
-                }
-                for (int i = 0; i < getPageCount(); i++)
-                {
-                    if (pages.get(i) instanceof BasicFormPage)
-                    {
-                        BasicFormPage page = (BasicFormPage) pages.get(i);
-                        // re-validate the model on changes of the spec
-                        page.validatePage(switchToErrorPage);
-                    }
-                }
-            }
-        }
-    };
+    /**
+     * A listener that reacts to when editor tabs showing saved modules
+     * get closed. This listener properly disposes of the editor and its contents.
+     * See the class documentation for more details.
+     */
+    private CTabFolder2Listener listener = new CloseModuleTabListener();
+    
+    private final Map<Integer, Closeable> indexCloseableMap;
 
-    // react on spec file changes
-    private IResourceChangeListener workspaceResourceChangeListener = new IResourceChangeListener() {
-        public void resourceChanged(IResourceChangeEvent event)
-        {
-            IResourceDelta delta = event.getDelta();
+    // array of pages to add
+    private BasicFormPage[] pagesToAdd;
 
-            /**
-             * This is a helper method that returns a new instance of ChangedModulesGatheringDeltaVisitor,
-             * which gathers the changed TLA modules from a resource delta tree.
-             */
-            ChangedSpecModulesGatheringDeltaVisitor visitor = new ChangedSpecModulesGatheringDeltaVisitor(model) {
-                public IResource getModel()
-                {
-                    return model.getFile();
-                }
-            };
+	private Model model;
 
-            try
-            {
-                delta.accept(visitor);
-                // one of the modules in the specification has changed
-                // this means that identifiers defined in a spec might have changed
-                // re-validate the editor
-                if (!visitor.getModules().isEmpty() || visitor.isModelChanged() || visitor.getCheckpointChanged())
-                {
-                    // update the specObject of the helper
-                    helper.resetSpecNames();
+    // react on spec file changes
+	private IResourceChangeListener workspaceResourceChangeListener = (event) -> {
+		final IResourceDelta delta = event.getDelta();
+
+		/**
+		 * This is a helper method that returns a new instance of
+		 * ChangedModulesGatheringDeltaVisitor, which gathers the changed TLA modules
+		 * from a resource delta tree.
+		 */
+		final ChangedSpecModulesGatheringDeltaVisitor visitor = new ChangedSpecModulesGatheringDeltaVisitor(model) {
+			public IResource getModel() {
+				return model.getFile();
+			}
+		};
 
-                    // iff the model has changed, switch to the error page after the validation
-                    validateRunable.switchToErrorPage = visitor.isModelChanged();
+		try {
+			delta.accept(visitor);
+			// one of the modules in the specification has changed
+			// this means that identifiers defined in a spec might have changed
+			// re-validate the editor
+			if (!visitor.getModules().isEmpty() || visitor.isModelChanged() || visitor.getCheckpointChanged()) {
+				// update the specObject of the helper
+				helper.resetSpecNames();
 
-                    // re-validate the pages
-                    UIHelper.runUIAsync(validateRunable);
+				// iff the model has changed, switch to the error page after the validation
+				validateRunable.switchToErrorPage = visitor.isModelChanged();
 
-                    return;
-                }
-            } catch (CoreException e)
-            {
-                TLCUIActivator.getDefault().logError("Error visiting changed resource", e);
-                return;
-            }
+				// re-validate the pages
+				UIHelper.runUIAsync(validateRunable);
 
-        }
+				return;
+			}
+		} catch (CoreException e) {
+			TLCUIActivator.getDefault().logError("Error visiting changed resource", e);
+			return;
+		}
     };
     
 	/**
@@ -297,11 +203,16 @@ public class ModelEditor extends FormEditor {
 		navigationHistory.markLocation((IEditorPart) event.getSelectedPage());
 	};
 	
-	private final IPropertyChangeListener m_preferenceChangeListener = (event) -> {
-		if (ITLCPreferenceConstants.I_TLC_SHOW_ECE_AS_TAB.equals(event.getProperty())) {
+	private final IPropertyChangeListener preferenceChangeListener = (event) -> {
+		if (IModelEditorPreferenceConstants.I_MODEL_EDITOR_SHOW_ECE_AS_TAB.equals(event.getProperty())) {
 			final boolean eceAsTab = ((Boolean) event.getNewValue()).booleanValue();
 			final Pair<Integer, FormPage> pair = getLastFormPage();
 			final String id = pair.getRight().getId();
+			
+			// No results page open, so don't show the ECE page, slash, affect the results page to show the ECE section
+			if (!ResultPage.ID.equals(id) && !EvaluateConstantExpressionPage.ID.equals(id)) {
+				return;
+			}
 
 			if (eceAsTab) {
 				if (!EvaluateConstantExpressionPage.ID.equals(id)) {
@@ -335,29 +246,21 @@ public class ModelEditor extends FormEditor {
 		}
 	};
 
-    // data binding manager
-    private DataBindingManager dataBindingManager = new DataBindingManager();
-
-    /**
-     * A listener that reacts to when editor tabs showing saved modules
-     * get closed. This listener properly disposes of the editor and its contents.
-     * See the class documentation for more details.
-     */
-    private CTabFolder2Listener listener = new CloseModuleTabListener();
-    
-    private final Map<Integer, Closeable> m_indexCloseableMap;
-
-    // array of pages to add
-    private BasicFormPage[] pagesToAdd;
-
-	private Model model;
-
     /**
      * Simple editor constructor
      */
 	public ModelEditor() {
 		helper = new SemanticHelper();
-		m_indexCloseableMap = new HashMap<>();
+		indexCloseableMap = new HashMap<>();
+	}
+	
+	/**
+	 * This constructor should only be used with certain unit tests.
+	 */
+	public ModelEditor(final Model testingModel) {
+		this();
+		
+		model = testingModel;
 	}
 
     /**
@@ -382,37 +285,42 @@ public class ModelEditor extends FormEditor {
         try {
 			openTabsValue = model.getLaunchConfiguration().getAttribute(IModelConfigurationConstants.EDITOR_OPEN_TABS, 0);
         } catch (CoreException e) { }
-        
-		final IPreferenceStore ips = TLCUIActivator.getDefault().getPreferenceStore();
-		final boolean eceInItsOwnTab = ips.getBoolean(ITLCPreferenceConstants.I_TLC_SHOW_ECE_AS_TAB);
 
+        final boolean mustShowResultsPage
+        			= model.isSnapshot()
+        				|| parsePotentialAssociatedTLCRunToDetermineWhetherResultsPageMustBeShown();
+		final IPreferenceStore ips = TLCUIActivator.getDefault().getPreferenceStore();
         if (openTabsValue == IModelConfigurationConstants.EDITOR_OPEN_TAB_NONE) {
-        	if (eceInItsOwnTab) {
-				pagesToAdd = new BasicFormPage[] { new MainModelPage(this), new ResultPage(this), new EvaluateConstantExpressionPage(this) };
-			} else {
-				pagesToAdd = new BasicFormPage[] { new MainModelPage(this), new ResultPage(this) };
-			}
+			pagesToAdd = mustShowResultsPage
+									? new BasicFormPage[] { new MainModelPage(this), new ResultPage(this) }
+									: new BasicFormPage[] { new MainModelPage(this) };
         } else {
-        	ArrayList<BasicFormPage> pages = new ArrayList<>();
-        	
-        	pages.add(new MainModelPage(this));
-			if ((openTabsValue
-					& IModelConfigurationConstants.EDITOR_OPEN_TAB_ADVANCED_MODEL) == IModelConfigurationConstants.EDITOR_OPEN_TAB_ADVANCED_MODEL) {
-				pages.add(new AdvancedModelPage(this));
+        	final ArrayList<BasicFormPage> editorPages = new ArrayList<>();
+            
+        	editorPages.add(new MainModelPage(this));
+			if ((openTabsValue & IModelConfigurationConstants.EDITOR_OPEN_TAB_ADVANCED_MODEL) != 0) {
+				editorPages.add(new AdvancedModelPage(this));
         	}
-			if ((openTabsValue
-					& IModelConfigurationConstants.EDITOR_OPEN_TAB_ADVANCED_TLC) == IModelConfigurationConstants.EDITOR_OPEN_TAB_ADVANCED_TLC) {
-				pages.add(new AdvancedTLCOptionsPage(this));
+			if ((openTabsValue & IModelConfigurationConstants.EDITOR_OPEN_TAB_ADVANCED_TLC) != 0) {
+				editorPages.add(new AdvancedTLCOptionsPage(this));
         	}
-        	pages.add(new ResultPage(this));
-        	if (eceInItsOwnTab) {
-        		pages.add(new EvaluateConstantExpressionPage(this));
+			if (mustShowResultsPage
+							|| ((openTabsValue & IModelConfigurationConstants.EDITOR_OPEN_TAB_RESULTS) != 0)) {
+				editorPages.add(new ResultPage(this));
+	        	if (ips.getBoolean(IModelEditorPreferenceConstants.I_MODEL_EDITOR_SHOW_ECE_AS_TAB)) {
+	        		editorPages.add(new EvaluateConstantExpressionPage(this));
+	        	}
+	        	
+	        	if (mustShowResultsPage) {
+	        		final int openTabState = getModel().getOpenTabsValue();
+	        		updateOpenTabsState(openTabState | IModelConfigurationConstants.EDITOR_OPEN_TAB_RESULTS);	        		
+	        	}
         	}
 
-            pagesToAdd = pages.toArray(new BasicFormPage[pages.size()]);
+            pagesToAdd = editorPages.toArray(new BasicFormPage[editorPages.size()]);
         }
         
-        ips.addPropertyChangeListener(m_preferenceChangeListener);
+        ips.addPropertyChangeListener(preferenceChangeListener);
         
         
         // setContentDescription(path.toString());
@@ -453,6 +361,40 @@ public class ModelEditor extends FormEditor {
 		model.add(modelStateListener);
 	}
     
+    // how's that for a method name....
+    private boolean parsePotentialAssociatedTLCRunToDetermineWhetherResultsPageMustBeShown() {
+        final TLCModelLaunchDataProvider ldp = TLCOutputSourceRegistry.getModelCheckSourceRegistry().getProvider(model);
+        final AtomicBoolean hasStartTime = new AtomicBoolean(false);
+        final AtomicBoolean hasError = new AtomicBoolean(false);
+        final AtomicBoolean hasZeroCoverage = new AtomicBoolean(false);
+    	final ITLCModelLaunchDataPresenter consumer = (dataProvider, fieldId) -> {
+    		switch (fieldId) {
+    			case ITLCModelLaunchDataPresenter.START_TIME:
+    				hasStartTime.set(dataProvider.getStartTimestamp() > 0);
+    				break;
+    			case ITLCModelLaunchDataPresenter.COVERAGE:
+    				if (!hasZeroCoverage.get()) {
+						final CoverageInformation coverageInfo = dataProvider.getCoverageInfo();
+						if (dataProvider.isDone() && !coverageInfo.isEmpty() && dataProvider.hasZeroCoverage()) {
+							hasZeroCoverage.set(true);
+						}
+					}
+    				break;
+    			case ITLCModelLaunchDataPresenter.ERRORS:
+    				if (dataProvider.getErrors().size() > 0) {
+    					hasError.set(true);
+    				}
+    				break;
+    		}
+    	};
+    	
+    	ldp.addDataPresenter(consumer);
+    	ldp.waitForParsingFinish();
+    	ldp.removeDataPresenter(consumer);
+    	
+    	return hasStartTime.get() || hasError.get() || hasZeroCoverage.get();
+    }
+    
     /**
 	 * @param index the tab index
 	 * @return null if the index is greater than or equal to the number of tabs,
@@ -475,7 +417,7 @@ public class ModelEditor extends FormEditor {
 	public void dispose() {
 		removePageChangedListener(pageChangedListener);
 		
-		TLCUIActivator.getDefault().getPreferenceStore().removePropertyChangeListener(m_preferenceChangeListener);
+		TLCUIActivator.getDefault().getPreferenceStore().removePropertyChangeListener(preferenceChangeListener);
 		
         // TLCUIActivator.getDefault().logDebug("entering ModelEditor#dispose()");
         // remove the listeners
@@ -662,11 +604,9 @@ public class ModelEditor extends FormEditor {
         	tabFolder.setTabPosition(SWT.TOP);
         	tabFolder.addCTabFolder2Listener(listener);
 
-            for (int i = 0; i < pagesToAdd.length; i++)
-            {
+			for (int i = 0; i < pagesToAdd.length; i++) {
                 addPage(pagesToAdd[i]);
                 // initialize the page
-
                 // this means the content will be created
                 // the data will be loaded
                 // the refresh method will update the UI state
@@ -685,7 +625,7 @@ public class ModelEditor extends FormEditor {
                 if (pagesToAdd[i] instanceof Closeable) {
         			item.setShowClose(true);
         			
-        			m_indexCloseableMap.put(new Integer(i), (Closeable)pagesToAdd[i]);
+        			indexCloseableMap.put(new Integer(i), (Closeable)pagesToAdd[i]);
                 }
             }
 
@@ -697,7 +637,7 @@ public class ModelEditor extends FormEditor {
             final ModuleNode rootModule = SemanticHelper.getRootModuleNode();
 			if ((rootModule != null) && (rootModule.getVariableDecls().length == 0)
 					&& (rootModule.getConstantDecls().length == 0)) {
-            	showResultPage();
+            	addOrShowResultsPage();
             }
             
             if (model.hasStateGraphDump()) {
@@ -730,22 +670,27 @@ public class ModelEditor extends FormEditor {
 		// constants to not introduce a plugin dependency.
 		// org.lamport.tla.toolbox.tool.tla2tex.TLA2TeXActivator.PLUGIN_ID
 		// org.lamport.tla.toolbox.tool.tla2tex.preference.ITLA2TeXPreferenceConstants.EMBEDDED_VIEWER
+		// org.lamport.tla.toolbox.tool.tla2tex.preference.ITLA2TeXPreferenceConstants.HAVE_OS_OPEN_PDF
 		final boolean useEmbeddedViewer = Platform.getPreferencesService()
 				.getBoolean("org.lamport.tla.toolbox.tool.tla2tex", "embeddedViewer", false, null);
+		final boolean osOpensPDF = Platform.getPreferencesService()
+				.getBoolean("org.lamport.tla.toolbox.tool.tla2tex", "osHandlesPDF", false, null);
 		
-		final IEditorPart findEditor;
-		if (useEmbeddedViewer) {
+		final IEditorPart pdfEditor;
+		if (osOpensPDF) {
+			pdfEditor = null;
+		} else if (useEmbeddedViewer) {
 			// Try to get hold of the editor instance without opening it yet. Opening is
 			// triggered by calling addPage.
-			findEditor = UIHelper.findEditor("de.vonloesch.pdf4eclipse.editors.PDFEditor");
+			pdfEditor = UIHelper.findEditor("de.vonloesch.pdf4eclipse.editors.PDFEditor");
 		} else {
-			findEditor = UIHelper.findEditor(PDFBrowserEditor.ID);
+			pdfEditor = UIHelper.findEditor(PDFBrowserEditor.ID);
 		}
 
 		// Load a previously generated pdf file.
 		final IFile pdfFile = model.getFolder().getFile(model.getName() + ".pdf");
 		if (pdfFile.exists()) {
-			saferAddPage(stateGraphDotDump, findEditor, pdfFile, useEmbeddedViewer);
+			saferAddPage(stateGraphDotDump, pdfEditor, pdfFile, useEmbeddedViewer);
 			return;
 		}
 
@@ -767,7 +712,7 @@ public class ModelEditor extends FormEditor {
 					UIHelper.runUISync(new Runnable() {
 						@Override
 						public void run() {
-							ModelEditor.this.saferAddPage(stateGraphDotDump, findEditor, pdfFile, useEmbeddedViewer);
+							ModelEditor.this.saferAddPage(stateGraphDotDump, pdfEditor, pdfFile, useEmbeddedViewer);
 						}
 					});
 				} catch (CoreException e) {
@@ -789,9 +734,23 @@ public class ModelEditor extends FormEditor {
 	}
 
 	// Attempt to handle (primarily) OutOfMemory errors when opening large pdf files. 
-	private void saferAddPage(final IFile stateGraphDotDump, final IEditorPart findEditor, final IFile file, final boolean usesEmbeddedViewer) {
+	private void saferAddPage(final IFile stateGraphDotDump, final IEditorPart pdfEditor, final IFile file,
+			final boolean usesEmbeddedViewer) {
+		if (pdfEditor == null) {
+			// This is the case when the user would like the OS to open the PDF.
+			final String openCommand = "open " + file.getLocation().toOSString();
+			
+			try {
+				Runtime.getRuntime().exec(openCommand);
+			} catch (final Exception e) {
+				TLCUIActivator.getDefault().logError("Unable to execute 'open' command on PDF.", e);
+			}
+			
+			return;
+		}
+		
 		try {
-			addPage(findEditor, new FileEditorInput(file));
+			addPage(pdfEditor, new FileEditorInput(file));
 		} catch (PartInitException e) {
 			final Shell shell = Display.getDefault().getActiveShell();
 			MessageDialog.openError(shell == null ? new Shell() : shell,
@@ -963,7 +922,7 @@ public class ModelEditor extends FormEditor {
 							if (ModelHelper.containsModelCheckingModuleConflict(rootModuleName)) {
 								MessageDialog.openError(getSite().getShell(), "Illegal module name",
 										"Model validation and checking is not allowed on a spec containing a module named "
-												+ ModelHelper.MC_MODEL_NAME + "."
+												+ TLAConstants.Files.MODEL_CHECK_FILE_BASENAME + "."
 												+ (userInvoked ? "" : " However, the model can still be saved."));
 								return;
 							}
@@ -1039,10 +998,10 @@ public class ModelEditor extends FormEditor {
 							return;
 						}
 					} else {
-						// launching the config
-						model.launch(mode, SubMonitor.convert(monitor, 1), true);
-						
 						/*
+						 * Notify that model checking has begun ahead the launch to avoid potentially cleaning state
+						 * 	after it has started mutating.
+						 * 
 						 * Close any tabs in this editor containing read-only versions of modules. They
 						 * will be changed by the launch, regardless of the mode. We could do something
 						 * more sophisticated like listening to resource changes and updating the
@@ -1053,7 +1012,7 @@ public class ModelEditor extends FormEditor {
 						 */
 						for (int i = getPageCount() - 1; i >= 0; i--) {
 							if (pages.get(i) instanceof BasicFormPage) {
-								((BasicFormPage)pages.get(i)).modelCheckingHasBegun();
+								((BasicFormPage)pages.get(i)).modelCheckingWillBegin();
 							} else {
 								/*
 								 * The normal form pages (main model page, advanced options, results) are remain
@@ -1064,6 +1023,9 @@ public class ModelEditor extends FormEditor {
 							}
 						}
 
+						// launching the config
+						model.launch(mode, SubMonitor.convert(monitor, 1), true);
+						
 						// clear the error view when launching the model
 						// checker
 						// but not when validating
@@ -1151,16 +1113,14 @@ public class ModelEditor extends FormEditor {
             IMarker[] modelProblemMarkers = model.getMarkers();
             DataBindingManager dm = getDataBindingManager();
 
-            for (int j = 0; j < getPageCount(); j++)
-            {
+			for (int j = 0; j < getPageCount(); j++) {
                 /*
                  * Note that all pages are not necessarily
                  * instances of BasicFormPage. Some are read
                  * only editors showing saved versions of
                  * modules.
                  */
-                if (pages.get(j) instanceof BasicFormPage)
-                {
+				if (pages.get(j) instanceof BasicFormPage) {
                     // get the current page
                     BasicFormPage page = (BasicFormPage) pages.get(j);
                     Assert.isNotNull(page.getManagedForm(), "Page not initialized, this is a bug.");
@@ -1191,40 +1151,36 @@ public class ModelEditor extends FormEditor {
                             bubbleType = IMessageProvider.INFORMATION;
                         }
 
-                        if (ModelHelper.EMPTY_STRING.equals(attributeName))
-                        {
+						if (ModelHelper.EMPTY_STRING.equals(attributeName)) {
                             final String message = modelProblemMarkers[i].getAttribute(IMarker.MESSAGE,
                                     IModelConfigurationDefaults.EMPTY_STRING);
-							int pageId = modelProblemMarkers[i]
-									.getAttribute(ModelHelper.TLC_MODEL_ERROR_MARKER_ATTRIBUTE_PAGE, -1);
+							final String pageId = modelProblemMarkers[i]
+									.getAttribute(ModelHelper.TLC_MODEL_ERROR_MARKER_ATTRIBUTE_PAGE, null);
                             // no attribute, this is a global error, not bound to a particular attribute
                             // install it on the first page
                             // if it is a global TLC error, then we call addGlobalTLCErrorMessage()
                             // to add a hyperlink to the TLC Error view
-							if ((pageId != -1) && (bubbleType == IMessageProvider.WARNING)
+							if ((pageId != null) && (bubbleType == IMessageProvider.WARNING)
 									&& !IModelConfigurationDefaults.EMPTY_STRING.equals(message)) {
-								// Used by the ResultPage to display an error on
-								// incomplete state space exploration.
-								if (pageId >= pagesToAdd.length) {
-									pageId = pagesToAdd.length - 1;
+								final ResultPage rp = (ResultPage)findPage(ResultPage.ID);
+								if (rp != null) {
+									rp.addGlobalTLCErrorMessage(ResultPage.RESULT_PAGE_PROBLEM, message);
 								}
-								pagesToAdd[pageId].addGlobalTLCErrorMessage(ResultPage.RESULT_PAGE_PROBLEM, message);
 							} else if (bubbleType == IMessageProvider.WARNING) {
 								final PageIterator iterator = new PageIterator();		
 								while (iterator.hasNext()) {
 									final BasicFormPage bfp = iterator.next();
 									
-									if (!bfp.getId().equals(ResultPage.ID)) {
+									if (!ResultPage.ID.equals(bfp.getId())) {
 										bfp.addGlobalTLCErrorMessage("modelProblem_" + i);
 									}
 								}
 							} else {
 								// else install as with other messages
-								IMessageManager mm = pagesToAdd[0].getManagedForm().getMessageManager();
+								IMessageManager mm = ((BasicFormPage)pages.get(0)).getManagedForm().getMessageManager();
 								mm.addMessage("modelProblem_" + i, message, null, bubbleType);
 							}
-                        } else
-                        {
+						} else {
                             // attribute found
                             String sectionId = dm.getSectionForAttribute(attributeName);
                             Assert.isNotNull(sectionId,
@@ -1289,9 +1245,9 @@ public class ModelEditor extends FormEditor {
     }
     
     public void setActivePage(int index) {
-    	if(pages != null) {
-    		super.setActivePage(index);
-    	}
+		if ((pages != null) && (getCurrentPage() != index)) {
+			super.setActivePage(index);
+		}
     }
 
     /**
@@ -1349,25 +1305,6 @@ public class ModelEditor extends FormEditor {
         }
         return null;
     }
-
-    /**
-     * Show the result page of the editor    
-     */
-    public void showResultPage()
-    {
-        // goto result page
-        IFormPage resultPage = setActivePage(ResultPage.ID);
-        if (resultPage != null)
-        {
-            try
-            {
-                ((ResultPage) resultPage).loadData();
-            } catch (CoreException e)
-            {
-                TLCUIActivator.getDefault().logError("Error refreshing the result page", e);
-            }
-        }
-    }
     
 	/**
 	 * Expands the given sections on the model editor pages. 
@@ -1473,7 +1410,7 @@ public class ModelEditor extends FormEditor {
     }
 
     /**
-     * Invoke this to save the model.
+     * Invoke this to save the model via a workspace job.
      */
     public void saveModel() {
     	final Job job = new WorkspaceJob("Saving updated model...") {
@@ -1506,10 +1443,13 @@ public class ModelEditor extends FormEditor {
         if (setActivePage(AdvancedTLCOptionsPage.ID) == null) {
         	try {
         		int pageIndex = 1;
-        		final String id = getIdForEditorAtIndex(1);
+        		
+        		if (pageIndex < getPageCount()) {
+            		final String id = getIdForEditorAtIndex(pageIndex);
 
-        		if (AdvancedModelPage.ID.equals(id)) {
-        			pageIndex++;
+            		if (AdvancedModelPage.ID.equals(id)) {
+            			pageIndex++;
+            		}
         		}
 
         		addPage(pageIndex, new AdvancedTLCOptionsPage(this), getEditorInput());
@@ -1523,7 +1463,62 @@ public class ModelEditor extends FormEditor {
         	}
         }
     }
+    
+    public void addOrShowResultsPage() {
+        if (setActivePage(ResultPage.ID) == null) {
+        	try {
+        		int pageIndex = 1;
+        		
+        		if (pageIndex < getPageCount()) {
+            		String id = getIdForEditorAtIndex(pageIndex);
+
+            		if (AdvancedTLCOptionsPage.ID.equals(id) || AdvancedModelPage.ID.equals(id)) {
+            			pageIndex++;
+            			
+                		if (pageIndex < getPageCount()) {
+                    		id = getIdForEditorAtIndex(pageIndex);
+
+                    		if (AdvancedTLCOptionsPage.ID.equals(id) || AdvancedModelPage.ID.equals(id)) {
+                    			pageIndex++;
+                    		}
+                		}
+            		}
+        		}
+
+        		addPage(pageIndex, new ResultPage(this), getEditorInput());
 
+        		final IPreferenceStore ips = TLCUIActivator.getDefault().getPreferenceStore();
+	        	if (ips.getBoolean(IModelEditorPreferenceConstants.I_MODEL_EDITOR_SHOW_ECE_AS_TAB)) {
+	        		addPage((pageIndex + 1), new EvaluateConstantExpressionPage(this), getEditorInput());
+	        	}
+
+        		ResultPage rp = (ResultPage)setActivePage(ResultPage.ID);
+        		
+        		final int openTabState = getModel().getOpenTabsValue();
+        		updateOpenTabsState(openTabState | IModelConfigurationConstants.EDITOR_OPEN_TAB_RESULTS);
+        		
+        		rp.loadData();
+        		
+        		// MMP for architecturally unclear reasons, is charged with updating content on the RP
+        		final MainModelPage page = (MainModelPage)findPage(MainModelPage.ID);
+        		page.validatePage(true);
+        	} catch (Exception e) {
+				TLCActivator.getDefault().getLog().log(new Status(IStatus.ERROR, TLCActivator.PLUGIN_ID,
+						"Could not add results page", e));
+        	}
+        }
+    }
+    
+    public void resultsPageIsClosing() {
+		final IPreferenceStore ips = TLCUIActivator.getDefault().getPreferenceStore();
+    	if (ips.getBoolean(IModelEditorPreferenceConstants.I_MODEL_EDITOR_SHOW_ECE_AS_TAB)) {
+    		removePage(getPageCount() - 1);
+    	}
+    	
+		final int openTabState = getModel().getOpenTabsValue();
+		updateOpenTabsState(openTabState & ~IModelConfigurationConstants.EDITOR_OPEN_TAB_RESULTS);
+    }
+    
     /**
      * Overrides the method in {@link FormEditor}. Calls this method in the superclass
      * and then makes some changes if the input is a tla file.
@@ -1537,8 +1532,7 @@ public class ModelEditor extends FormEditor {
      * 2.) Set those pages to be closeable. This makes it possible to click on the tab
      *     to close it.
      */
-    public void addPage(int index, IEditorPart editor, IEditorInput input) throws PartInitException
-    {
+	public void addPage(int index, IEditorPart editor, IEditorInput input) throws PartInitException {
         super.addPage(index, editor, input);
         //TODO This method screams to be refactored and simplified, but sadly life is short.
         /*
@@ -1571,14 +1565,14 @@ public class ModelEditor extends FormEditor {
 
 			final int tabCount = tabFolder.getItemCount();
 			for (int i = tabCount - 2; i >= index; i--) {
-				final Closeable c = m_indexCloseableMap.remove(new Integer(i));
+				final Closeable c = indexCloseableMap.remove(new Integer(i));
 				
 				if (c != null) {
-					m_indexCloseableMap.put(new Integer(i + 1), c);
+					indexCloseableMap.put(new Integer(i + 1), c);
 				}
 			}
 
-			m_indexCloseableMap.put(new Integer(index), (Closeable)editor);
+			indexCloseableMap.put(new Integer(index), (Closeable)editor);
 		}
     }
 
@@ -1614,14 +1608,14 @@ public class ModelEditor extends FormEditor {
         	//	man-years wasted writing and dealing with you..
         	// event.item is already disposed by the time we get notified so we can't use its data holder which is
 			//	what is being used to hold the editor part by our super-superclass... kwality
-			final Closeable c = m_indexCloseableMap.remove(new Integer(index));
+			final Closeable c = indexCloseableMap.remove(new Integer(index));
 			if (c != null) {
 				final int tabCount = tabFolder.getItemCount();
 				for (int i = index; i <= tabCount; i++) {
-					final Closeable remaining = m_indexCloseableMap.remove(new Integer(i));
+					final Closeable remaining = indexCloseableMap.remove(new Integer(i));
 					
 					if (remaining != null) {
-						m_indexCloseableMap.put(new Integer(i - 1), remaining);
+						indexCloseableMap.put(new Integer(i - 1), remaining);
 					}
 				}
 
@@ -1642,29 +1636,29 @@ public class ModelEditor extends FormEditor {
 	 */
 	private class PageIterator implements Iterator<BasicFormPage> {
 
-		private final List<Object> m_pages;
-		private int m_counter;
+		private final List<Object> cachedPages;
+		private int counter;
 		
-		private BasicFormPage m_nextPage;
+		private BasicFormPage nextPage;
 		
 		PageIterator() {
-			m_pages = new ArrayList<>(pages);
-			m_counter = 0;
-			
-			m_nextPage = findNextPage();
+			cachedPages = new ArrayList<>(pages);
+			counter = 0;
+
+			nextPage = findNextPage();
 		}
 		
 		private BasicFormPage findNextPage() {
 			BasicFormPage page = null;
 			
-			while ((page == null) && (m_counter < m_pages.size())) {
-				final Object o = m_pages.get(m_counter);
+			while ((page == null) && (counter < cachedPages.size())) {
+				final Object o = cachedPages.get(counter);
 				
 				if (o instanceof BasicFormPage) {
 					page = (BasicFormPage)o;
 				}
 				
-				m_counter++;
+				counter++;
 			}
 			
 			return page;
@@ -1672,16 +1666,128 @@ public class ModelEditor extends FormEditor {
 		
 		@Override
 		public boolean hasNext() {
-			return (m_nextPage != null);
+			return (nextPage != null);
 		}
 
 		@Override
 		public BasicFormPage next() {
-			final BasicFormPage next = m_nextPage;
+			final BasicFormPage next = nextPage;
 			
-			m_nextPage = findNextPage();
+			nextPage = findNextPage();
 
 			return next;
 		}
 	}
+
+	
+    // TODO this is pretty poor design - there is one instance of this inner class per instance of ModelEditor; the 
+    //			code below tweaks the switchToErrorPage ivar and then hands it off to a run async method, i guess just
+    //			hoping that the flag isn't tweaked again before the async method does what was originally intended...
+	private class ValidateRunnable implements Runnable {
+        private boolean switchToErrorPage = false;
+
+        @Override
+		public void run() {
+            // Re-validate the pages, iff the model is not running.
+			// Also check if the model is nulled by now which
+			// happens if the ModelEditor disposed before a scheduled run gets
+			// executed.
+            if ((model != null) && !model.isRunning())
+            {
+                /*
+                 * Note that all pages are not necessarily
+                 * instances of BasicFormPage. Some are read
+                 * only editors showing saved versions of
+                 * modules.
+                 */
+                for (int i = 0; i < getPageCount(); i++)
+                {
+                    if (pages.get(i) instanceof BasicFormPage)
+                    {
+                        BasicFormPage page = (BasicFormPage) pages.get(i);
+                        page.resetAllMessages(true);
+                    }
+                }
+                for (int i = 0; i < getPageCount(); i++)
+                {
+                    if (pages.get(i) instanceof BasicFormPage)
+                    {
+                        BasicFormPage page = (BasicFormPage) pages.get(i);
+                        // re-validate the model on changes of the spec
+                        page.validatePage(switchToErrorPage);
+                    }
+                }
+            }
+        }
+    }
+	
+	
+	private class ModelStateListener extends AbstractModelStateChangeListener {
+    	private State lastState = State.NOT_RUNNING;
+    	
+		@Override
+		public boolean handleChange(final ChangeEvent event) {
+			if (event.getState().in(State.NOT_RUNNING, State.RUNNING)) {
+				final State lastStateCopy = lastState;
+				UIHelper.runUIAsync(() -> {
+					for (int i = 0; i < getPageCount(); i++) {
+						final Object object = pages.get(i);
+						if (object instanceof BasicFormPage) {
+							final BasicFormPage bfp = (BasicFormPage) object;
+							bfp.refresh();
+						}
+					}
+					if (event.getState().in(State.RUNNING)) {
+						// Switch to Result Page (put on top) of model editor stack. A user wants to see
+						// the status of a model run she has just started.
+						final IPreferenceStore ips = TLCUIActivator.getDefault().getPreferenceStore();
+						final boolean eceInItsOwnTab = ips
+								.getBoolean(IModelEditorPreferenceConstants.I_MODEL_EDITOR_SHOW_ECE_AS_TAB);
+
+						if (!eceInItsOwnTab || !modelIsConfiguredWithNoBehaviorSpec()) {
+							addOrShowResultsPage();
+						}
+					} else if (event.getState().in(State.NOT_RUNNING)) {
+						// Model checking finished, lets open state graph if any.
+						if (event.getModel().hasStateGraphDump()) {
+							try {
+								addOrUpdateStateGraphEditor(event.getModel().getStateGraphDump());
+							} catch (CoreException e) {
+								TLCUIActivator.getDefault().logError("Error initializing editor", e);
+							}
+						}
+
+						if (lastStateCopy.in(State.RUNNING, State.REMOTE_RUNNING)) {
+							final IPreferenceStore ips = TLCUIActivator.getDefault().getPreferenceStore();
+							final boolean eceInItsOwnTab = ips
+									.getBoolean(IModelEditorPreferenceConstants.I_MODEL_EDITOR_SHOW_ECE_AS_TAB);
+
+							if (eceInItsOwnTab && modelIsConfiguredWithNoBehaviorSpec()) {
+								setActivePage(EvaluateConstantExpressionPage.ID);
+							}
+						}
+
+						// MAK 01/2018: Re-validate the page because running the model removes or sets
+						// problem markers (Model#setMarkers) which are presented to the user by
+						// ModelEditor#handleProblemMarkers. If we don't re-validate once a model is
+						// done running, the user visible presentation resulting from an earlier run of
+						// handleProblemMarkers gets stale.
+						// This behavior can be triggered by creating a spec (note commented EXTENDS):
+						// \* EXTENDS Integers
+						// VARIABLE s
+						// Spec == s = 0 /\ [][s'=s]_s
+						// and a model that defines the invariant (s >= 0). Upon the first launch of
+						// the model, the ModelEditor correctly marks the invariant due to the operator
+						// >= being not defined. Uncommenting EXTENDS, saving the spec and rerunning
+						// the model would incorrectly not remove the marker on the invariant.
+						UIHelper.runUISync(validateRunable);
+					}
+				});
+			}
+			
+			lastState = event.getState();
+			
+			return false;
+		}
+	}
 }
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/TLACoverageEditor.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/TLACoverageEditor.java
index f9be7e21ccc63cdfcbbe3ed6997ba1ec1df765c5..c7c3aeb6a6d31cc6e4cf627c83531583df6439a4 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/TLACoverageEditor.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/TLACoverageEditor.java
@@ -93,6 +93,8 @@ import org.lamport.tla.toolbox.tool.tlc.output.data.Representation.Grouping;
 import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
 import org.lamport.tla.toolbox.util.UIHelper;
 
+import util.TLAConstants;
+
 public class TLACoverageEditor extends TLAEditorReadOnly {
 
 	static {
@@ -527,7 +529,7 @@ public class TLACoverageEditor extends TLAEditorReadOnly {
 					editor.getViewer().getTextWidget().notifyListeners(SWT.MouseUp, null);
 					event.doit = false;
 					
-					final String moduleName = getModuleName() + ".tla";
+					final String moduleName = getModuleName() + TLAConstants.Files.TLA_EXTENSION;
 					final TLAEditor editor = EditorUtil.openTLAEditor(moduleName);
 					
 					if (editor != null) {
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/BasicFormPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/BasicFormPage.java
index 1db6b859fcc398e39773fba8491ec26cea8f8aa6..e7b3ae657126bc32460aa4f9d6fe2fc5bdf52ddd 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/BasicFormPage.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/BasicFormPage.java
@@ -163,7 +163,7 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat
             {
                 if (getModel() != null)
                 {
-                    TLCErrorView.updateErrorView(getModel());
+                    TLCErrorView.updateErrorView(getModelEditor());
                 }
             } else
             {
@@ -779,9 +779,9 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat
     }
 
     /**
-     * Subclasses may override this to be notified when model checking has been launched.
+     * Subclasses may override this to be notified when model checking is about to be launched.
      */
-    public void modelCheckingHasBegun() { }
+    public void modelCheckingWillBegin() { }
     
     /**
      * Retrieves the data binding manager
@@ -838,7 +838,7 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat
 
     public void resetMessage(final Object key) {
         getManagedForm().getMessageManager().setAutoUpdate(false);
-        getManagedForm().getMessageManager().removeMessage(key);;
+        getManagedForm().getMessageManager().removeMessage(key);
         // make the run possible
         setComplete(true);
         // make the change visible
@@ -876,9 +876,9 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat
      */
     class RunAction extends Action
     {
-        RunAction()
-        {
-            super("Run", TLCUIActivator.imageDescriptorFromPlugin(TLCUIActivator.PLUGIN_ID, "icons/full/lrun_obj.gif"));
+    	// TODO: HiDPI on this icon as we also have an @2x version
+        RunAction() {
+            super("Run", TLCUIActivator.imageDescriptorFromPlugin(TLCUIActivator.PLUGIN_ID, "icons/full/run_exc.png"));
             this.setDescription("Run TLC");
             this.setToolTipText("Runs TLC on the model.");
         }
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/MainModelPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/MainModelPage.java
index 89e07a28a28be925d1efcd8e4a6b8f1a15804e10..a827be351174b89129d0418020c26fa679601d83 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/MainModelPage.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/MainModelPage.java
@@ -27,10 +27,14 @@ import org.eclipse.jface.resource.JFaceResources;
 import org.eclipse.jface.text.Document;
 import org.eclipse.jface.text.source.SourceViewer;
 import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
 import org.eclipse.jface.viewers.TableViewer;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.CTabFolder;
 import org.eclipse.swt.custom.StackLayout;
+import org.eclipse.swt.custom.StyledText;
 import org.eclipse.swt.events.KeyAdapter;
 import org.eclipse.swt.events.KeyEvent;
 import org.eclipse.swt.events.SelectionEvent;
@@ -62,9 +66,7 @@ import org.eclipse.ui.forms.widgets.TableWrapData;
 import org.eclipse.ui.forms.widgets.TableWrapLayout;
 import org.lamport.tla.toolbox.tool.tlc.launch.IConfigurationConstants;
 import org.lamport.tla.toolbox.tool.tlc.launch.IConfigurationDefaults;
-import org.lamport.tla.toolbox.tool.tlc.model.Assignment;
 import org.lamport.tla.toolbox.tool.tlc.model.Model;
-import org.lamport.tla.toolbox.tool.tlc.model.TypedSet;
 import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.DataBindingManager;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor;
@@ -84,6 +86,8 @@ import org.lamport.tla.toolbox.util.IHelpConstants;
 import org.lamport.tla.toolbox.util.UIHelper;
 
 import tla2sany.semantic.ModuleNode;
+import tlc2.model.Assignment;
+import tlc2.model.TypedSet;
 import util.TLCRuntime;
 
 /**
@@ -103,7 +107,7 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 
 	private static final String TITLE = "Model Overview";
 
-	private static final String INIT_NEXT_COMBO_LABEL = "Initial predicate and next-state";
+	private static final String INIT_NEXT_COMBO_LABEL = "Initial predicate and next-state relation";
 	private static final String TEMPORAL_FORMULA_COMBO_LABEL = "Temporal formula";
 	private static final String NO_SPEC_COMBO_LABEL = "No behavior spec";
 	private static final String[] VARIABLE_BEHAVIOR_COMBO_ITEMS = { INIT_NEXT_COMBO_LABEL, TEMPORAL_FORMULA_COMBO_LABEL,
@@ -191,6 +195,11 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 			getModelEditor().addOrShowAdvancedTLCOptionsPage();
 		}
 	};
+	protected HyperlinkAdapter resultsPageOpener = new HyperlinkAdapter() {
+		public void linkActivated(final HyperlinkEvent he) {
+			getModelEditor().addOrShowResultsPage();
+		}
+	};
 
 	/**
 	 * Stacked composites for displaying options based on user selection in combo
@@ -395,6 +404,34 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 		validatePage(false);
 	}
 	
+	/**
+	 * This switches the behavior combo to be Init-Next behavior and potentially sets the Init and Next values in the
+	 * 	UI text areas.
+	 * 
+	 * @param initFormula if non-null, this will be set into the Init text area
+	 * @param nextFormula if non-null, this will be set into the Next text area
+	 */
+	public void setInitNextBehavior(final String initFormula, final String nextFormula) {
+		boolean setDirty = setSpecSelection(MODEL_BEHAVIOR_TYPE_SPEC_INIT_NEXT);
+		
+		if (initFormula != null) {
+			initFormulaSource.setDocument(new Document(initFormula));
+			setDirty = true;
+		}
+		
+		if (nextFormula != null) {
+			nextFormulaSource.setDocument(new Document(nextFormula));
+			setDirty = true;
+		}
+		
+		if (setDirty) {
+			final DataBindingManager dm = getDataBindingManager();
+			dm.getSection(dm.getSectionForAttribute(MODEL_BEHAVIOR_NO_SPEC)).markDirty();
+			
+			validatePage(false);
+		}
+	}
+	
 	@Override
 	public void validatePage(boolean switchToErrorPage) {
 		if (getManagedForm() == null) {
@@ -479,7 +516,7 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 					TypedSet modelValuesSet = TypedSet.parseSet(constant.getRight());
 
 					if (constant.isSymmetricalSet()) {
-						if (((CheckboxTableViewer) propertiesTable).getCheckedElements().length > 0) {
+						if (hasLivenessProperty()) {
 							modelEditor.addErrorMessage(constant.getLabel(), String.format(
 									"%s declared to be symmetric while one or more temporal formulas are set to be checked.\n"
 											+ "If the temporal formula is a liveness property, liveness checking might fail to find\n"
@@ -643,10 +680,11 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 		// that code changes the selection.
 		final Section whatToCheckSection = dm.getSection(SEC_WHAT_TO_CHECK).getSection();
 		final ResultPage rp = (ResultPage) modelEditor.findPage(ResultPage.ID);
-		final EvaluateConstantExpressionPage ecep = (EvaluateConstantExpressionPage) modelEditor
-				.findPage(EvaluateConstantExpressionPage.ID);
+		final EvaluateConstantExpressionPage ecep
+				= (rp != null) ? (EvaluateConstantExpressionPage) modelEditor.findPage(EvaluateConstantExpressionPage.ID)
+							   : null;
 
-		final Set<Section> resultPageSections = rp.getSections(SEC_GENERAL, SEC_STATISTICS);
+		final Set<Section> resultPageSections = (rp != null) ? rp.getSections(SEC_GENERAL, SEC_STATISTICS) : null;
 
 		final String hint = " (\"What is the behavior spec?\" above has no behavior spec)";
 		final String hintResults = " (\"What is the behavior spec?\" on \"Model Overview\" page has no behavior spec)";
@@ -657,15 +695,18 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 			whatToCheckSection.setExpanded(false);
 			whatToCheckSection.setEnabled(false);
 
-			resultPageSections.forEach((section) -> {
-				section.setText(!section.getText().endsWith(hintResults) ? section.getText() + hintResults : section.getText());
-				section.setEnabled(false);
-				compensateForExpandableCompositesPoorDesign(section, false);
-			});
+			if (resultPageSections != null) {
+				resultPageSections.forEach((section) -> {
+					section.setText(!section.getText().endsWith(hintResults) ? section.getText() + hintResults
+							: section.getText());
+					section.setEnabled(false);
+					compensateForExpandableCompositesPoorDesign(section, false);
+				});
+			}
 			
 			if (ecep != null) {
 				ecep.setNoBehaviorSpecToggleState(true);
-			} else {
+			} else if (rp != null) {
 				rp.setNoBehaviorSpecToggleState(true);
 			}
 		} else {
@@ -673,15 +714,17 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 			whatToCheckSection.setExpanded(true);
 			whatToCheckSection.setEnabled(true);
 
-			resultPageSections.forEach((section) -> {
-				section.setText(section.getText().replace(hintResults, ""));
-				section.setEnabled(true);
-				compensateForExpandableCompositesPoorDesign(section, true);
-			});
+			if (resultPageSections != null) {
+				resultPageSections.forEach((section) -> {
+					section.setText(section.getText().replace(hintResults, ""));
+					section.setEnabled(true);
+					compensateForExpandableCompositesPoorDesign(section, true);
+				});
+			}
 			
 			if (ecep != null) {
 				ecep.setNoBehaviorSpecToggleState(false);
-			} else {
+			} else if (rp != null) {
 				rp.setNoBehaviorSpecToggleState(false);
 			}
 		}
@@ -766,6 +809,10 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 
 		super.validatePage(switchToErrorPage);
 	}
+	
+	public boolean hasLivenessProperty() {
+		return ((CheckboxTableViewer) propertiesTable).getCheckedElements().length > 0;
+	}
 
 	public boolean workerCountCanBeModified() {
 		return workerValueCanBeModified.get();
@@ -837,8 +884,9 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 	 * This method sets the selection on the
 	 * 
 	 * @param selectedFormula
+	 * @return true if the selection changed
 	 */
-	private void setSpecSelection(int specType) {
+	private boolean setSpecSelection(int specType) {
 		int index = -1;
 
 		switch (specType) {
@@ -855,10 +903,14 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 				throw new IllegalArgumentException("Wrong spec type, this is a bug");
 		}
 		
-		if (index != -1) {
+		if ((index != -1) && (index != behaviorCombo.getSelectionIndex())) {
 			behaviorCombo.select(index);
 			moveToTopOfBehaviorOptionsStack(behaviorCombo.getText());
+			
+			return true;
 		}
+		
+		return false;
 	}
 	
 	private int getModelConstantForSpecSelection() {
@@ -977,7 +1029,7 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 		}
 		return constants;
 	}
-
+	
 	/**
 	 * Creates the UI This method is called to create the widgets and arrange them
 	 * on the page
@@ -989,6 +1041,7 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 	 * given in the article
 	 * http://www.eclipse.org/articles/article.php?file=Article-Understanding-Layouts/index.html
 	 */
+	@Override
 	protected void createBodyContent(IManagedForm managedForm) {
 		DataBindingManager dm = getDataBindingManager();
 		int sectionFlags = Section.TITLE_BAR | Section.DESCRIPTION | Section.TREE_NODE;
@@ -1046,19 +1099,19 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 
 		
 
-		Composite advancedLinkLine = new Composite(body, SWT.NONE);
+		Composite linkLineComposite = new Composite(body, SWT.NONE);
 		twd = new TableWrapData();
 		twd.colspan = 2;
 		twd.grabHorizontal = true;
 		twd.align = TableWrapData.RIGHT;
-		advancedLinkLine.setLayoutData(twd);
-		advancedLinkLine.setBackground(body.getDisplay().getSystemColor(SWT.COLOR_WHITE));
+		linkLineComposite.setLayoutData(twd);
+		linkLineComposite.setBackground(body.getDisplay().getSystemColor(SWT.COLOR_WHITE));
 		gl = new GridLayout(1, false);
 		gl.marginWidth = 0;
 		gl.marginRight = 36;
 		gl.horizontalSpacing = 0;
-		advancedLinkLine.setLayout(gl);
-		Hyperlink hyper = toolkit.createHyperlink(advancedLinkLine, "Additional Spec Options", SWT.NONE);
+		linkLineComposite.setLayout(gl);
+		Hyperlink hyper = toolkit.createHyperlink(linkLineComposite, "Additional Spec Options", SWT.NONE);
 		hyper.addHyperlinkListener(advancedModelOptionsOpener);
 		Font baseFont = JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT);
 		FontData[] baseFD = baseFont.getFontData();
@@ -1158,9 +1211,13 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 		gd.horizontalAlignment = SWT.FILL;
 		gd.grabExcessHorizontalSpace = true;
 		gd.heightHint = 48;
-		initFormulaSource.getTextWidget().setLayoutData(gd);
-		initFormulaSource.getTextWidget().addModifyListener(whatIsTheSpecListener);
-		initFormulaSource.getTextWidget().addFocusListener(focusListener);
+		StyledText st = initFormulaSource.getTextWidget();
+		st.setLayoutData(gd);
+		st.addModifyListener(whatIsTheSpecListener);
+		st.addFocusListener(focusListener);
+		st.addTraverseListener((event) -> {
+			event.doit = true;
+		});
 		dm.bindAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT, initFormulaSource, behaviorPart);
 
 		// next
@@ -1171,9 +1228,13 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 		gd.horizontalAlignment = SWT.FILL;
 		gd.grabExcessHorizontalSpace = true;
 		gd.heightHint = 48;
-		nextFormulaSource.getTextWidget().setLayoutData(gd);
-		nextFormulaSource.getTextWidget().addModifyListener(whatIsTheSpecListener);
-		nextFormulaSource.getTextWidget().addFocusListener(focusListener);
+		st = nextFormulaSource.getTextWidget();
+		st.setLayoutData(gd);
+		st.addModifyListener(whatIsTheSpecListener);
+		st.addFocusListener(focusListener);
+		st.addTraverseListener((event) -> {
+			event.doit = true;
+		});
 		dm.bindAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT, nextFormulaSource, behaviorPart);
 
 		// fairness
@@ -1261,19 +1322,19 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 		dm.bindAttribute(MODEL_PARAMETER_CONSTANTS, constantTable, constantsPart);
 		
 
-		advancedLinkLine = new Composite(body, SWT.NONE);
+		linkLineComposite = new Composite(body, SWT.NONE);
 		twd = new TableWrapData();
 		twd.colspan = 2;
 		twd.grabHorizontal = true;
 		twd.align = TableWrapData.RIGHT;
-		advancedLinkLine.setLayoutData(twd);
-		advancedLinkLine.setBackground(body.getDisplay().getSystemColor(SWT.COLOR_WHITE));
+		linkLineComposite.setLayoutData(twd);
+		linkLineComposite.setBackground(body.getDisplay().getSystemColor(SWT.COLOR_WHITE));
 		gl = new GridLayout(1, false);
 		gl.marginWidth = 0;
 		gl.marginRight = 36;
 		gl.horizontalSpacing = 0;
-		advancedLinkLine.setLayout(gl);
-		hyper = toolkit.createHyperlink(advancedLinkLine, "Additional TLC Options", SWT.NONE);
+		linkLineComposite.setLayout(gl);
+		hyper = toolkit.createHyperlink(linkLineComposite, "Additional TLC Options", SWT.NONE);
 		hyper.addHyperlinkListener(advancedTLCOptionsOpener);
 		hyper.setFont(biggerLinkFont);
 
@@ -1370,17 +1431,17 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 		gd.horizontalAlignment = SWT.CENTER;
 		tlcResourceSummaryLabel.setLayoutData(gd);
 
-		advancedLinkLine = new Composite(howToRunArea, SWT.NONE);
+		linkLineComposite = new Composite(howToRunArea, SWT.NONE);
 		gd = new GridData();
 		gd.horizontalSpan = 2;
 		gd.grabExcessHorizontalSpace = true;
 		gd.horizontalAlignment = SWT.CENTER;
-		advancedLinkLine.setLayoutData(gd);
+		linkLineComposite.setLayoutData(gd);
 		gl = new GridLayout(1, false);
 		gl.marginWidth = 0;
 		gl.horizontalSpacing = 0;
-		advancedLinkLine.setLayout(gl);
-		tlcTuneHyperlink = toolkit.createHyperlink(advancedLinkLine, "Tune these parameters and set defaults", SWT.NONE);
+		linkLineComposite.setLayout(gl);
+		tlcTuneHyperlink = toolkit.createHyperlink(linkLineComposite, "Tune these parameters and set defaults", SWT.NONE);
 		tlcTuneHyperlink.addHyperlinkListener(advancedTLCOptionsOpener);
 		baseFont = JFaceResources.getFont(JFaceResources.DIALOG_FONT);
 		baseFD = baseFont.getFontData();
@@ -1609,12 +1670,45 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta
 
 		distributedOptions.setData(CLOUD_CONFIGURATION_KEY, jcloudsOptions);
 
+	
+		linkLineComposite = new Composite(body, SWT.NONE);
+		twd = new TableWrapData();
+		twd.colspan = 2;
+		twd.grabHorizontal = true;
+		twd.align = TableWrapData.RIGHT;
+		linkLineComposite.setLayoutData(twd);
+		linkLineComposite.setBackground(body.getDisplay().getSystemColor(SWT.COLOR_WHITE));
+		gl = new GridLayout(1, false);
+		gl.marginWidth = 0;
+		gl.marginRight = 36;
+		gl.horizontalSpacing = 0;
+		linkLineComposite.setLayout(gl);
+		hyper = toolkit.createHyperlink(linkLineComposite, "Evaluate Constant Expressions", SWT.NONE);
+		hyper.addHyperlinkListener(resultsPageOpener);
+		hyper.setFont(biggerLinkFont);
+		
+		
 		// add listeners propagating the changes of the elements to the changes
 		// of the parts to the list to be activated after the values has been loaded
 		dirtyPartListeners.add(commentsListener);
 		dirtyPartListeners.add(whatIsTheSpecListener);
 		dirtyPartListeners.add(whatToCheckListener);
 		dirtyPartListeners.add(howToRunListener);
+		
+		// add an empty ISelectionProvider; the default selection provider results in an infinite loop if the site
+		//		never gets another one set.
+		getSite().setSelectionProvider(new ISelectionProvider() {
+			@Override
+			public void addSelectionChangedListener(final ISelectionChangedListener listener) { }
+			@Override
+			public ISelection getSelection() {
+				return null;
+			}
+			@Override
+			public void removeSelectionChangedListener(final ISelectionChangedListener listener) { }
+			@Override
+			public void setSelection(final ISelection selection) { }
+		});
 	}
 
 	private void moveToTopOfDistributedOptionsStack(final String id, final boolean enableWorker,
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/advanced/AdvancedModelPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/advanced/AdvancedModelPage.java
index 61b10e5defeb1dd91e7bc9a307928b0ddebaae21..47e0e255d3c1a3b541c64cbb5d9bdb8c64926799 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/advanced/AdvancedModelPage.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/advanced/AdvancedModelPage.java
@@ -27,11 +27,10 @@ import org.eclipse.ui.forms.widgets.TableWrapData;
 import org.eclipse.ui.forms.widgets.TableWrapLayout;
 import org.lamport.tla.toolbox.tool.ToolboxHandle;
 import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants;
-import org.lamport.tla.toolbox.tool.tlc.model.Assignment;
-import org.lamport.tla.toolbox.tool.tlc.model.TypedSet;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.DataBindingManager;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.BasicFormPage;
+import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.MainModelPage;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.part.ValidateableOverridesSectionPart;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.part.ValidateableSectionPart;
 import org.lamport.tla.toolbox.tool.tlc.ui.util.DirtyMarkingListener;
@@ -42,6 +41,8 @@ import org.lamport.tla.toolbox.util.UIHelper;
 
 import tla2sany.modanalyzer.SpecObj;
 import tla2sany.semantic.OpDefNode;
+import tlc2.model.Assignment;
+import tlc2.model.TypedSet;
 
 /**
  * Where we are sticking "advanced" model options, not including those related to TLC execution.
@@ -287,6 +288,26 @@ public class AdvancedModelPage extends BasicFormPage implements Closeable {
                 }
             }
         }
+        
+		final MainModelPage mmp = (MainModelPage) getModelEditor().getFormPage(MainModelPage.ID);
+		if (mmp.hasLivenessProperty()) {
+			if (!FormHelper.trimTrailingSpaces(constraintSource.getDocument().get()).isEmpty()) {
+				modelEditor.addErrorMessage("constraintSource", "Declaring state constraints during liveness checking is dangerous: "
+								+ "Please read\nsection 14.3.5 on page 247 of Specifying Systems (https://lamport.azurewebsites.net/tla/book.html)"
+								+ "\nand the optionally discussion at https://discuss.tlapl.us/msg00994.html for more details.",
+						this.getId(), IMessageProvider.INFORMATION,
+						UIHelper.getWidget(dm.getAttributeControl(MODEL_PARAMETER_CONSTRAINT)));
+				expandSection(dm.getSectionForAttribute(MODEL_PARAMETER_CONSTRAINT));
+			}
+			if (!FormHelper.trimTrailingSpaces(actionConstraintSource.getDocument().get()).isEmpty()) {
+				modelEditor.addErrorMessage("actionConstraintSource", "Declaring action constraints during liveness checking is dangerous: "
+						+ "Please read\nsection 14.3.5 on page 247 of Specifying Systems (https://lamport.azurewebsites.net/tla/book.html)"
+						+ "\nand optionally the discussion at https://discuss.tlapl.us/msg00994.html for more details.",
+					this.getId(), IMessageProvider.INFORMATION,
+						UIHelper.getWidget(dm.getAttributeControl(MODEL_PARAMETER_ACTION_CONSTRAINT)));
+				expandSection(dm.getSectionForAttribute(MODEL_PARAMETER_ACTION_CONSTRAINT));
+			}
+		}
 
         mm.setAutoUpdate(true);
         
@@ -486,5 +507,12 @@ public class AdvancedModelPage extends BasicFormPage implements Closeable {
 	public void close() throws IOException {
 		final int openTabState = getModel().getOpenTabsValue();
 		getModelEditor().updateOpenTabsState(openTabState & ~IModelConfigurationConstants.EDITOR_OPEN_TAB_ADVANCED_MODEL);
+		
+        final DataBindingManager dm = getDataBindingManager();
+        dm.unbindSectionAndAttribute(MODEL_PARAMETER_ACTION_CONSTRAINT);
+        dm.unbindSectionAndAttribute(MODEL_PARAMETER_CONSTRAINT);
+        dm.unbindSectionAndAttribute(MODEL_PARAMETER_DEFINITIONS);
+        dm.unbindSectionAndAttribute(MODEL_PARAMETER_MODEL_VALUES);
+        dm.unbindSectionAndAttribute(MODEL_PARAMETER_NEW_DEFINITIONS);
 	}
 }
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/advanced/AdvancedTLCOptionsPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/advanced/AdvancedTLCOptionsPage.java
index 9373cfc697a771d5a6273dad578a6ecde4c56407..56a490719366b9e8a94fbe06cc60043ba4c69ff2 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/advanced/AdvancedTLCOptionsPage.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/advanced/AdvancedTLCOptionsPage.java
@@ -45,7 +45,7 @@ import org.eclipse.ui.forms.widgets.TableWrapData;
 import org.eclipse.ui.forms.widgets.TableWrapLayout;
 import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants;
 import org.lamport.tla.toolbox.tool.tlc.model.Model;
-import org.lamport.tla.toolbox.tool.tlc.model.Model.Coverage;
+import org.lamport.tla.toolbox.tool.tlc.model.ModelCoverage;
 import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.DataBindingManager;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor;
@@ -628,8 +628,8 @@ public class AdvancedTLCOptionsPage extends BasicFormPage implements Closeable {
         m_collectCoverageCombo.setLabelProvider(new LabelProvider() {
 			@Override
 			public String getText(Object element) {
-				if (element instanceof Coverage) {
-					switch ((Coverage) element) {
+				if (element instanceof ModelCoverage) {
+					switch ((ModelCoverage) element) {
 					case OFF:
 						return "Off";
 					case ACTION:
@@ -641,7 +641,7 @@ public class AdvancedTLCOptionsPage extends BasicFormPage implements Closeable {
 				return "Off"; // make compiler happy 
 			}
         });
-        m_collectCoverageCombo.setInput(Model.Coverage.values());
+        m_collectCoverageCombo.setInput(ModelCoverage.values());
         
         
         b = HelpButton.helpButton(coverageComposite, "model/tlc-options-page.html#profiling") ;
@@ -986,8 +986,8 @@ public class AdvancedTLCOptionsPage extends BasicFormPage implements Closeable {
 
         // Collect Coverage
 		final Object coverage = m_collectCoverageCombo.getStructuredSelection().getFirstElement();
-		if (coverage instanceof Coverage) {
-			model.setCoverage((Coverage) coverage);
+		if (coverage instanceof ModelCoverage) {
+			model.setCoverage((ModelCoverage) coverage);
 		}
        
         // view
@@ -1281,9 +1281,11 @@ public class AdvancedTLCOptionsPage extends BasicFormPage implements Closeable {
     
 	public void setWorkerAndMemoryEnable(final boolean enableWorker, final boolean enableMaxHeap) {
     	workers.getDisplay().asyncExec(() -> {
-    		saveDefaultConfigurationButton.setEnabled(enableWorker);
-    		workers.setEnabled(enableWorker);
-    		maxHeapSize.setEnabled(enableMaxHeap);
+			if (!saveDefaultConfigurationButton.isDisposed()) {
+				saveDefaultConfigurationButton.setEnabled(enableWorker);
+				workers.setEnabled(enableWorker);
+				maxHeapSize.setEnabled(enableMaxHeap);
+			}
     	});
     }
 
@@ -1309,6 +1311,12 @@ public class AdvancedTLCOptionsPage extends BasicFormPage implements Closeable {
 	public void close() throws IOException {
 		final int openTabState = getModel().getOpenTabsValue();
 		getModelEditor().updateOpenTabsState(openTabState & ~IModelConfigurationConstants.EDITOR_OPEN_TAB_ADVANCED_TLC);
+
+		final DataBindingManager dm = getDataBindingManager();
+		dm.unbindSectionAndAttribute(LAUNCH_MAX_HEAP_SIZE);
+		dm.unbindSectionAndAttribute(LAUNCH_NUMBER_OF_WORKERS);
+		dm.unbindSectionAndAttribute(LAUNCH_RECOVER);
+		dm.unbindSectionAndAttribute(MODEL_PARAMETER_VIEW);
 	}
     
     private String generateMemoryDisplayText () {
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/CoverageLabelProvider.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/CoverageLabelProvider.java
index 0f159e746666bdf54c8d2f66475ab3abc4e34841..f96e386ae6d2f2ada65ab54cb88690d63a2edf1c 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/CoverageLabelProvider.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/CoverageLabelProvider.java
@@ -2,13 +2,16 @@ package org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results;
 
 import java.util.Comparator;
 
+import org.eclipse.core.runtime.Platform;
 import org.eclipse.jface.layout.TableColumnLayout;
 import org.eclipse.jface.viewers.ColumnWeightData;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.TableColumn;
+import org.lamport.tla.toolbox.editor.basic.TLAEditorActivator;
 import org.lamport.tla.toolbox.tool.tlc.output.data.ActionInformationItem;
 import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
 import org.lamport.tla.toolbox.tool.tlc.ui.util.AbstractTableLabelProvider;
@@ -32,7 +35,11 @@ class CoverageLabelProvider extends AbstractTableLabelProvider {
 
     static final String TOOLTIP = "Click on a row to go to action.";
     
+    private static final boolean RUNNING_WINDOWS = Platform.getOS().equals(Platform.OS_WIN32);
 	private static final String[] COLUMN_TITLES = new String[] { "Module", "Action", "Location", "States Found", "Distinct States"  };
+	private static final String[] COLUMN_TOOLTIPS = new String[] { TOOLTIP, TOOLTIP, TOOLTIP,
+			"\u03A3 of this column equals (total) States Found on the State Space progress table to the left.",
+			"\u03A3 of this column equals (total) Distinct States on the State Space progress table to the left." };
     private static final int[] COLUMN_WIDTHS;
     private static final Comparator<ActionInformationItem>[] COLUMN_COMP;
 	private static final double[] COLUMN_WIDTH_PERCENTAGES;
@@ -107,7 +114,7 @@ class CoverageLabelProvider extends AbstractTableLabelProvider {
 			final TableColumn column = new TableColumn(stateTable, SWT.NULL);
 			column.setWidth(COLUMN_WIDTHS[i]);
 			column.setText(COLUMN_TITLES[i]);
-			column.setToolTipText(TOOLTIP);
+			column.setToolTipText(COLUMN_TOOLTIPS[i]);
 			column.setData(COVERAGE_COMPARATOR, COLUMN_COMP[i]);
 
 			final int weight = (int)(100.0 * COLUMN_WIDTH_PERCENTAGES[i]);
@@ -154,13 +161,20 @@ class CoverageLabelProvider extends AbstractTableLabelProvider {
 	}
 
 	public Color getForeground(final Object element, final int columnIndex) {
+		if (TLAEditorActivator.getDefault().isCurrentThemeDark() && (element instanceof ActionInformationItem)
+				&& !RUNNING_WINDOWS) {	// RUNNING_WINDOWS check due to https://github.com/tlaplus/tlaplus/issues/341
+			final ActionInformationItem aii = (ActionInformationItem) element;
+			if ((aii.getCount() == 0) && (aii.getUnseen() == 0)) {
+				return Display.getCurrent().getSystemColor(SWT.COLOR_BLACK);
+			}
+		}
 		return null; // Use default color
 	}
 
 	public Color getBackground(final Object element, final int columnIndex) {
 		if (element instanceof ActionInformationItem) {
 			final ActionInformationItem aii = (ActionInformationItem) element;
-			if (aii.getCount() == 0 && aii.getUnseen() == 0) {
+			if ((aii.getCount() == 0) && (aii.getUnseen() == 0)) {
 				return TLCUIActivator.getColor(SWT.COLOR_YELLOW);
 			}
 		}
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/EvaluateConstantExpressionPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/EvaluateConstantExpressionPage.java
index e6eee6e65dcc9150452aa999c8f30f769b65cc1f..ff4d3ef7514e8c71bd00d2cf153ba67546a9f455 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/EvaluateConstantExpressionPage.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/EvaluateConstantExpressionPage.java
@@ -301,6 +301,7 @@ public class EvaluateConstantExpressionPage extends BasicFormPage implements ITL
 
 			managedForm.removePart(m_validateableCalculatorSection);
 
+			getDataBindingManager().unbindSectionAndAttribute(SEC_EXPRESSION);
 			getDataBindingManager().unbindSectionFromPage(SEC_EXPRESSION, getId());
 
 			final Model model = getModel();
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/ResultPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/ResultPage.java
index 084497ae2d4943423bedb8a6baa8c357905fbb58..2ab1cc019c6acde888d877c51da8c1f34ac4d796 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/ResultPage.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/results/ResultPage.java
@@ -1,9 +1,12 @@
 package org.lamport.tla.toolbox.tool.tlc.ui.editor.page.results;
 
+import java.io.Closeable;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
@@ -24,6 +27,7 @@ import java.util.stream.Collectors;
 import org.apache.commons.lang3.time.DurationFormatUtils;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IWorkspace;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.resources.WorkspaceJob;
@@ -82,42 +86,48 @@ import org.lamport.tla.toolbox.editor.basic.TLAFastPartitioner;
 import org.lamport.tla.toolbox.editor.basic.TLAPartitionScanner;
 import org.lamport.tla.toolbox.spec.Module;
 import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants;
-import org.lamport.tla.toolbox.tool.tlc.model.Assignment;
 import org.lamport.tla.toolbox.tool.tlc.model.Model;
+import org.lamport.tla.toolbox.tool.tlc.model.ModelCoverage;
 import org.lamport.tla.toolbox.tool.tlc.output.data.ActionInformationItem;
 import org.lamport.tla.toolbox.tool.tlc.output.data.CoverageInformation;
 import org.lamport.tla.toolbox.tool.tlc.output.data.CoverageInformationItem;
 import org.lamport.tla.toolbox.tool.tlc.output.data.CoverageUINotification;
 import org.lamport.tla.toolbox.tool.tlc.output.data.ITLCModelLaunchDataPresenter;
 import org.lamport.tla.toolbox.tool.tlc.output.data.StateSpaceInformationItem;
+import org.lamport.tla.toolbox.tool.tlc.output.data.TLCError;
 import org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider;
 import org.lamport.tla.toolbox.tool.tlc.output.source.TLCOutputSourceRegistry;
 import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
 import org.lamport.tla.toolbox.tool.tlc.ui.contribution.DynamicContributionItem;
+import org.lamport.tla.toolbox.tool.tlc.ui.editor.DataBindingManager;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.ISectionConstants;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.TLACoverageEditor;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.BasicFormPage;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.ErrorMessage;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.MainModelPage;
+import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.advanced.AdvancedModelPage;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.advanced.AdvancedTLCOptionsPage;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.part.ValidateableSectionPart;
+import org.lamport.tla.toolbox.tool.tlc.ui.editor.preference.IModelEditorPreferenceConstants;
 import org.lamport.tla.toolbox.tool.tlc.ui.preference.ITLCPreferenceConstants;
-import org.lamport.tla.toolbox.tool.tlc.ui.util.RecordToSourceCoupler;
 import org.lamport.tla.toolbox.tool.tlc.ui.util.DirtyMarkingListener;
 import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper;
+import org.lamport.tla.toolbox.tool.tlc.ui.util.RecordToSourceCoupler;
 import org.lamport.tla.toolbox.tool.tlc.ui.view.TLCErrorView;
 import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper;
 import org.lamport.tla.toolbox.util.FontPreferenceChangeListener;
 import org.lamport.tla.toolbox.util.IHelpConstants;
 import org.lamport.tla.toolbox.util.UIHelper;
 
+import tlc2.model.Assignment;
+
 /**
  * A page to display results of model checking.
  * @author Simon Zambrovski
  */
 @SuppressWarnings("restriction")
-public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPresenter {
+public class ResultPage extends BasicFormPage implements Closeable, ITLCModelLaunchDataPresenter {
 	public static final String RESULT_PAGE_PROBLEM = "ResultPageProblem";
 
     public static final String ID = "resultPage";
@@ -137,7 +147,6 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
 
 	private static final Color ERROR_PANE_BACKGROUND = new Color(PlatformUI.getWorkbench().getDisplay(), 255, 241, 237);
 	private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("HH:mm:ss '('MMM d')'");
-	private static final String ZERO_COVERAGE_WARNING = "Disabled actions for one or more modules.";
 	
 	
     /**
@@ -146,27 +155,26 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
     private SourceViewer userOutput;
     private SourceViewer progressOutput;
     
-    private Composite m_calculatorSection;
+    private Composite calculatorSection;
     private SourceViewer expressionEvalResult;
     private SourceViewer expressionEvalInput;
-	private ValidateableSectionPart m_validateableCalculatorSection;
-	private Button m_noBehaviorModeToggleButton;
-
-	private Section m_generalSection;
-	private int m_collapsedSectionHeight = 20;		// We should be able to calculate this before we need; this is the 'just in case' value
-	private long m_startTimestamp;
-    private Composite m_generalTopPane;
-    private Label m_startLabel;
-    private Label m_lastCheckpointLabel;
-    private Label m_finishLabel;
-    private Label m_tlcSimulationLabel;    
-    private Label m_tlcSearchModeLabel;
-    private Label m_tlcStatusLabel;
-
-    private Composite m_generalErrorPane;
-    private Hyperlink m_errorStatusHyperLink;
-    private Label m_fingerprintCollisionLabel;
-    private Label m_zeroCoverageLabel;
+	private ValidateableSectionPart validateableCalculatorSection;
+	private Button noBehaviorModeToggleButton;
+
+	private Section generalSection;
+	private int collapsedSectionHeight = 20;		// We should be able to calculate this before we need; this is the 'just in case' value
+	private long startTimestamp;
+    private Composite generalTopPane;
+    private Label startLabel;
+    private Label lastCheckpointLabel;
+    private Label finishLabel;
+    private Label tlcSimulationLabel;    
+    private Label tlcSearchModeLabel;
+    private Label tlcStatusLabel;
+
+    private Composite generalErrorPane;
+    private Hyperlink errorStatusHyperLink;
+    private Label fingerprintCollisionLabel;
 
     private Text coverageTimestampText;
     private TableViewer coverage;
@@ -179,22 +187,21 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
 
     // hyper link listener activated in case of errors
     private final IHyperlinkListener m_errorHyperLinkListener = new HyperlinkAdapter() {
-        public void linkActivated(HyperlinkEvent e)
-        {
-            if (getModel() != null)
-            {
-            	getModel().setOriginalTraceShown(true);
-                TLCErrorView.updateErrorView(getModel());
-            }
-        }
+		public void linkActivated(final HyperlinkEvent e) {
+			if (getModel() != null) {
+				getModel().setOriginalTraceShown(true);
+				TLCErrorView.updateErrorView(getModelEditor());
+			}
+		}
     };
 
 	private IMarker incompleteStateExploration;
-	private IMarker zeroCoverage;
 	
-	private final INotificationService ns;
+	private final INotificationService notificationService;
+	
+	private final ErrorPaneViewState errorPaneViewState;
 	
-	private final ErrorPaneViewState m_errorPaneViewState;
+	private final ArrayList<String> markedErrorMessages;
 
     /**
      * Constructor for the page
@@ -202,293 +209,326 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
      */
 	public ResultPage(final FormEditor editor) {
         super(editor, ID, "Model Checking Results", "icons/full/results_page_" + IMAGE_TEMPLATE_TOKEN + ".png");
-        this.helpId = IHelpConstants.RESULT_MODEL_PAGE;
+        helpId = IHelpConstants.RESULT_MODEL_PAGE;
         
-        this.ns = NotificationsUi.getService();
+        notificationService = NotificationsUi.getService();
         
-        m_errorPaneViewState = new ErrorPaneViewState();
+        errorPaneViewState = new ErrorPaneViewState();
+        markedErrorMessages = new ArrayList<>();
     }
 
 	@Override
-    public void modelCheckingHasBegun() {
-		m_errorPaneViewState.clearState();
-		PlatformUI.getWorkbench().getDisplay().asyncExec(() -> {
-    		m_tlcStatusLabel.setText("Starting...");
-			m_errorStatusHyperLink.setVisible(m_errorPaneViewState.errorLinkIsDisplayed());
-			m_fingerprintCollisionLabel.setVisible(m_errorPaneViewState.fingerprintIsDisplayed());
-			m_zeroCoverageLabel.setVisible(m_errorPaneViewState.zeroCountIsDisplayed());
-			setErrorPaneVisible(m_errorPaneViewState.shouldDisplay());
+    public void modelCheckingWillBegin() {
+		errorPaneViewState.clearState();
+		markedErrorMessages.clear();
+		getManagedForm().getMessageManager().removeAllMessages();
+		PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
+			if (!tlcStatusLabel.isDisposed()) {
+	    		tlcStatusLabel.setText("Starting...");
+				errorStatusHyperLink.setVisible(errorPaneViewState.errorLinkIsDisplayed());
+				fingerprintCollisionLabel.setVisible(errorPaneViewState.fingerprintIsDisplayed());
+				setErrorPaneVisible(errorPaneViewState.shouldDisplay());
+			}
 		});
 	}
 
     /**
      * Will be called by the provider on data changes
      */
+	@Override
 	public void modelChanged(final TLCModelLaunchDataProvider dataProvider, final int fieldId) {
-        UIHelper.runUIAsync(() -> {
+		UIHelper.runUIAsync(() -> {
 			// Acquire dispose lock prior to widget access. Using a single
 			// lock just to serialize dispose and modelChange seems
 			// overkill, but the wait-for graph becomes tricky with all the
 			// background jobs going on (at least too tricky to get it
 			// solved within an hour).
-        	disposeLock.lock();
-        	try {
-            	if (getPartControl().isDisposed()) {
-        			// Don't update the widgets if the underlying SWT control has
-        			// already been disposed. Otherwise it results in an
-        			// "SWTException: Widget is disposed".
-            		return;
-            	}
+			disposeLock.lock();
+			try {
+				if (getPartControl().isDisposed()) {
+					// Don't update the widgets if the underlying SWT control has
+					// already been disposed. Otherwise it results in an
+					// "SWTException: Widget is disposed".
+					return;
+				}
 				switch (fieldId) {
-                case USER_OUTPUT:
-                    userOutput.setDocument(dataProvider.getUserOutput());
-                    break;
-                case PROGRESS_OUTPUT:
-                    progressOutput.setDocument(dataProvider.getProgressOutput());
-                    break;
-                case CONST_EXPR_EVAL_OUTPUT:
-                	if (expressionEvalResult != null) {
-                		expressionEvalResult.getTextWidget().setText(dataProvider.getCalcOutput());
-                	}
-                    break;
-                case START_TIME:
-                	setStartTime(dataProvider.getStartTimestamp());
-                    break;
-                case END_TIME:
-                	setEndTime(dataProvider.getFinishTimestamp());
-                    
-                	final long delta = dataProvider.getFinishTimestamp() - dataProvider.getStartTimestamp();
-                	final String duration = DurationFormatUtils.formatDuration(delta, "HH'hrs' mm'mins' ss'sec'");
-                	m_startLabel.setToolTipText(duration);
-                	m_finishLabel.setToolTipText(duration);
-                    break;
-                case TLC_MODE:
-                	setSearchMode(dataProvider.getTLCMode());
-                	
-                	final IFormPage iep = getEditor().findPage(AdvancedTLCOptionsPage.ID);
-                	if (iep != null) {
-                		((AdvancedTLCOptionsPage)iep).setFpIndex(dataProvider.getFPIndex());
-                	} else {
-                		// The tab isn't open so set the value into the model and the tab, should it open, will
-                		//		load it out of the model.
-                		getModel().setAttribute(LAUNCH_FP_INDEX, dataProvider.getFPIndex());
-                		getModelEditor().saveModel();
-                	}
-                case LAST_CHECKPOINT_TIME:
-                	setCheckpoint(dataProvider.getLastCheckpointTimeStamp());
-                   	break;
-                case CURRENT_STATUS:
-                	m_tlcStatusLabel.setText(dataProvider.getCurrentStatus());
-                	m_generalTopPane.layout(true, true);
-                    break;
-                case FINGERPRINT_COLLISION_PROBABILITY:
-                	final String collisionText = dataProvider.getFingerprintCollisionProbability().trim();
-                	
-                	if (collisionText.length() == 0) {
-						m_fingerprintCollisionLabel.setVisible(false);
-						m_errorPaneViewState.setFingerprintDisplay(false);
-						setErrorPaneVisible(m_errorPaneViewState.shouldDisplay());
-                	} else {
-						m_fingerprintCollisionLabel.setText("Fingerprint collision probability: " + collisionText);
-						m_fingerprintCollisionLabel.setVisible(true);
-						m_errorPaneViewState.setFingerprintDisplay(true);
-						setErrorPaneVisible(true);
-                	}
-                    break;
-                case COVERAGE_TIME:
-					final String coverageTimestamp = dataProvider.getCoverageTimestamp();
-					if ("".equals(coverageTimestamp)) {
-						// Reset
-						ResultPage.this.coverageTimestampText.setText("");
-					} else {
-						// Print statistics timestamp relative to TLC startup.
-						final Date date = TLCModelLaunchDataProvider.parseDate(coverageTimestamp);
-						final String interval = TLCModelLaunchDataProvider.formatInterval(getStartTimestamp(), date.getTime());
-						ResultPage.this.coverageTimestampText.setText(interval);
-					}
-                    break;
-                case COVERAGE:
-                	final CoverageInformation coverageInfo = dataProvider.getCoverageInfo();
-                	coverage.setInput(coverageInfo);
-					if (dataProvider.isDone() && !coverageInfo.isEmpty()) {
-// mku: uncomment the following line; run Dijkstra with no zero coverage; then with zero coverage; then no zero coverage
-//Logger.getAnonymousLogger().severe("COVERAGE - dp hasZeroCoverage? " + dataProvider.hasZeroCoverage());
-						if (dataProvider.hasZeroCoverage()) {
-							if (zeroCoverage == null) {
-								final Hashtable<String, Object> marker = ModelHelper.createMarkerDescription(
-										ZERO_COVERAGE_WARNING, IMarker.SEVERITY_WARNING);
-								marker.put(ModelHelper.TLC_MODEL_ERROR_MARKER_ATTRIBUTE_PAGE, 2);
-								zeroCoverage = getModel().setMarker(marker, ModelHelper.TLC_MODEL_ERROR_MARKER_TLC);
+					case USER_OUTPUT:
+						userOutput.setDocument(dataProvider.getUserOutput());
+						break;
+					case PROGRESS_OUTPUT:
+						progressOutput.setDocument(dataProvider.getProgressOutput());
+						break;
+					case CONST_EXPR_EVAL_OUTPUT:
+						if (expressionEvalResult != null) {
+							expressionEvalResult.getTextWidget().setText(dataProvider.getCalcOutput());
+						}
+						break;
+					case START_TIME:
+						setStartTime(dataProvider.getStartTimestamp());
+						break;
+					case END_TIME:
+						setEndTime(dataProvider.getFinishTimestamp());
+
+						final long delta = dataProvider.getFinishTimestamp() - dataProvider.getStartTimestamp();
+						final String duration = DurationFormatUtils.formatDuration(delta, "HH'hrs' mm'mins' ss'sec'");
+						startLabel.setToolTipText(duration);
+						finishLabel.setToolTipText(duration);
+						break;
+					case TLC_MODE:
+						setSearchMode(dataProvider.getTLCMode());
+
+						final IFormPage iep = getEditor().findPage(AdvancedTLCOptionsPage.ID);
+						if (iep != null) {
+							((AdvancedTLCOptionsPage) iep).setFpIndex(dataProvider.getFPIndex());
+						} else {
+							// The tab isn't open so set the value into the model and the tab, should it
+							// open, will
+							// load it out of the model.
+							getModel().setAttribute(LAUNCH_FP_INDEX, dataProvider.getFPIndex());
+							getModelEditor().saveModel();
+						}
+					case LAST_CHECKPOINT_TIME:
+						setCheckpoint(dataProvider.getLastCheckpointTimeStamp());
+						break;
+					case CURRENT_STATUS:
+						tlcStatusLabel.setText(dataProvider.getCurrentStatus());
+						generalTopPane.layout(true, true);
+						break;
+					case FINGERPRINT_COLLISION_PROBABILITY:
+						final String collisionText = dataProvider.getFingerprintCollisionProbability().trim();
+
+						if (collisionText.length() == 0) {
+							fingerprintCollisionLabel.setVisible(false);
+							errorPaneViewState.setFingerprintDisplay(false);
+							setErrorPaneVisible(errorPaneViewState.shouldDisplay());
+						} else {
+							fingerprintCollisionLabel.setText("Fingerprint collision probability: " + collisionText);
+							fingerprintCollisionLabel.setVisible(true);
+							errorPaneViewState.setFingerprintDisplay(true);
+							setErrorPaneVisible(true);
+						}
+						break;
+					case COVERAGE_TIME:
+						final String coverageTimestamp = dataProvider.getCoverageTimestamp();
+						if ("".equals(coverageTimestamp)) {
+							// Reset
+							coverageTimestampText.setText("");
+						} else {
+							// Print statistics timestamp relative to TLC startup.
+							final Date date = TLCModelLaunchDataProvider.parseDate(coverageTimestamp);
+							final String interval = TLCModelLaunchDataProvider.formatInterval(getStartTimestamp(),
+									date.getTime());
+							coverageTimestampText.setText(String.format("(at %s)", interval));
+							coverageTimestampText.setToolTipText(
+									"Time indicates the execution time at which the numbers were recorded");
+						}
+						break;
+					case COVERAGE:
+						final CoverageInformation coverageInfo = dataProvider.getCoverageInfo();
+						coverage.setInput(coverageInfo);
+						break;
+					case COVERAGE_END_OVERHEAD:
+						notificationService.notify(Collections.singletonList(new CoverageUINotification(getModelEditor())));
+						// Continue with COVERAGE_END...
+					case COVERAGE_END:
+						final CoverageInformation ci = dataProvider.getCoverageInfo();
+						if (ci.isEmpty() || ci.isLegacy()) {
+							// Cannot show coverage information without (non-legacy) coverage data.
+							break;
+						}
+						
+						// Delete all zero coverage markers because they might have become obsolete
+						// since the last reporting..
+						// Consider this spec:
+						// ----
+						// Init == x = 1
+						// A == x' = x + 1
+						// B == TLCGet("duration") > 90 /\ x' = x
+						// Spec == Init /\ [][A \/ B]_x
+						// ----
+						// With -coverage set to 1 (every  60 secs), the first coverage reporting
+						// marks action B as disabled. However, in subsequent reportings, B is enabled.
+						try {
+							List<Module> modules = getModel().getSpec().getModules();
+							for (Module module : modules) {
+								module.getResource().deleteMarkers(ModelEditor.ZERO_COVERAGE_ACTION_MARKER, false,
+										IResource.DEPTH_ZERO);
 							}
-							if (coverageInfo.hasDisabledSpecActions()) {
-								m_zeroCoverageLabel.setVisible(true);
-								m_errorPaneViewState.setZeroCountDisplay(true);
-								setErrorPaneVisible(true);
+						} catch (CoreException e) {
+							TLCUIActivator.getDefault().logError(e.getMessage(), e);
+						}
+
+						final List<ActionInformationItem> zeroCoverageInformation = ci.getDisabledSpecActions();
+						for (ActionInformationItem item : zeroCoverageInformation) {
+							final Module m = getModel().getSpec().getModule(item.getModule());
+							if (m == null) {
+								// With the Toolbox better be safe than sorry.
+								continue;
 							}
-						} else if (zeroCoverage != null) {
 							try {
-								zeroCoverage.delete();
-								resetMessage(RESULT_PAGE_PROBLEM);
-								zeroCoverage = null;
-							} catch (CoreException e) {
-								TLCUIActivator.getDefault().logError(e.getMessage(), e);
-							} finally {
-								m_zeroCoverageLabel.setVisible(false);
-								m_errorPaneViewState.setZeroCountDisplay(false);
-								setErrorPaneVisible(m_errorPaneViewState.shouldDisplay());
-							}
-						}
-					}
-                    break;
-                case COVERAGE_END_OVERHEAD:
-					ns.notify(Collections.singletonList(new CoverageUINotification(getModelEditor())));
-                	// Continue with COVERAGE_END...
-                case COVERAGE_END:
-                	final CoverageInformation ci = dataProvider.getCoverageInfo();
-                	if (ci.isEmpty() || ci.isLegacy()) {
-						// Cannot show coverage information without (non-legacy) coverage data.
-                		break;
-                	}
-
-            		final List<ActionInformationItem> zeroCoverageInformation = ci.getDisabledSpecActions();
-            		for (ActionInformationItem item : zeroCoverageInformation) {
-            			final Module m = getModel().getSpec().getModule(item.getModule());
-            			if (m == null) {
-            				// With the Toolbox better be safe than sorry.
-            				continue;
-            			}
-            			try {
-            				final IMarker createMarker = m.getResource()
-            						.createMarker(ModelEditor.ZERO_COVERAGE_ACTION_MARKER);
-            				
-							createMarker.setAttribute(IMarker.MESSAGE,
-									String.format("%s is never enabled.", item.getName()));
-							createMarker.setAttribute(IMarker.LINE_NUMBER, item.getModuleLocation().beginLine());
-
-							// In order to color/highlight the token itself, set char_start and char_end
-							// too. At this point we decided it is too intrusive though.
+								final IMarker createMarker = m.getResource()
+										.createMarker(ModelEditor.ZERO_COVERAGE_ACTION_MARKER);
+
+								createMarker.setAttribute(IMarker.MESSAGE,
+										String.format("%s is never enabled.", item.getName()));
+								createMarker.setAttribute(IMarker.LINE_NUMBER, item.getModuleLocation().beginLine());
+
+								// In order to color/highlight the token itself, set char_start and char_end
+								// too. At this point we decided it is too intrusive though.
 //							final org.eclipse.jface.text.IRegion region = org.lamport.tla.toolbox.util.AdapterFactory
 //									.locationToRegion(item.getModuleLocation());
 //							createMarker.setAttribute(IMarker.CHAR_START, region.getOffset());
 //							createMarker.setAttribute(IMarker.CHAR_END, region.getOffset() + region.getLength());
-            			} catch (CoreException e) {
-            				TLCUIActivator.getDefault().logError(e.getMessage(), e);
-            			}
-            		}
-
-					// Do not open the dedicated coverage editor below if the user only requested
-					// action-only coverage.
-            		if (Model.Coverage.ACTION == getModel().getCoverage()) {
-                		break;
-                	}
-
-					
-					final ModelEditor modelEditor = (ModelEditor) ResultPage.this.getEditor();
-					
-					final List<IFile> savedTLAFiles = modelEditor.getModel().getSavedTLAFiles();
-					for (IFile iFile : savedTLAFiles) {
-						if (!ci.has(iFile)) {
-							continue;
+							} catch (CoreException e) {
+								TLCUIActivator.getDefault().logError(e.getMessage(), e);
+							}
 						}
-						// Open the files as pages of the current model editor.
-						final FileEditorInput input = new FileEditorInput(iFile);
-						final IEditorPart[] findEditors = modelEditor.findEditors(input);
-						try {
-							if (findEditors.length == 0) {
-								modelEditor.addPage(new TLACoverageEditor(ci.projectionFor(iFile)), input);
-							} else {
-								if (findEditors[0] instanceof TLACoverageEditor) {
-									final TLACoverageEditor coverageEditor = (TLACoverageEditor) findEditors[0];
-									coverageEditor.resetInput(ci.projectionFor(iFile));
+
+						// Do not open the dedicated coverage editor below if the user only requested
+						// action-only coverage.
+						if (ModelCoverage.ACTION.equals(getModel().getCoverage())) {
+							break;
+						}
+
+						final ModelEditor modelEditor = (ModelEditor) getEditor();
+
+						final List<IFile> savedTLAFiles = modelEditor.getModel().getSavedTLAFiles();
+						for (IFile iFile : savedTLAFiles) {
+							if (!ci.has(iFile)) {
+								continue;
+							}
+							// Open the files as pages of the current model editor.
+							final FileEditorInput input = new FileEditorInput(iFile);
+							final IEditorPart[] findEditors = modelEditor.findEditors(input);
+							try {
+								if (findEditors.length == 0) {
+									modelEditor.addPage(new TLACoverageEditor(ci.projectionFor(iFile)), input);
+								} else {
+									if (findEditors[0] instanceof TLACoverageEditor) {
+										final TLACoverageEditor coverageEditor = (TLACoverageEditor) findEditors[0];
+										coverageEditor.resetInput(ci.projectionFor(iFile));
+									}
 								}
+							} catch (PartInitException e) {
+								TLCUIActivator.getDefault().logError(e.getMessage(), e);
 							}
-						} catch (PartInitException e) {
-							TLCUIActivator.getDefault().logError(e.getMessage(), e);
 						}
-					}
-                	break;
-                case PROGRESS:
-                    ResultPage.this.stateSpace.setInput(dataProvider.getProgressInformation());
-
-                    // The following code finds all the graph windows (shells) for this
-                    // model and calls redraw() and update() on them, which apparently is the
-                    // magic incantation to cause its listener to be called to issue the
-                    // necessary commands to redraw the data and then displays the result.
-                    String suffix = getGraphTitleSuffix(ResultPage.this);
-                    Shell[] shells = UIHelper.getCurrentDisplay().getShells();
-                    for (int i = 0; i < shells.length; i++)
-                    {
-                        if (shells[i].getText().endsWith(suffix))
-                        {
-                            shells[i].redraw();
-                            shells[i].update();
-                            // The following was commented out by LL on 6 Jul 2012 because it was filling
-                            // up the Console log with useless stuff.
-                            // TLCUIActivator.getDefault().logDebug("Called redraw/update on shell number" + i);
-                        }
-                    }
-                    break;
-                case WARNINGS:
-					if (dataProvider.isSymmetryWithLiveness()) {
-						final MainModelPage mmp = (MainModelPage) getModelEditor().getFormPage(MainModelPage.ID);
-						final Optional<Assignment> possibleSymmetrySet = mmp.getConstants().stream()
-								.filter(c -> c.isSymmetricalSet()).findFirst();
-						if (possibleSymmetrySet.isPresent()) {
-							final Assignment symmetrySet = possibleSymmetrySet.get();
-							getModelEditor().addErrorMessage(new ErrorMessage(String.format("%s %s",
-									symmetrySet.getLabel(),
-									"declared to be symmetric. Liveness checking under symmetry might fail to find a violation."),
-									symmetrySet.getLabel(), MainModelPage.ID,
-									Arrays.asList(ISectionConstants.SEC_WHAT_IS_THE_MODEL,
-											ISectionConstants.SEC_WHAT_TO_CHECK_PROPERTIES),
-									IModelConfigurationConstants.MODEL_PARAMETER_CONSTANTS));
+						break;
+					case PROGRESS:
+						stateSpace.setInput(dataProvider.getProgressInformation());
+
+						// The following code finds all the graph windows (shells) for this
+						// model and calls redraw() and update() on them, which apparently is the
+						// magic incantation to cause its listener to be called to issue the
+						// necessary commands to redraw the data and then displays the result.
+						String suffix = getGraphTitleSuffix(ResultPage.this);
+						Shell[] shells = UIHelper.getCurrentDisplay().getShells();
+						for (int i = 0; i < shells.length; i++) {
+							if (shells[i].getText().endsWith(suffix)) {
+								shells[i].redraw();
+								shells[i].update();
+								// The following was commented out by LL on 6 Jul 2012 because it was filling
+								// up the Console log with useless stuff.
+								// TLCUIActivator.getDefault().logDebug("Called redraw/update on shell number" +
+								// i);
+							}
 						}
-					}
-					break;
-                case ERRORS:
-                    final String text;
-                    final Color color;
-                    final boolean visible;
-                    final int errorCount = dataProvider.getErrors().size();
-                    switch (errorCount) {
-						case 0:
-							text = TLCModelLaunchDataProvider.NO_ERRORS;
-							color = TLCUIActivator.getColor(SWT.COLOR_BLACK);
-							m_errorStatusHyperLink.removeHyperlinkListener(m_errorHyperLinkListener);
-							visible = false;
-							break;
-						case 1:
-							text = "1 Error";
-							m_errorStatusHyperLink.addHyperlinkListener(m_errorHyperLinkListener);
-							color = TLCUIActivator.getColor(SWT.COLOR_RED);
-							visible = true;
-							break;
-						default:
-							text = String.valueOf(errorCount) + " Errors";
-							m_errorStatusHyperLink.addHyperlinkListener(m_errorHyperLinkListener);
-							color = TLCUIActivator.getColor(SWT.COLOR_RED);
-							visible = true;
-							break;
-	                }
-
-                    m_errorStatusHyperLink.setText(text);
-                    m_errorStatusHyperLink.setForeground(color);
-					m_errorStatusHyperLink.setVisible(visible);
-					m_errorPaneViewState.setErrorLinkDisplay(visible);
-					setErrorPaneVisible(m_errorPaneViewState.shouldDisplay());
-					
-                    // update the error view
-                    TLCErrorView.updateErrorView(dataProvider.getModel());
-                    break;
-                default:
-                    break;
-                }
-				
+						break;
+					case WARNINGS:
+						if (dataProvider.isSymmetryWithLiveness()) {
+							final MainModelPage mmp = (MainModelPage) getModelEditor().getFormPage(MainModelPage.ID);
+							final Optional<Assignment> possibleSymmetrySet = mmp.getConstants().stream()
+									.filter(c -> c.isSymmetricalSet()).findFirst();
+							if (possibleSymmetrySet.isPresent()) {
+								final Assignment symmetrySet = possibleSymmetrySet.get();
+								final String errorMessage = String.format("%s %s", symmetrySet.getLabel(),
+										"declared to be symmetric. Liveness checking under symmetry might fail to find a violation.");
+								getModelEditor().addErrorMessage(
+										new ErrorMessage(errorMessage, symmetrySet.getLabel(), MainModelPage.ID,
+												Arrays.asList(ISectionConstants.SEC_WHAT_IS_THE_MODEL,
+														ISectionConstants.SEC_WHAT_TO_CHECK_PROPERTIES),
+												IModelConfigurationConstants.MODEL_PARAMETER_CONSTANTS));
+								final Hashtable<String, Object> marker = ModelHelper
+										.createMarkerDescription(errorMessage, IMarker.SEVERITY_WARNING);
+								getModel().setMarker(marker, ModelHelper.TLC_MODEL_ERROR_MARKER_TLC);
+							}
+						}
+						if (dataProvider.isConstraintsWithLiveness()) {
+							final String errorMessage = "Liveness checking with state or action constraints might fail to find a violation. "
+									+ "Please read section 14.3.5 on page 247 of Specifying Systems "
+									+ "(https://lamport.azurewebsites.net/tla/book.html) for more details.";
+							getModelEditor().addErrorMessage(new ErrorMessage(errorMessage, "StateConstraintWarning",
+									AdvancedModelPage.ID, Arrays.asList(ISectionConstants.SEC_STATE_CONSTRAINT),
+									IModelConfigurationConstants.MODEL_PARAMETER_CONSTRAINT));
+							final Hashtable<String, Object> marker = ModelHelper
+									.createMarkerDescription(errorMessage, IMarker.SEVERITY_WARNING);
+							getModel().setMarker(marker, ModelHelper.TLC_MODEL_ERROR_MARKER_TLC);
+						}
+						break;
+					case ERRORS:
+						final String text;
+						final Color color;
+						final boolean visible;
+						final int errorCount = dataProvider.getErrors().size();
+						switch (errorCount) {
+							case 0:
+								text = TLCModelLaunchDataProvider.NO_ERRORS;
+								color = TLCUIActivator.getColor(SWT.COLOR_BLACK);
+								errorStatusHyperLink.removeHyperlinkListener(m_errorHyperLinkListener);
+								visible = false;
+								break;
+							case 1:
+								text = "1 Error";
+								errorStatusHyperLink.addHyperlinkListener(m_errorHyperLinkListener);
+								color = TLCUIActivator.getColor(SWT.COLOR_RED);
+								visible = true;
+								break;
+							default:
+								text = String.valueOf(errorCount) + " Errors";
+								errorStatusHyperLink.addHyperlinkListener(m_errorHyperLinkListener);
+								color = TLCUIActivator.getColor(SWT.COLOR_RED);
+								visible = true;
+								break;
+						}
+
+						if (visible) {
+							final ModelEditor editor = (ModelEditor)getEditor();
+							final MainModelPage mmp = (MainModelPage)editor.findPage(MainModelPage.ID);
+							
+							mmp.addGlobalTLCErrorMessage(ResultPage.ID + "_err_" + errorCount);
+						}
+						
+						synchronized (markedErrorMessages) {
+							for (final TLCError error : dataProvider.getErrors()) {
+								final String message = error.getMessage();
+								if (!markedErrorMessages.contains(message)) {
+									final Hashtable<String, Object> marker = ModelHelper
+											.createMarkerDescription(message, IMarker.SEVERITY_ERROR);
+									getModel().setMarker(marker, ModelHelper.TLC_MODEL_ERROR_MARKER_TLC);
+									markedErrorMessages.add(message);
+								}
+							}
+						}
+						
+						errorStatusHyperLink.setText(text);
+						errorStatusHyperLink.setForeground(color);
+						errorStatusHyperLink.setVisible(visible);
+						errorPaneViewState.setErrorLinkDisplay(visible);
+						setErrorPaneVisible(errorPaneViewState.shouldDisplay());
+
+						// update the error view - previously (pre-201909) we used the Model instance
+						// contained
+						// in the data provider.
+						TLCErrorView.updateErrorView(getModelEditor());
+						break;
+					default:
+						break;
+				}
+
 				// Set label provider to highlight unexplored states if
 				// TLC is done but not all states are explored.
-				if (ResultPage.this.stateSpace.getLabelProvider() instanceof StateSpaceLabelProvider) {
-					final StateSpaceLabelProvider sslp = (StateSpaceLabelProvider) ResultPage.this.stateSpace
-							.getLabelProvider();
+				if (stateSpace.getLabelProvider() instanceof StateSpaceLabelProvider) {
+					final StateSpaceLabelProvider sslp = (StateSpaceLabelProvider) stateSpace.getLabelProvider();
 					if (dataProvider.isDone() && dataProvider.getProgressInformation().size() > 0) {
 						final long statesLeft = dataProvider.getProgressInformation().get(0).getLeftStates();
 						if (statesLeft > 0) {
@@ -499,14 +539,15 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
 							if (incompleteStateExploration == null) {
 								final Hashtable<String, Object> marker = ModelHelper.createMarkerDescription(
 										"State space exploration incomplete", IMarker.SEVERITY_WARNING);
-								marker.put(ModelHelper.TLC_MODEL_ERROR_MARKER_ATTRIBUTE_PAGE, 2);
-								incompleteStateExploration = getModel().setMarker(marker, ModelHelper.TLC_MODEL_ERROR_MARKER_TLC);
+								marker.put(ModelHelper.TLC_MODEL_ERROR_MARKER_ATTRIBUTE_PAGE, ResultPage.ID);
+								incompleteStateExploration = getModel().setMarker(marker,
+										ModelHelper.TLC_MODEL_ERROR_MARKER_TLC);
 							}
 						} else {
 							if (incompleteStateExploration != null) {
 								try {
 									incompleteStateExploration.delete();
-									ResultPage.this.resetMessage(RESULT_PAGE_PROBLEM);
+									resetMessage(RESULT_PAGE_PROBLEM);
 									incompleteStateExploration = null;
 								} catch (CoreException e) {
 									TLCUIActivator.getDefault().logError(e.getMessage(), e);
@@ -515,14 +556,13 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
 							sslp.unsetHighlightUnexplored();
 						}
 					}
-					ResultPage.this.stateSpace.refresh();
+					stateSpace.refresh();
 				}
-        	} finally {
-        		disposeLock.unlock();
-        	}
-        });
-
-    }
+			} finally {
+				disposeLock.unlock();
+			}
+		});
+	}
 
     /**
      * {@inheritDoc}
@@ -599,18 +639,17 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
     			return;
     		}
     		
-    		m_startTimestamp = 0;
-    		m_startLabel.setText("");
-    		m_lastCheckpointLabel.setText("");
-    		m_finishLabel.setText("");
-    		m_tlcSimulationLabel.setVisible(false);
-    		m_tlcSearchModeLabel.setText("");
-    		m_tlcStatusLabel.setText(TLCModelLaunchDataProvider.NOT_RUNNING);
-    		m_errorStatusHyperLink.setText(TLCModelLaunchDataProvider.NO_ERRORS);
-            m_errorStatusHyperLink.setVisible(false);
-            m_fingerprintCollisionLabel.setText("");
-            m_fingerprintCollisionLabel.setVisible(false);
-            m_zeroCoverageLabel.setVisible(false);
+    		startTimestamp = 0;
+    		startLabel.setText("");
+    		lastCheckpointLabel.setText("");
+    		finishLabel.setText("");
+    		tlcSimulationLabel.setVisible(false);
+    		tlcSearchModeLabel.setText("");
+    		tlcStatusLabel.setText(TLCModelLaunchDataProvider.NOT_RUNNING);
+    		errorStatusHyperLink.setText(TLCModelLaunchDataProvider.NO_ERRORS);
+            errorStatusHyperLink.setVisible(false);
+            fingerprintCollisionLabel.setText("");
+            fingerprintCollisionLabel.setVisible(false);
     		coverage.setInput(new Vector<CoverageInformationItem>());
     		stateSpace.setInput(new Vector<StateSpaceInformationItem>());
     		progressOutput.setDocument(new Document(TLCModelLaunchDataProvider.NO_OUTPUT_AVAILABLE));
@@ -618,7 +657,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
 
     		setErrorPaneVisible(false);
         	
-        	m_generalTopPane.layout(true, true);
+        	generalTopPane.layout(true, true);
     	} finally {
     		disposeLock.unlock();
     	}
@@ -647,11 +686,6 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
 				incompleteStateExploration.delete();
 				incompleteStateExploration = null;
 			}
-			
-			if (zeroCoverage != null) {
-				zeroCoverage.delete();
-				zeroCoverage = null;
-			}
 
 			JFaceResources.getFontRegistry().removeListener(fontChangeListener);
 
@@ -712,105 +746,94 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
         // necessary to eliminate that bit in the style flags that
         // are passed in. If the bit were not changed to 0, an
         // extra empty line would appear below the title.
-        m_generalSection = FormHelper.createSectionComposite(body, "General", "", toolkit, sectionFlags & ~Section.DESCRIPTION,
+        generalSection = FormHelper.createSectionComposite(body, "General", "", toolkit, sectionFlags & ~Section.DESCRIPTION,
                 null); //getExpansionListener());
-        sections.put(SEC_GENERAL, m_generalSection);
+        sections.put(SEC_GENERAL, generalSection);
         gd = new GridData();
         gd.horizontalAlignment = SWT.FILL;
         gd.grabExcessHorizontalSpace = true;
         gd.verticalAlignment = SWT.TOP;
-        m_generalSection.setLayoutData(gd);
+        generalSection.setLayoutData(gd);
         final GeneralSectionExpansionHoopJumper absurdListener = new GeneralSectionExpansionHoopJumper();
-        m_generalSection.addExpansionListener(absurdListener);
-        m_generalSection.setData(SECTION_EXPANSION_LISTENER, absurdListener);
+        generalSection.addExpansionListener(absurdListener);
+        generalSection.setData(SECTION_EXPANSION_LISTENER, absurdListener);
         
-        final Composite generalArea = (Composite) m_generalSection.getClient();
+        final Composite generalArea = (Composite) generalSection.getClient();
         gl = new GridLayout(1, false);
         gl.marginHeight = 0;
         gl.marginWidth = 0;
         gl.marginBottom = 6;
         generalArea.setLayout(gl);
         
-        m_generalTopPane = new Composite(generalArea, SWT.NONE);
+        generalTopPane = new Composite(generalArea, SWT.NONE);
         gd = new GridData();
         gd.horizontalAlignment = SWT.FILL;
         gd.grabExcessHorizontalSpace = true;
         gd.verticalAlignment = SWT.TOP;
-        m_generalTopPane.setLayoutData(gd);
+        generalTopPane.setLayoutData(gd);
         gl = new GridLayout(6, false);
         gl.marginHeight = 0;
         gl.marginWidth = 0;
         gl.horizontalSpacing = 12;
-        m_generalTopPane.setLayout(gl);
+        generalTopPane.setLayout(gl);
         
-        m_startLabel = new Label(m_generalTopPane, SWT.NONE);
-        m_startLabel.setLayoutData(new GridData());
-        m_startLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT));
-        m_lastCheckpointLabel = new Label(m_generalTopPane, SWT.NONE);
-        m_lastCheckpointLabel.setLayoutData(new GridData());
-        m_finishLabel = new Label(m_generalTopPane, SWT.NONE);
-        m_finishLabel.setLayoutData(new GridData());
-        m_finishLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT));
-        m_tlcSimulationLabel = new Label(m_generalTopPane, SWT.NONE);
+        startLabel = new Label(generalTopPane, SWT.NONE);
+        startLabel.setLayoutData(new GridData());
+        startLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT));
+        lastCheckpointLabel = new Label(generalTopPane, SWT.NONE);
+        lastCheckpointLabel.setLayoutData(new GridData());
+        finishLabel = new Label(generalTopPane, SWT.NONE);
+        finishLabel.setLayoutData(new GridData());
+        finishLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT));
+        tlcSimulationLabel = new Label(generalTopPane, SWT.NONE);
         gd = new GridData();
         gd.horizontalAlignment = SWT.CENTER;
-        m_tlcSimulationLabel.setLayoutData(gd);
-        m_tlcSimulationLabel.setText("Simulation mode");
-        m_tlcSimulationLabel.setVisible(false);
-        m_tlcSimulationLabel.setFont(JFaceResources.getFontRegistry().getItalic(JFaceResources.DIALOG_FONT));
-        m_tlcSearchModeLabel = new Label(m_generalTopPane, SWT.NONE);
+        tlcSimulationLabel.setLayoutData(gd);
+        tlcSimulationLabel.setText("Simulation mode");
+        tlcSimulationLabel.setVisible(false);
+        tlcSimulationLabel.setFont(JFaceResources.getFontRegistry().getItalic(JFaceResources.DIALOG_FONT));
+        tlcSearchModeLabel = new Label(generalTopPane, SWT.NONE);
         gd = new GridData();
         gd.horizontalAlignment = SWT.RIGHT;
         gd.grabExcessHorizontalSpace = true;
-        m_tlcSearchModeLabel.setLayoutData(gd);
-        m_tlcStatusLabel = new Label(m_generalTopPane, SWT.NONE);
+        tlcSearchModeLabel.setLayoutData(gd);
+        tlcStatusLabel = new Label(generalTopPane, SWT.NONE);
         gd = new GridData();
         gd.horizontalAlignment = SWT.RIGHT;
         gd.grabExcessHorizontalSpace = true;
         gd.horizontalIndent = 18;
-        m_tlcStatusLabel.setLayoutData(gd);
-        m_tlcStatusLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT));
+        tlcStatusLabel.setLayoutData(gd);
+        tlcStatusLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT));
         
-        m_generalErrorPane = new Composite(generalArea, SWT.NONE);
+        generalErrorPane = new Composite(generalArea, SWT.NONE);
         gd = new GridData();
         gd.horizontalAlignment = SWT.FILL;
         gd.grabExcessHorizontalSpace = true;
         gd.verticalIndent = 9;
         gd.verticalAlignment = SWT.TOP;
-        m_generalErrorPane.setLayoutData(gd);
+        generalErrorPane.setLayoutData(gd);
         gl = new GridLayout(3, false);
         gl.marginHeight = 6;
         gl.marginWidth = 0;
         gl.horizontalSpacing = 6;
-        m_generalErrorPane.setLayout(gl);
-        m_generalErrorPane.setBackground(ERROR_PANE_BACKGROUND);
+        generalErrorPane.setLayout(gl);
+        generalErrorPane.setBackground(ERROR_PANE_BACKGROUND);
 
         // errors
         // Label createLabel =
         // toolkit.createLabel(statusComposite, "Errors detected:");
         // this.errorStatusHyperLink = toolkit.createHyperlink(statusComposite, "", SWT.RIGHT);
-        m_errorStatusHyperLink = toolkit.createHyperlink(m_generalErrorPane, "", SWT.NONE);
-        m_errorStatusHyperLink.setBackground(m_generalErrorPane.getBackground());
-        m_errorStatusHyperLink.setVisible(false);
+        errorStatusHyperLink = toolkit.createHyperlink(generalErrorPane, "", SWT.NONE);
+        errorStatusHyperLink.setBackground(generalErrorPane.getBackground());
+        errorStatusHyperLink.setVisible(false);
         
         // fingerprint collision probability
-        m_fingerprintCollisionLabel = new Label(m_generalErrorPane, SWT.NONE);
+        fingerprintCollisionLabel = new Label(generalErrorPane, SWT.NONE);
         gd = new GridData();
         gd.horizontalAlignment = SWT.CENTER;
-        m_fingerprintCollisionLabel.setLayoutData(gd);
-        m_fingerprintCollisionLabel.setVisible(false);
-        
-        // zero coverage label
-        m_zeroCoverageLabel = new Label(m_generalErrorPane, SWT.NONE);
-        m_zeroCoverageLabel.setText(ZERO_COVERAGE_WARNING);
-        m_zeroCoverageLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT));
-        m_zeroCoverageLabel.setVisible(false);
-        gd = new GridData();
-        gd.horizontalAlignment = SWT.RIGHT;
-        gd.grabExcessHorizontalSpace = true;
-        gd.verticalAlignment = SWT.BOTTOM;
-        m_zeroCoverageLabel.setLayoutData(gd);
-        
+        fingerprintCollisionLabel.setLayoutData(gd);
+        fingerprintCollisionLabel.setVisible(false);
+                
 		setErrorPaneVisible(false);
 
 	
@@ -848,20 +871,20 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
         // -------------------------------------------------------------------
         // Calculator section
 		final IPreferenceStore ips = TLCUIActivator.getDefault().getPreferenceStore();
-		final boolean eceInItsOwnTab = ips.getBoolean(ITLCPreferenceConstants.I_TLC_SHOW_ECE_AS_TAB);
+		final boolean eceInItsOwnTab = ips.getBoolean(IModelEditorPreferenceConstants.I_MODEL_EDITOR_SHOW_ECE_AS_TAB);
 
-		m_calculatorSection = new Composite(body, SWT.NONE);
+		calculatorSection = new Composite(body, SWT.NONE);
         gd = new GridData();
         gd.horizontalAlignment = SWT.FILL;
         gd.verticalAlignment = SWT.FILL;
         gd.grabExcessHorizontalSpace = true;
         gd.grabExcessVerticalSpace = !eceInItsOwnTab;
-        m_calculatorSection.setLayoutData(gd);
+        calculatorSection.setLayoutData(gd);
         gl = new GridLayout();
         gl.marginHeight = 0;
         gl.marginWidth = 0;
-        m_calculatorSection.setLayout(gl);
-        m_calculatorSection.setBackground(m_calculatorSection.getDisplay().getSystemColor(SWT.COLOR_WHITE));
+        calculatorSection.setLayout(gl);
+        calculatorSection.setBackground(calculatorSection.getDisplay().getSystemColor(SWT.COLOR_WHITE));
         
 		if (!eceInItsOwnTab) {
 			pageShouldDisplayEvaluateConstantUI(true);
@@ -935,7 +958,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
         progressOutput.getTextWidget().setLayoutData(gd);
         progressOutput.getTextWidget().setFont(JFaceResources.getFont(ITLCPreferenceConstants.I_TLC_OUTPUT_FONT));
 
-        Vector<Control> controls = new Vector<Control>();
+        final Vector<Control> controls = new Vector<Control>();
         controls.add(userOutput.getControl());
         controls.add(progressOutput.getControl());
         fontChangeListener = new FontPreferenceChangeListener(controls, ITLCPreferenceConstants.I_TLC_OUTPUT_FONT);
@@ -980,7 +1003,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
 						final Job job = new UIJob("Updating results page with loaded output...") {
 							public IStatus runInUIThread(IProgressMonitor monitor) {
 								try {
-									ResultPage.this.loadData();
+									loadData();
 								} catch (CoreException e) {
 									return new Status(IStatus.ERROR, TLCUIActivator.PLUGIN_ID, e.getMessage(), e);
 								}
@@ -1024,62 +1047,62 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
     }
 
     private void setStartTime(final long msTime) {
-    	m_startTimestamp = msTime;
+    	startTimestamp = msTime;
     	
     	if (msTime < 0) {
 			// Leave the starttime text empty on a negative timestamp. A negative one indicates that the
 			// model has never been checked
     		// See Long.MIN_VALUE in org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider.initialize()
-    		m_startLabel.setText("Awaiting first run...");
+    		startLabel.setText("Awaiting first run...");
 		} else {
-			m_startLabel.setText("Start: " + DATE_FORMATTER.format(new Date(msTime)));
+			startLabel.setText("Start: " + DATE_FORMATTER.format(new Date(msTime)));
 		}
     	
-    	m_generalTopPane.layout(true, true);
+    	generalTopPane.layout(true, true);
     }
     
     private void setEndTime(final long msTime) {
     	if (msTime < 0) {
-    		m_finishLabel.setVisible(false);
+    		finishLabel.setVisible(false);
 		} else {
-			m_finishLabel.setText("End: " + DATE_FORMATTER.format(new Date(msTime)));
-    		m_finishLabel.setVisible(true);
+			finishLabel.setText("End: " + DATE_FORMATTER.format(new Date(msTime)));
+    		finishLabel.setVisible(true);
 		}
     	
-    	m_generalTopPane.layout(true, true);
+    	generalTopPane.layout(true, true);
     }
     
     private void setCheckpoint(final long msTime) {
     	if (msTime < 0) {
-        	m_lastCheckpointLabel.setVisible(false);
+        	lastCheckpointLabel.setVisible(false);
 		} else {
-        	m_lastCheckpointLabel.setText("Last checkpoint: " + DATE_FORMATTER.format(new Date(msTime)));
-        	m_lastCheckpointLabel.setVisible(true);
+        	lastCheckpointLabel.setText("Last checkpoint: " + DATE_FORMATTER.format(new Date(msTime)));
+        	lastCheckpointLabel.setVisible(true);
 		}
     	
-    	m_generalTopPane.layout(true, true);
+    	generalTopPane.layout(true, true);
     }
     
     private void setSearchMode(final String mode) {
     	if (TLCModelLaunchDataProvider.DEPTH_FIRST_SEARCH.equals(mode)) {
-    		m_tlcSearchModeLabel.setText(TLCModelLaunchDataProvider.DEPTH_FIRST_SEARCH);
-    		m_tlcSearchModeLabel.setVisible(true);
-    		m_tlcSimulationLabel.setVisible(false);
+    		tlcSearchModeLabel.setText(TLCModelLaunchDataProvider.DEPTH_FIRST_SEARCH);
+    		tlcSearchModeLabel.setVisible(true);
+    		tlcSimulationLabel.setVisible(false);
     	} else {
-    		m_tlcSearchModeLabel.setVisible(false);
-			m_tlcSimulationLabel.setVisible(TLCModelLaunchDataProvider.SIMULATION_MODE.equals(mode));
+    		tlcSearchModeLabel.setVisible(false);
+			tlcSimulationLabel.setVisible(TLCModelLaunchDataProvider.SIMULATION_MODE.equals(mode));
     	}
     	
-    	m_generalTopPane.layout(true, true);
+    	generalTopPane.layout(true, true);
     }
     
     private void setErrorPaneVisible(final boolean visible) {
-    	final GridData gd = (GridData)m_generalErrorPane.getLayoutData();
+    	final GridData gd = (GridData)generalErrorPane.getLayoutData();
     	
     	gd.exclude = !visible;
-    	m_generalErrorPane.setLayoutData(gd);
+    	generalErrorPane.setLayoutData(gd);
     	
-    	m_generalErrorPane.setVisible(visible);
+    	generalErrorPane.setVisible(visible);
     }
     
     private int getHeightGuidanceForLabelTextFieldLine(final Composite parent, final FormToolkit toolkit) {
@@ -1212,7 +1235,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
         gd.verticalIndent = 0;
         headerLine.setLayoutData(gd);
         
-        final Label title = toolkit.createLabel(headerLine, "Actions at");
+        final Label title = toolkit.createLabel(headerLine, "Sub-actions of next-state"); // "next-state" term used on MainModelPage too
         gd = new GridData();
         gd.horizontalIndent = 0;
         gd.verticalIndent = 6;
@@ -1223,7 +1246,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
 
         this.coverageTimestampText = toolkit.createText(headerLine, "", SWT.FLAT);
         this.coverageTimestampText.setEditable(false);
-        this.coverageTimestampText.setMessage("No information collected yet. Has coverage been enabled?");
+        this.coverageTimestampText.setMessage("(No numbers recorded yet. Has profiling been enabled on TLC options?)");
         gd = new GridData();
         gd.horizontalIndent = 6;
         gd.verticalIndent = 0;
@@ -1302,7 +1325,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
     }
 
     long getStartTimestamp() {
-    	return m_startTimestamp;
+    	return startTimestamp;
     }
     
     TableViewer getStateSpaceTableViewer() {
@@ -1317,8 +1340,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
      * @return
      */
     @SuppressWarnings("unchecked")  // generics cast
-    public StateSpaceInformationItem[] getStateSpaceInformation()
-    {
+	public StateSpaceInformationItem[] getStateSpaceInformation() {
 		List<StateSpaceInformationItem> infoList = (List<StateSpaceInformationItem>) stateSpace.getInput();
         StateSpaceInformationItem[] result = new StateSpaceInformationItem[infoList.size()];
         for (int i = 0; i < result.length; i++)
@@ -1339,7 +1361,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
 	public EvaluateConstantExpressionPage.State getECEContent() {
 		if (expressionEvalInput != null) {
 			return new EvaluateConstantExpressionPage.State(expressionEvalInput.getDocument(),
-					expressionEvalResult.getTextWidget().getText(), m_noBehaviorModeToggleButton.getSelection());
+					expressionEvalResult.getTextWidget().getText(), noBehaviorModeToggleButton.getSelection());
 		}
 		
 		return null;
@@ -1351,13 +1373,13 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
 		} else {
 			expressionEvalInput.setDocument(state.getInputDocument());
 			expressionEvalResult.getTextWidget().setText(state.getOutputText());
-			m_noBehaviorModeToggleButton.setSelection(state.getToggleState());
+			noBehaviorModeToggleButton.setSelection(state.getToggleState());
 		}
 	}
     
 	public void setNoBehaviorSpecToggleState(final boolean selected) {
-		if (m_noBehaviorModeToggleButton != null) {
-			m_noBehaviorModeToggleButton.setSelection(selected);
+		if (noBehaviorModeToggleButton != null) {
+			noBehaviorModeToggleButton.setSelection(selected);
 		}
 	}
 	
@@ -1369,7 +1391,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
 	        final int sectionFlags = Section.TITLE_BAR | Section.TREE_NODE | Section.EXPANDED | SWT.WRAP;
 	        final int textFieldFlags = SWT.MULTI | SWT.V_SCROLL | SWT.READ_ONLY | SWT.FULL_SELECTION | SWT.WRAP;
 			final EvaluateConstantExpressionPage.BodyContentAssets assets = EvaluateConstantExpressionPage
-					.createBodyContent(m_calculatorSection, toolkit, sectionFlags, textFieldFlags,
+					.createBodyContent(calculatorSection, toolkit, sectionFlags, textFieldFlags,
 							getExpansionListener(), (ModelEditor)getEditor());
 			final Section section = assets.getSection();
 			
@@ -1377,17 +1399,16 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
 
 			expressionEvalInput = assets.getExpressionInput();
 	        expressionEvalResult = assets.getExpressionOutput();
-	        m_noBehaviorModeToggleButton = assets.getToggleButton();
+	        noBehaviorModeToggleButton = assets.getToggleButton();
 
-	        m_validateableCalculatorSection = new ValidateableSectionPart(section, this, SEC_EXPRESSION);
+	        validateableCalculatorSection = new ValidateableSectionPart(section, this, SEC_EXPRESSION);
 	        // This ensures that when the part is made dirty, the model appears unsaved.
-	        managedForm.addPart(m_validateableCalculatorSection);
+	        managedForm.addPart(validateableCalculatorSection);
 
 	        // This makes the widget unsaved when text is entered.
-	        expressionEvalInput.getTextWidget().addModifyListener(new DirtyMarkingListener(m_validateableCalculatorSection, false));
+	        expressionEvalInput.getTextWidget().addModifyListener(new DirtyMarkingListener(validateableCalculatorSection, false));
 
-	        getDataBindingManager().bindSection(m_validateableCalculatorSection, SEC_EXPRESSION, getId());
-	        getDataBindingManager().bindAttribute(Model.MODEL_EXPRESSION_EVAL, expressionEvalInput, m_validateableCalculatorSection);
+	        getDataBindingManager().bindAttribute(Model.MODEL_EXPRESSION_EVAL, expressionEvalInput, validateableCalculatorSection);
 	        
 	        section.addExpansionListener(new ExpansionAdapter() {
 	            public void expansionStateChanged(final ExpansionEvent e) {
@@ -1397,42 +1418,51 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
 	                    gd.verticalAlignment = SWT.FILL;
 	                    gd.grabExcessHorizontalSpace = true;
 	                    gd.grabExcessVerticalSpace = true;
-	                    m_calculatorSection.setLayoutData(gd);
+	                    calculatorSection.setLayoutData(gd);
 	            	} else {
-	            		final GridData gd = (GridData)m_calculatorSection.getLayoutData();
+	            		final GridData gd = (GridData)calculatorSection.getLayoutData();
 	            		final Point size = section.computeSize(SWT.DEFAULT, SWT.DEFAULT);
 	            		
 	            		gd.grabExcessVerticalSpace = e.getState();
 	            		gd.heightHint = size.y;
 
-		            	m_calculatorSection.setLayoutData(gd);
+		            	calculatorSection.setLayoutData(gd);
 	            	}
 	            }
 	        });
-		} else if (m_validateableCalculatorSection != null) {
+		} else if (validateableCalculatorSection != null) {
 			sections.remove(SEC_EXPRESSION);
 			
-			managedForm.removePart(m_validateableCalculatorSection);
+			managedForm.removePart(validateableCalculatorSection);
 			
-			m_validateableCalculatorSection = null;
+			validateableCalculatorSection = null;
 			expressionEvalInput = null;
 			expressionEvalResult = null;
-			m_noBehaviorModeToggleButton = null;
+			noBehaviorModeToggleButton = null;
 			
-			for (final Control control : m_calculatorSection.getChildren()) {
+			for (final Control control : calculatorSection.getChildren()) {
 				control.dispose();
 			}
 			
 			getDataBindingManager().unbindSectionFromPage(SEC_EXPRESSION, getId());
 		}
 		
-		final GridData gd = (GridData)m_calculatorSection.getLayoutData();
+		final GridData gd = (GridData)calculatorSection.getLayoutData();
 		gd.grabExcessVerticalSpace = shouldShow;
-		m_calculatorSection.setLayoutData(gd);
+		calculatorSection.setLayoutData(gd);
 		
 		getManagedForm().reflow(true);
 	}
-	
+
+	@Override
+	public void close() throws IOException {
+		getModelEditor().resultsPageIsClosing();
+		
+		final DataBindingManager dm = getDataBindingManager();
+		dm.unbindSectionAndAttribute(Model.MODEL_EXPRESSION_EVAL);
+		dm.unbindSectionFromPage(SEC_EXPRESSION, getId());
+	}
+
 	
 	private class GeneralSectionExpansionHoopJumper extends ExpansionAdapter implements Consumer<Boolean> {
         public void expansionStateChanged(final ExpansionEvent e) {
@@ -1441,21 +1471,21 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
 
         public void accept(final Boolean expand) {
         	if (expand.booleanValue()) {
-        		final Composite c = (Composite)m_generalSection.getClient();
-        		final GridData gd = (GridData)m_generalSection.getLayoutData();
+        		final Composite c = (Composite)generalSection.getClient();
+        		final GridData gd = (GridData)generalSection.getLayoutData();
         		
-        		gd.heightHint = m_collapsedSectionHeight + c.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
+        		gd.heightHint = collapsedSectionHeight + c.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
 
-                m_generalSection.setLayoutData(gd);
-                m_generalSection.getParent().layout(true, true);
+                generalSection.setLayoutData(gd);
+                generalSection.getParent().layout(true, true);
         	} else {
         		final GridData gd = new GridData();
                 gd.horizontalAlignment = SWT.FILL;
                 gd.grabExcessHorizontalSpace = true;
                 gd.verticalAlignment = SWT.TOP;
-                m_generalSection.setLayoutData(gd);
+                generalSection.setLayoutData(gd);
                 
-                m_collapsedSectionHeight = m_generalSection.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
+                collapsedSectionHeight = generalSection.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
         	}
         }
 	}
@@ -1493,14 +1523,6 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres
 			return m_displayFingerprint.get();
 		}
 		
-		void setZeroCountDisplay(final boolean display) {
-			m_displayZeroCount.set(display);
-		}
-		
-		boolean zeroCountIsDisplayed() {
-			return m_displayZeroCount.get();
-		}
-		
 		void clearState() {
 			m_displayErrorLink.set(false);
 			m_displayFingerprint.set(false);
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableConstantSectionPart.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableConstantSectionPart.java
index 8d231553445026bf62fea9cd33ee391f9e4228a1..af4cd9fcab52ec327ad4207dfe2f2e1f59d27906 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableConstantSectionPart.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableConstantSectionPart.java
@@ -13,12 +13,13 @@ import org.eclipse.swt.SWT;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.ui.forms.widgets.FormToolkit;
-import org.lamport.tla.toolbox.tool.tlc.model.Assignment;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.BasicFormPage;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.provider.AssignmentContentProvider;
 import org.lamport.tla.toolbox.tool.tlc.ui.wizard.AssignmentWizard;
 import org.lamport.tla.toolbox.tool.tlc.ui.wizard.AssignmentWizardPage;
 
+import tlc2.model.Assignment;
+
 /**
  * Section part for the constants 
  * @author Simon Zambrovski
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableOverridesSectionPart.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableOverridesSectionPart.java
index c08219885105fbb9c72657ad0757873cd1369e13..967ee76010505b9499f3c7a6f123afff1cd266bb 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableOverridesSectionPart.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableOverridesSectionPart.java
@@ -2,6 +2,8 @@ package org.lamport.tla.toolbox.tool.tlc.ui.editor.part;
 
 import java.util.Vector;
 
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
 import org.eclipse.jface.viewers.LabelProvider;
 import org.eclipse.jface.viewers.TableViewer;
 import org.eclipse.jface.window.Window;
@@ -10,29 +12,44 @@ import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.ui.forms.widgets.FormToolkit;
 import org.lamport.tla.toolbox.tool.ToolboxHandle;
-import org.lamport.tla.toolbox.tool.tlc.model.Assignment;
+import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
 import org.lamport.tla.toolbox.tool.tlc.ui.dialog.FilteredDefinitionSelectionDialog;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.DataBindingManager;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.BasicFormPage;
+import org.lamport.tla.toolbox.tool.tlc.ui.editor.preference.IModelEditorPreferenceConstants;
 import org.lamport.tla.toolbox.tool.tlc.ui.wizard.AssignmentWizard;
 import org.lamport.tla.toolbox.tool.tlc.ui.wizard.AssignmentWizardPage;
 import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper;
 
 import tla2sany.semantic.OpDefNode;
+import tlc2.model.Assignment;
 
 /**
  * Section part for the DefinitionOverride section of the Advanced Options page
  * @author Simon Zambrovski
- * @version $Id$
  */
-public class ValidateableOverridesSectionPart extends ValidateableConstantSectionPart
-{
-
-    public ValidateableOverridesSectionPart(Composite composite, String title, String description, FormToolkit toolkit,
-            int flags, BasicFormPage page)
-    {
+public class ValidateableOverridesSectionPart extends ValidateableConstantSectionPart {
+	private final IPropertyChangeListener m_preferenceChangeListener = (event) -> {
+		if (IModelEditorPreferenceConstants.I_OVERRIDDEN_DEFINITION_STYLE.equals(event.getProperty())) {
+			tableViewer.refresh(true);
+		}
+	};
+
+	public ValidateableOverridesSectionPart(Composite composite, String title, String description, FormToolkit toolkit,
+			int flags, BasicFormPage page) {
         super(composite, title, description, toolkit, flags, page, DataBindingManager.SEC_DEFINITION_OVERRIDE);
+        
+		final IPreferenceStore ips = TLCUIActivator.getDefault().getPreferenceStore();
+		ips.addPropertyChangeListener(m_preferenceChangeListener);
     }
+	
+	@Override
+	public void dispose() {
+		final IPreferenceStore ips = TLCUIActivator.getDefault().getPreferenceStore();
+		ips.removePropertyChangeListener(m_preferenceChangeListener);
+		
+		super.dispose();
+	}
 
     @Override
     @SuppressWarnings("unchecked")  // Generic casting...
@@ -163,8 +180,13 @@ public class ValidateableOverridesSectionPart extends ValidateableConstantSectio
             {
                 if (element instanceof Assignment)
                 {
-                    Assignment assign = (Assignment) element;
-                    String label = assign.getLabel();
+					final IPreferenceStore ips = TLCUIActivator.getDefault().getPreferenceStore();
+					final String style = ips
+							.getString(IModelEditorPreferenceConstants.I_OVERRIDDEN_DEFINITION_STYLE);
+					final boolean moduleNameStyle = IModelEditorPreferenceConstants.I_OVERRIDDEN_DEFINITION_STYLE_MODULE_NAME
+							.equals(style);
+                    final Assignment assign = (Assignment) element;
+                    final String label = assign.getLabel();
                     String noBangLabel = label.substring(label.lastIndexOf("!") + 1);
             		
 					// This is upside-down because early in the call stack we had the node instance
@@ -172,21 +194,26 @@ public class ValidateableOverridesSectionPart extends ValidateableConstantSectio
 					// have to reconstruct the actual OpDefNode because need to know its module.
 					// Since this is the standard idiom throughout this part of the model editor,
 					// I'm not going to rewrite it.
-                    OpDefNode node = ModelHelper.getOpDefNode(label);
-            		if (node != null && node.getSource() != node) {
+                    final OpDefNode node = ModelHelper.getOpDefNode(label);
+            		if (moduleNameStyle && (node != null) && (node.getSource() != node)) {
             			noBangLabel += " [" + node.getSource().getOriginallyDefinedInModuleNode().getName().toString() + "]";
             		}
-            		
-                    String rightSide = null;
-                    if (assign.isModelValue())
-                    {
-                        rightSide = noBangLabel;
-                    } else
-                    {
-                        rightSide = assign.getRight();
+
+					final boolean appendOverriddenModelValue = assign.isModelValue() && (node != null)
+							&& (node.getSource() != node);
+                    if (appendOverriddenModelValue && !moduleNameStyle) {
+                    	return (assign.toString() + " " + noBangLabel);
+                    } else {
+                        final String rightSide;
+    					if (assign.isModelValue()) {
+    						rightSide = noBangLabel;
+    					} else {
+    						rightSide = assign.getRight();
+    					}
+    					
+                        final Assignment assignNoBang = new Assignment(noBangLabel, assign.getParams(), rightSide);
+                        return assignNoBang.toString() + (appendOverriddenModelValue ? (" " + noBangLabel) : "");
                     }
-                    Assignment assignNoBang = new Assignment(noBangLabel, assign.getParams(), rightSide);
-                    return assignNoBang.toString();
                 }
                 return super.getText(element);
             }
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableTableSectionPart.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableTableSectionPart.java
index 70a53ce73581ab2708bd21ef998972e1ff749f94..68604148c2431e1c1623abdf7ba0df052beb7f4d 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableTableSectionPart.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/part/ValidateableTableSectionPart.java
@@ -27,13 +27,14 @@ import org.eclipse.ui.forms.IManagedForm;
 import org.eclipse.ui.forms.SectionPart;
 import org.eclipse.ui.forms.widgets.FormToolkit;
 import org.eclipse.ui.forms.widgets.Section;
-import org.lamport.tla.toolbox.tool.tlc.model.Formula;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.BasicFormPage;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.provider.FormulaContentProvider;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.provider.FormulaLabelProvider;
 import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper;
 import org.lamport.tla.toolbox.tool.tlc.ui.wizard.FormulaWizard;
 
+import tlc2.model.Formula;
+
 /**
  * Section part with table and add, edit and remove buttons
  * @author Simon Zambrovski
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/preference/IModelEditorPreferenceConstants.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/preference/IModelEditorPreferenceConstants.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd8b69294b77a68c3117416811237e8259a0cafc
--- /dev/null
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/preference/IModelEditorPreferenceConstants.java
@@ -0,0 +1,22 @@
+package org.lamport.tla.toolbox.tool.tlc.ui.editor.preference;
+
+public interface IModelEditorPreferenceConstants {
+	/**
+	 * If set, the Evaluate Constant Expressions section of the Results page will be shown in its own model editor tab.
+	 */
+	public static final String I_MODEL_EDITOR_SHOW_ECE_AS_TAB = "showECEAsTab";
+
+	/**
+	 * The preference defining how the user would prefer to see overridden definitions displayed.
+	 */
+	public static final String I_OVERRIDDEN_DEFINITION_STYLE = "definitionOverrideStyle";
+	/**
+	 * The style of "Definition [Module Name]"
+	 */
+	public static final String I_OVERRIDDEN_DEFINITION_STYLE_MODULE_NAME = "byModuleName";
+	/**
+	 * The style of "InstanceVariableName!Definition" where there is a declaration in the code like:
+	 * 		InstanceVariableName == INSTANCE ModuleName WITH ...
+	 */
+	public static final String I_OVERRIDDEN_DEFINITION_STYLE_INSTANCE_NAME = "byInstanceName";
+}
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/preference/ModelEditorPreferenceInitializer.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/preference/ModelEditorPreferenceInitializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..b3fb35b37119396f46cc4c9568c3ad424e83c29b
--- /dev/null
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/preference/ModelEditorPreferenceInitializer.java
@@ -0,0 +1,15 @@
+package org.lamport.tla.toolbox.tool.tlc.ui.editor.preference;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
+
+public class ModelEditorPreferenceInitializer  extends AbstractPreferenceInitializer {
+	public void initializeDefaultPreferences() {
+		final IPreferenceStore uiPreferencesStore = TLCUIActivator.getDefault().getPreferenceStore();
+
+        uiPreferencesStore.setDefault(IModelEditorPreferenceConstants.I_MODEL_EDITOR_SHOW_ECE_AS_TAB, false);
+        uiPreferencesStore.setDefault(IModelEditorPreferenceConstants.I_OVERRIDDEN_DEFINITION_STYLE,
+        		IModelEditorPreferenceConstants.I_OVERRIDDEN_DEFINITION_STYLE_MODULE_NAME);
+	}
+}
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/preference/ModelEditorPreferencePage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/preference/ModelEditorPreferencePage.java
new file mode 100644
index 0000000000000000000000000000000000000000..09b9f70d5ce2ada4e22392a5789a6db5ce5dcd49
--- /dev/null
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/preference/ModelEditorPreferencePage.java
@@ -0,0 +1,60 @@
+package org.lamport.tla.toolbox.tool.tlc.ui.editor.preference;
+
+import org.eclipse.jface.preference.BooleanFieldEditor;
+import org.eclipse.jface.preference.ComboFieldEditor;
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.lamport.tla.toolbox.tool.tlc.TLCActivator;
+import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
+import org.lamport.tla.toolbox.util.IHelpConstants;
+import org.lamport.tla.toolbox.util.UIHelper;
+
+/**
+ * Preference pane for the Model Editor preferences page.
+ */
+public class ModelEditorPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+	public ModelEditorPreferencePage() {
+        super(GRID);
+        
+        // Copy preference value to non-ui plugin.
+        TLCUIActivator.getDefault().getPreferenceStore().addPropertyChangeListener(new IPropertyChangeListener() {
+			@Override
+			public void propertyChange(PropertyChangeEvent event) {
+				final IPreferenceStore store = TLCActivator.getDefault().getPreferenceStore();
+				if (TLCActivator.I_TLC_SNAPSHOT_KEEP_COUNT.equals(event.getProperty())) {
+					store.setValue(TLCActivator.I_TLC_SNAPSHOT_KEEP_COUNT, (int)event.getNewValue());
+				}
+			}
+		});
+		setPreferenceStore(TLCUIActivator.getDefault().getPreferenceStore());
+        setDescription("Model Editor preferences");
+    }
+
+	protected Control createContents(Composite parent) {
+        final Control pageControl = super.createContents(parent);
+        UIHelper.setHelp(pageControl, IHelpConstants.MODEL_EDITOR_PREFERENCE_PAGE);
+        return pageControl;
+    }
+
+	protected void createFieldEditors() {
+        addField(new BooleanFieldEditor(IModelEditorPreferenceConstants.I_MODEL_EDITOR_SHOW_ECE_AS_TAB,
+                "Show Evaluate Constant Expression in its own tab", getFieldEditorParent()));
+        
+        final String[][] overrideDisplays = {
+        		{ "Definition [Module Name]",
+        			IModelEditorPreferenceConstants.I_OVERRIDDEN_DEFINITION_STYLE_MODULE_NAME },
+        		{ "InstanceName!Definition",
+        			IModelEditorPreferenceConstants.I_OVERRIDDEN_DEFINITION_STYLE_INSTANCE_NAME }
+        };
+        addField(new ComboFieldEditor(IModelEditorPreferenceConstants.I_OVERRIDDEN_DEFINITION_STYLE,
+        		"Definition Override display style", overrideDisplays, getFieldEditorParent()));
+    }
+
+    public void init(IWorkbench workbench) { }
+}
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/provider/AssignmentContentProvider.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/provider/AssignmentContentProvider.java
index 2e2117040802aa860934ff764d8613dc15c855f5..f21af359139718344c895f61c740364190c40d59 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/provider/AssignmentContentProvider.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/provider/AssignmentContentProvider.java
@@ -4,7 +4,8 @@ import java.util.Vector;
 
 import org.eclipse.jface.viewers.IStructuredContentProvider;
 import org.eclipse.jface.viewers.Viewer;
-import org.lamport.tla.toolbox.tool.tlc.model.Assignment;
+
+import tlc2.model.Assignment;
 
 /**
  * Boy.  You could spend days studying Simon's documentation of this class.
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/provider/FormulaContentProvider.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/provider/FormulaContentProvider.java
index a841f0a614d0779700a1f6643511a6dbd80739c1..4f956f733431a3352ad9984c9a80192c7713f59e 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/provider/FormulaContentProvider.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/provider/FormulaContentProvider.java
@@ -5,7 +5,8 @@ import java.util.Vector;
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.jface.viewers.IStructuredContentProvider;
 import org.eclipse.jface.viewers.Viewer;
-import org.lamport.tla.toolbox.tool.tlc.model.Formula;
+
+import tlc2.model.Formula;
 
 /**
  * @author Simon Zambrovski
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelContentProvider.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelContentProvider.java
index c41458c27be49db984d095661985c15cb7e61465..e0d3d1e635263fbb6f490f8b649eacc74aafb323 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelContentProvider.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelContentProvider.java
@@ -35,9 +35,8 @@ import org.eclipse.jface.viewers.Viewer;
 import org.eclipse.ui.navigator.CommonViewer;
 import org.lamport.tla.toolbox.spec.Spec;
 import org.lamport.tla.toolbox.tool.ToolboxHandle;
+import org.lamport.tla.toolbox.tool.tlc.model.AbstractModelStateChangeListener;
 import org.lamport.tla.toolbox.tool.tlc.model.Model;
-import org.lamport.tla.toolbox.tool.tlc.model.Model.StateChangeListener;
-import org.lamport.tla.toolbox.tool.tlc.model.Model.StateChangeListener.ChangeEvent.State;
 import org.lamport.tla.toolbox.tool.tlc.model.TLCSpec;
 import org.lamport.tla.toolbox.ui.provider.IGroup;
 import org.lamport.tla.toolbox.util.UIHelper;
@@ -52,40 +51,7 @@ public class ModelContentProvider implements ITreeContentProvider {
 	private static final Object[] EMPTY_ARRAY = new Object[0];
 	
 	private final Map<Model, Group> reverse = new HashMap<Model, Group>();
-	private final MyStateChangeListener modelChangeListener = new MyStateChangeListener() {
-		@Override
-		public boolean handleChange(final ChangeEvent event) {
-			if (event.getState() == State.DELETED) {
-				UIHelper.runUISync(new Runnable() {
-					@Override
-					public void run() {
-						final Model model = event.getModel();
-						// getViewer().remove(...) internally (see
-						// org.eclipse.jface.viewers.StructuredViewer.findItems(Object)) tries to find
-						// the TreeItem corresponding to Spec (not TLCSpec). TLCSpec just wraps Spec but
-						// does not exist in the SpecExplorers content tree. With TLCSpec setSelection
-						// and remove are actually (silent) no-ops.
-						final Spec parent = model.getSpec().toSpec();
-						// The CommonViewer is stupid in that it accesses an element (model) even
-						// after it has been removed in order to update the viewer's current selection.
-						// Since we have to prevent this access to avoid a null pointer, we explicitly
-						// reset the selection.
-						getViewer().setSelection(new StructuredSelection(parent));
-						// ...still remove the element from the tree.
-						getViewer().remove(parent, new Object[] {model});
-					}
-				});
-			} else if (event.getState() == State.REMOTE_NOT_RUNNING) {
-				UIHelper.runUISync(new Runnable() {
-					@Override
-					public void run() {
-						getViewer().refresh(event.getModel(), true);			
-					}
-				});
-			}
-			return true;
-		}
-	};
+	private final MyStateChangeListener modelChangeListener = new MyStateChangeListener();
 	
 	public Object[] getChildren(final Object parentElement) {
 		if (parentElement instanceof Spec) {
@@ -148,21 +114,55 @@ public class ModelContentProvider implements ITreeContentProvider {
 		this.modelChangeListener.setViewer((CommonViewer) viewer);
 	}
 	
-	private static class MyStateChangeListener extends StateChangeListener {
+	
+	private static class MyStateChangeListener extends AbstractModelStateChangeListener {
 
 		private CommonViewer viewer;
 
-		public void setViewer(CommonViewer viewer) {
+		public void setViewer(final CommonViewer viewer) {
 			this.viewer = viewer;
 		}
 		
 		public CommonViewer getViewer() {
 			return viewer;
 		}
+		
+		@Override
+		public boolean handleChange(final ChangeEvent event) {
+			if (event.getState() == State.DELETED) {
+				UIHelper.runUISync(new Runnable() {
+					@Override
+					public void run() {
+						final Model model = event.getModel();
+						// getViewer().remove(...) internally (see
+						// org.eclipse.jface.viewers.StructuredViewer.findItems(Object)) tries to find
+						// the TreeItem corresponding to Spec (not TLCSpec). TLCSpec just wraps Spec but
+						// does not exist in the SpecExplorers content tree. With TLCSpec setSelection
+						// and remove are actually (silent) no-ops.
+						final Spec parent = model.getSpec().toSpec();
+						// The CommonViewer is stupid in that it accesses an element (model) even
+						// after it has been removed in order to update the viewer's current selection.
+						// Since we have to prevent this access to avoid a null pointer, we explicitly
+						// reset the selection.
+						getViewer().setSelection(new StructuredSelection(parent));
+						// ...still remove the element from the tree.
+						getViewer().remove(parent, new Object[] {model});
+					}
+				});
+			} else if (event.getState() == State.REMOTE_NOT_RUNNING) {
+				UIHelper.runUISync(new Runnable() {
+					@Override
+					public void run() {
+						getViewer().refresh(event.getModel(), true);			
+					}
+				});
+			}
+			return true;
+		}
 	}
 
+	
 	public static final class Group implements IGroup {
-		
 		private final Model[] models;
 		private final Spec spec;
 		
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/SavedModuleContributionItem.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/SavedModuleContributionItem.java
index 8aca444dc19b244411ba37e1b142a141849435ab..ffb06280e501f42160a1795d33353427ab0b2f39 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/SavedModuleContributionItem.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/SavedModuleContributionItem.java
@@ -21,6 +21,8 @@ import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper;
 import org.lamport.tla.toolbox.util.ResourceHelper;
 import org.lamport.tla.toolbox.util.UIHelper;
 
+import util.TLAConstants;
+
 /**
  * This class is used to populate a menu with items that represent the versions
  * of modules saved in a run of TLC. Selecting an item opens the module in a
@@ -82,7 +84,7 @@ public class SavedModuleContributionItem extends CompoundContributionItem
                          */
                         if (members[i].exists() && members[i].getFileExtension() != null
                                 && members[i].getFileExtension().equals(ResourceHelper.TLA_EXTENSION)
-                                && !members[i].getName().equals(ModelHelper.FILE_TLA)
+                                && !members[i].getName().equals(TLAConstants.Files.MODEL_CHECK_TLA_FILE)
                                 && !members[i].getName().equals(ModelHelper.TE_FILE_TLA))
                         {
                             Map<String, String> parameters = new HashMap<String, String>(1);
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/ITLCPreferenceConstants.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/ITLCPreferenceConstants.java
index 477698bff5cd293d179f4ffde27fc8458cfc80be..2f14dc704fa8a4a407bc94305981d8b884130a0e 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/ITLCPreferenceConstants.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/ITLCPreferenceConstants.java
@@ -51,12 +51,6 @@ public interface ITLCPreferenceConstants {
 	 * old behavior prior to the change in https://bugs.eclipse.org/146205#c10.
 	 */
 	public static final String I_TLC_SHOW_MODAL_PROGRESS = "showModalProgress";
-	/**
-     * TODO this is not TLC - this is model editor
-     * 
-	 * If set, the Evaluate Constant Expressions section of the Results page will be shown in its own model editor tab.
-	 */
-	public static final String I_TLC_SHOW_ECE_AS_TAB = "showECEAsTab";
     // /**
     // * Delete data (.st files and unused checkpoints) from the previous run)
     // */
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferenceInitializer.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferenceInitializer.java
index 69ef319b9946bb404dd0bd40d093d4acee94c539..abaf0f92a4ae254c326e10f7d8c19eb70bd0425a 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferenceInitializer.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferenceInitializer.java
@@ -41,7 +41,6 @@ public class TLCPreferenceInitializer extends AbstractPreferenceInitializer
         uiPreferencesStore.setDefault(ITLCPreferenceConstants.I_TLC_TRACE_MAX_SHOW_ERRORS, 10000);
         uiPreferencesStore.setDefault(ITLCPreferenceConstants.I_TLC_POPUP_ERRORS, true);
         uiPreferencesStore.setDefault(ITLCPreferenceConstants.I_TLC_REVALIDATE_ON_MODIFY, true);
-        uiPreferencesStore.setDefault(ITLCPreferenceConstants.I_TLC_SHOW_ECE_AS_TAB, false);
         uiPreferencesStore.setDefault(ITLCPreferenceConstants.I_TLC_DEFAULT_WORKERS_COUNT,
         							  TLCConsumptionProfile.LOCAL_NORMAL.getWorkerThreads());
         uiPreferencesStore.setDefault(ITLCPreferenceConstants.I_TLC_MAXIMUM_HEAP_SIZE_DEFAULT, MAX_HEAP_SIZE_DEFAULT);
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferencePage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferencePage.java
index 7e2d1f99b337836032222f8246a455cdd8bbb56b..db5554a4821f92befc409f7c7e6b2734e8fe824b 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferencePage.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferencePage.java
@@ -60,9 +60,6 @@ public class TLCPreferencePage extends FieldEditorPreferencePage implements IWor
         addField(new BooleanFieldEditor(ITLCPreferenceConstants.I_TLC_REVALIDATE_ON_MODIFY,
                 "&Re-validate model on save", getFieldEditorParent()));
 
-        addField(new BooleanFieldEditor(ITLCPreferenceConstants.I_TLC_SHOW_ECE_AS_TAB,
-                "Show Evaluate Constant Expression in its own tab", getFieldEditorParent()));
-
         IntegerFieldEditor integerFieldEditor = new IntegerFieldEditor(TLCActivator.I_TLC_SNAPSHOT_KEEP_COUNT,
                                                                        "Number of model &snapshots to keep",
                                                                        getFieldEditorParent());
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ExecutionStatisticsDialog.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ExecutionStatisticsDialog.java
index 69abb7951836d7037432f3b30e1aa460d0b32ee8..c00ebac9a772f6e8f7840dda1af9edf52cfac778 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ExecutionStatisticsDialog.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ExecutionStatisticsDialog.java
@@ -63,9 +63,12 @@ public class ExecutionStatisticsDialog extends MessageDialog {
 	
 	private final ExecutionStatisticsCollector esc = new ExecutionStatisticsCollector();
 
-	public ExecutionStatisticsDialog(final Shell parentShell) {
+	private final boolean isUserTriggered;
+
+	public ExecutionStatisticsDialog(boolean isUserTriggered, final Shell parentShell) {
 		super(parentShell, "TLA+ execution statistics", (Image) null, "The TLA+ project needs your help!",
 				MessageDialog.QUESTION, new String[0], 0);
+		this.isUserTriggered = isUserTriggered;
 		
 		// Do not block the Toolbox's main window.
 		setShellStyle(getShellStyle() ^ SWT.APPLICATION_MODAL | SWT.MODELESS);
@@ -85,18 +88,25 @@ public class ExecutionStatisticsDialog extends MessageDialog {
         buttons[2] = createButton(parent, 2, "&Never Share\nExecution Statistics", false);
         buttons[2].setData(KEY, ExecutionStatisticsCollector.Selection.NO_ESC);
         
-        // Disable the button for the currently active selection. 
-        final Selection selection = esc.get();
-        switch (selection) {
-		case ON:
-			buttons[0].setEnabled(false);
-			break;
-		case RANDOM_IDENTIFIER:
-			buttons[1].setEnabled(false);
-			break;
-		case NO_ESC:
-			buttons[2].setEnabled(false);
-		}
+		// Disable the button for the currently active selection to indicate the state
+		// if this dialog is (explicitly) triggered by the user due to clicking the menu
+		// item.
+		// However, if this dialog is automatically opened by a fresh Toolbox install,
+		// we don't indicate the state. Technically the state is NO_ESC but the UI gives
+		// the impression it is impossible to disable exec stats.
+        if (isUserTriggered) {
+        	final Selection selection = esc.get();
+        	switch (selection) {
+        	case ON:
+        		buttons[0].setEnabled(false);
+        		break;
+        	case RANDOM_IDENTIFIER:
+        		buttons[1].setEnabled(false);
+        		break;
+        	case NO_ESC:
+        		buttons[2].setEnabled(false);
+        	}
+        }
         
         setButtons(buttons);
     }
@@ -131,6 +141,7 @@ public class ExecutionStatisticsDialog extends MessageDialog {
 		c.setLayout(new GridLayout());
 		c.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
 		
+		//NOTE: Take care of ExecutionStatisticsCollector.md when updating!!!
 		final String txt = String.format("%s"
 				+ "* Total number of cores and cores assigned to TLC\n"
 				+ "* Heap and off-heap memory allocated to TLC\n"
@@ -154,16 +165,21 @@ public class ExecutionStatisticsDialog extends MessageDialog {
 		st.setEditable(false);
 		st.setText(txt);
 		
-		final StyleRange[] ranges = new StyleRange[2];
+		final StyleRange[] ranges = new StyleRange[3];
 		ranges[0] = new StyleRange(txt.indexOf("(TLC) execution statistics"), "(TLC) execution statistics".length(), null, null);
 		ranges[0].underline = true;
 		ranges[0].underlineStyle = SWT.UNDERLINE_LINK;
 		ranges[0].data = "https://exec-stats.tlapl.us";
-				
-		ranges[1] = new StyleRange(txt.indexOf("git commit SHA"), "git commit SHA".length(), null, null);
+		
+		ranges[1] = new StyleRange(txt.indexOf("publicly available"), "publicly available".length(), null, null);
 		ranges[1].underline = true;
 		ranges[1].underlineStyle = SWT.UNDERLINE_LINK;
-		ranges[1].data = "https://git-scm.com/book/en/v2/Git-Internals-Git-Objects";
+		ranges[1].data = "https://exec-stats.tlapl.us/tlaplus.csv";
+				
+		ranges[2] = new StyleRange(txt.indexOf("git commit SHA"), "git commit SHA".length(), null, null);
+		ranges[2].underline = true;
+		ranges[2].underlineStyle = SWT.UNDERLINE_LINK;
+		ranges[2].data = "https://git-scm.com/book/en/v2/Git-Internals-Git-Objects";
 
 		st.setStyleRanges(ranges);
 		st.addMouseListener(new MouseAdapter() {
@@ -191,12 +207,14 @@ public class ExecutionStatisticsDialog extends MessageDialog {
 		switch (esc.get()) {
 		case ON:
 			return String.format(
-					"Thank you for sharing (TLC) execution statistics with installation identifier\n%s.\n\nExecution Statistics help us make informed decisions about future research and\ndevelopment directions. Execution statistics contain the following information:\n\n",
+					"Thank you for sharing (TLC) execution statistics with installation identifier\n%s.\n\nExecution Statistics help us make informed decisions about future research and\ndevelopment directions. Execution statistics are made publicly available on the\nweb and contain the following information:\n\n",
 					esc.getIdentifier());
 		case RANDOM_IDENTIFIER:
-			return "Thank you for sharing (TLC) execution statistics. Execution Statistics help us\nmake informed decisions about future research anddevelopment directions.\nExecution statistics contain the following information:\n\n";
+			return "Thank you for sharing (TLC) execution statistics. Execution Statistics help us\nmake informed decisions about future research and development directions.\nExecution statistics are made publicly available on the web and contain the\nfollowing information:\n\n";
 		}
-		return "Please opt-in and share (TLC) execution statistics. Execution statistics contain\nthe following information:\n\n";
+		return "Please opt-in and share (TLC) execution statistics. "
+				+ "Execution statistics are made\npublicly available on the web "
+				+ "and contain the following information:\n\n";
 	}
 
 	@Override
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ExecutionStatisticsHandler.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ExecutionStatisticsHandler.java
index 7341fe4de9ac1e0aed44a46b4e9e8d7621c9b717..9f308d2b84c3b8fb31f0198206f58757f52491fa 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ExecutionStatisticsHandler.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ExecutionStatisticsHandler.java
@@ -37,7 +37,7 @@ public class ExecutionStatisticsHandler extends AbstractHandler {
 	 */
 	@Override
 	public Object execute(ExecutionEvent event) throws ExecutionException {
-		new ExecutionStatisticsDialog(HandlerUtil.getActiveShellChecked(event)).open();
+		new ExecutionStatisticsDialog(true, HandlerUtil.getActiveShellChecked(event)).open();
 		return null;
 	}
 }
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/FormHelper.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/FormHelper.java
index 6c6a8f58eecfd869816b7ab5c163a9fd4a042982..c551bf2e45fc711484fc7886f1560238c8e18bfa 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/FormHelper.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/FormHelper.java
@@ -27,11 +27,12 @@ import org.eclipse.ui.forms.widgets.FormToolkit;
 import org.eclipse.ui.forms.widgets.Hyperlink;
 import org.eclipse.ui.forms.widgets.Section;
 import org.eclipse.ui.forms.widgets.TableWrapLayout;
-import org.lamport.tla.toolbox.tool.tlc.model.Assignment;
-import org.lamport.tla.toolbox.tool.tlc.model.Formula;
 import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
 import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper;
 
+import tlc2.model.Assignment;
+import tlc2.model.Formula;
+
 /**
  * A utility class containing a bunch of static methods used in the form editor
  * @author Simon Zambrovski
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ITLAReserveredWords.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ITLAReserveredWords.java
index 5f7826336c1d9eb567a2668dd23e8825a183aaf4..cdd1bf54104f7c955857d0f4b464166bf0b36185 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ITLAReserveredWords.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ITLAReserveredWords.java
@@ -4,11 +4,12 @@ import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
 
+import util.TLAConstants;
+
 /**
  * TLA+ Reserved words
  * TODO complete the word list
  * @author Simon Zambrovski, <a href="http://simon.zambrovski.org">http://simon.zambrovski.org</a> 
- * @version $Id: ITLAReserveredWords.java,v 1.1 2005/08/22 15:43:33 szambrovski Exp $
  */
 public interface ITLAReserveredWords
 {
@@ -17,8 +18,8 @@ public interface ITLAReserveredWords
     public final static String AXIOM = "AXIOM";
     public final static String CASE = "CASE";
     public final static String CHOOSE = "CHOOSE";
-    public final static String CONSTANT = "CONSTANT";
-    public final static String CONSTANTS = "CONSTANTS";
+    public final static String CONSTANT = TLAConstants.KeyWords.CONSTANT;
+    public final static String CONSTANTS = TLAConstants.KeyWords.CONSTANTS;
     public final static String DOMAIN = "DOMAIN";
     public final static String ELSE = "ELSE";
     public final static String ENABLED = "ENABLED";
@@ -37,8 +38,8 @@ public interface ITLAReserveredWords
     public final static String THEOREM = "THEOREM";
     public final static String UNCHANGED = "UNCHANGED";
     public final static String UNION = "UNION";
-    public final static String VARIABLE = "VARIABLE";
-    public final static String VARIABLES = "VARIABLES";
+    public final static String VARIABLE = TLAConstants.KeyWords.VARIABLE;
+    public final static String VARIABLES = VARIABLE + "S";
     public final static String WF_ = "WF_";
     public final static String WITH = "WITH";
 
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ModelEditorPartListener.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ModelEditorPartListener.java
index d006948547affd7fd77ca6ba543c0250c56e749f..7e97db3874f27b1a7f04db3998213e8549484ffe 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ModelEditorPartListener.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/ModelEditorPartListener.java
@@ -24,7 +24,6 @@ import org.lamport.tla.toolbox.util.UIHelper;
  * a singleton.
  * 
  * @author Dan Ricketts
- *
  */
 public class ModelEditorPartListener implements IPartListener2
 {
@@ -73,16 +72,14 @@ public class ModelEditorPartListener implements IPartListener2
      * If the model editor made visible does have errors, then the error
      * view is updated with these errors.
      */
-	public void partVisible(final IWorkbenchPartReference partRef)
-    {
+	public void partVisible(final IWorkbenchPartReference partRef) {
         final IWorkbenchPart part = partRef.getPart(false);
         
-		if (part != null && part instanceof ModelEditor) {
+		if ((part != null) && (part instanceof ModelEditor)) {
 			final ModelEditor editor = (ModelEditor) part;
-			TLCModelLaunchDataProvider provider = null;
+			final TLCModelLaunchDataProvider provider;
 
 			final Model model = editor.getModel();
-
 			if (model.isOriginalTraceShown()) {
 				provider = TLCOutputSourceRegistry.getModelCheckSourceRegistry().getProvider(model);
 			} else {
@@ -90,7 +87,7 @@ public class ModelEditorPartListener implements IPartListener2
 			}
 
 			final TLCErrorView errorView = (TLCErrorView) UIHelper.findView(TLCErrorView.ID);
-			if (errorView != null && provider != null) {
+			if ((errorView != null) && (provider != null)) {
 				if (provider.getErrors().size() > 0) {
 					// Tell the TLCErrorView update function to not open the
 					// TLCErrorView iff the ModelEditor and the TLCErrorView
@@ -107,12 +104,11 @@ public class ModelEditorPartListener implements IPartListener2
 			    	// 3) Run the model
 			    	// 4) Cycle focus
 					// 5) Bam!
-					TLCErrorView.updateErrorView(model, !UIHelper.isInSameStack(editor, TLCErrorView.ID));
+					TLCErrorView.updateErrorView(editor, !UIHelper.isInSameStack(editor, TLCErrorView.ID));
 				} else {
 					errorView.clear();
 				}
 			}
 		}
     }
-
 }
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/RecordToSourceCoupler.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/RecordToSourceCoupler.java
index cbf422d309bc5b20a7ded45775954e7bbdb84993..c00db2d57ccc6a63c9a75edd177708ceec3ea5d3 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/RecordToSourceCoupler.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/RecordToSourceCoupler.java
@@ -21,6 +21,7 @@ import org.eclipse.ui.texteditor.ITextEditor;
 import org.lamport.tla.toolbox.tool.ToolboxHandle;
 import org.lamport.tla.toolbox.tool.tlc.model.Model;
 import org.lamport.tla.toolbox.tool.tlc.model.TLCSpec;
+import org.lamport.tla.toolbox.tool.tlc.output.data.ActionInformationItem;
 import org.lamport.tla.toolbox.tool.tlc.output.data.TLCError;
 import org.lamport.tla.toolbox.tool.tlc.output.data.TLCState;
 import org.lamport.tla.toolbox.util.UIHelper;
@@ -165,7 +166,26 @@ public class RecordToSourceCoupler implements MouseListener, KeyListener {
 					});
 				} else if (firstElement instanceof IModuleLocatable) {
 					final IModuleLocatable moduleLocatable = (IModuleLocatable) firstElement;
-					final Location location = moduleLocatable.getModuleLocation();
+					Location location = moduleLocatable.getModuleLocation();
+					if (moduleLocatable instanceof ActionInformationItem) {
+						ActionInformationItem aii = (ActionInformationItem) moduleLocatable;
+						if (aii.hasDefinition()) {
+							// Do not jump to a sub-actions identifier but to its actual definition if a
+							// sub-action has a definition. Consider this partial spec:
+							// ...
+							// Next == \/ /\ x = 42
+							//            /\ x' = 23
+							//         \/ /\ x = 23
+							//            /\ x' = 4711
+							// ...
+						    // getModuleLocation called on the ActionInformationItem for sub-action
+							// "x = 42 /\ x' = 23" returns the location of  "x = 42 /\ x' = 23" and not
+							// that of "Next".
+							// This relevant in the Sub-actions for next-state table of the Model Checking
+							// Results page.
+							location = aii.getDefinition();
+						}
+					}
 					if (location != null) {
 						/*
 						 * jumpToNested will be true if the location could be
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/TLCUIHelper.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/TLCUIHelper.java
index 31b2ccec4c371da286e4078d88a160f8cb19cacf..4ec06468e9281f2694e9682f03150aa9d598c284 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/TLCUIHelper.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/TLCUIHelper.java
@@ -29,6 +29,7 @@ import org.lamport.tla.toolbox.util.AdapterFactory;
 import org.lamport.tla.toolbox.util.UIHelper;
 
 import tla2sany.st.Location;
+import util.TLAConstants;
 import util.UniqueString;
 
 public class TLCUIHelper
@@ -107,7 +108,7 @@ public class TLCUIHelper
                 final Location location = Location.parseLocation(locationString);
                 if ((location != null)
                 		&& !location.equals(Location.nullLoc)
-                        && !location.source().equals(ModelHelper.MC_MODEL_NAME)
+                        && !location.source().equals(TLAConstants.Files.MODEL_CHECK_FILE_BASENAME)
                         && !location.source().equals(ModelHelper.TE_MODEL_NAME)) {
                     moduleName = location.source();
                     result.add(getHyperlinkStyleRange(location, matcher.start(), matcher.end()));
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/view/ErrorTraceTreeViewer.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/view/ErrorTraceTreeViewer.java
new file mode 100644
index 0000000000000000000000000000000000000000..6ec3a1b0cab18394c504db1745a5e0507ed2d140
--- /dev/null
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/view/ErrorTraceTreeViewer.java
@@ -0,0 +1,769 @@
+package org.lamport.tla.toolbox.tool.tlc.ui.view;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.resource.FontRegistry;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.viewers.CellLabelProvider;
+import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
+import org.eclipse.jface.viewers.ILazyTreeContentProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.TreeViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.swt.widgets.Scrollable;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.lamport.tla.toolbox.Activator;
+import org.lamport.tla.toolbox.editor.basic.TLAEditorActivator;
+import org.lamport.tla.toolbox.tool.tlc.TLCActivator;
+import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants;
+import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationDefaults;
+import org.lamport.tla.toolbox.tool.tlc.model.Model;
+import org.lamport.tla.toolbox.tool.tlc.output.data.TLCError;
+import org.lamport.tla.toolbox.tool.tlc.output.data.TLCFcnElementVariableValue;
+import org.lamport.tla.toolbox.tool.tlc.output.data.TLCFunctionVariableValue;
+import org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider;
+import org.lamport.tla.toolbox.tool.tlc.output.data.TLCMultiVariableValue;
+import org.lamport.tla.toolbox.tool.tlc.output.data.TLCNamedVariableValue;
+import org.lamport.tla.toolbox.tool.tlc.output.data.TLCRecordVariableValue;
+import org.lamport.tla.toolbox.tool.tlc.output.data.TLCSequenceVariableValue;
+import org.lamport.tla.toolbox.tool.tlc.output.data.TLCSetVariableValue;
+import org.lamport.tla.toolbox.tool.tlc.output.data.TLCSimpleVariableValue;
+import org.lamport.tla.toolbox.tool.tlc.output.data.TLCState;
+import org.lamport.tla.toolbox.tool.tlc.output.data.TLCVariable;
+import org.lamport.tla.toolbox.tool.tlc.output.data.TLCVariableValue;
+import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
+import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor;
+import org.lamport.tla.toolbox.tool.tlc.ui.editor.page.MainModelPage;
+import org.lamport.tla.toolbox.tool.tlc.ui.preference.ITLCPreferenceConstants;
+import org.lamport.tla.toolbox.tool.tlc.ui.util.RecordToSourceCoupler;
+import org.lamport.tla.toolbox.tool.tlc.ui.util.RecordToSourceCoupler.LoaderTLCState;
+
+import tla2sany.st.Location;
+
+/**
+ * {@link TLCErrorView} was becoming a bit of a behemoth, so we're spinning out this chunk into its own class and inner
+ * 	classes.
+ */
+class ErrorTraceTreeViewer {
+    private static final int[] COLUMN_WIDTH = { 200, 200 };
+    private static final String[] COLUMN_TEXTS = { "Name", "Value" };
+
+	private static final String LOADER_TOOL_TIP
+			= "Double-click to load more states.\nIf the number of states is large, this might take a few seconds.";
+
+    
+	private final TreeViewer treeViewer;
+	
+    // listener on changes to the error trace font preference
+    private final IPropertyChangeListener errorTraceFontChangeListener;
+    
+    private ModelEditor modelEditor;
+	
+	ErrorTraceTreeViewer(final Tree parent, final ModelEditor associatedModelEditor) {
+		treeViewer = new TreeViewer(parent);
+		treeViewer.setUseHashlookup(true);
+		treeViewer.setContentProvider(new StateContentProvider());
+		ColumnViewerToolTipSupport.enableFor(treeViewer);
+
+		final TraceDisplayResizer resizer = new TraceDisplayResizer(parent);
+		final StateLabelProvider labelProvider = new StateLabelProvider();
+		for (int i = 0; i < COLUMN_TEXTS.length; i++) {
+			final TreeViewerColumn column = new TreeViewerColumn(treeViewer, i);
+			column.getColumn().setText(COLUMN_TEXTS[i]);
+			column.getColumn().setWidth(COLUMN_WIDTH[i]);
+			column.setLabelProvider(labelProvider);
+			resizer.setColumnForIndex(column, i);
+			column.getColumn().addSelectionListener(new SelectionAdapter() {
+				public void widgetSelected(final SelectionEvent e) {
+					// reverse the current trace
+					final TLCError error = (TLCError) treeViewer.getInput();
+					error.reverseTrace();
+					// Reset the viewer's selection to the empty selection. With empty
+					// selection, the subsequent refresh call does *not* invalidate the
+					// StateContentProvider's lazy policy.
+					// We know that the user clicked on the tree's column header
+					// and the real selection is of little importance.
+					treeViewer.setSelection(new ISelection() {
+						public boolean isEmpty() {
+							return true;
+						}
+					});
+					treeViewer.refresh(false);
+					
+					// remember the order for next trace shown
+					final IDialogSettings dialogSettings = Activator.getDefault().getDialogSettings();
+					dialogSettings.put(TLCModelLaunchDataProvider.STATESORTORDER,
+							!dialogSettings.getBoolean(TLCModelLaunchDataProvider.STATESORTORDER));
+				}
+			});
+		}
+		
+        parent.addControlListener(resizer);
+		
+		errorTraceFontChangeListener = (event) -> {
+			if ((event == null) || event.getProperty().equals(ITLCPreferenceConstants.I_TLC_ERROR_TRACE_FONT)) {
+				final Font f = JFaceResources.getFont(ITLCPreferenceConstants.I_TLC_ERROR_TRACE_FONT);
+				
+				JFaceResources.getFontRegistry().put(TLCErrorView.JFACE_ERROR_TRACE_ID, f.getFontData());
+
+				if (treeViewer != null) {
+					treeViewer.refresh(true);
+				}
+			}
+		};
+		errorTraceFontChangeListener.propertyChange(null);
+        JFaceResources.getFontRegistry().addListener(errorTraceFontChangeListener);
+        
+        createContextMenu();
+        
+        setModelEditor(associatedModelEditor);
+	}
+	
+	void dispose() {
+		final FontRegistry fr = JFaceResources.getFontRegistry();
+		
+        fr.removeListener(errorTraceFontChangeListener);
+	}
+	
+	void setModelEditor(final ModelEditor associatedModelEditor) {
+		modelEditor = associatedModelEditor;
+	}
+	
+	/**
+	 * @return the {@link TreeViewer} instance wrapped by this class
+	 */
+	TreeViewer getTreeViewer() {
+		return treeViewer;
+	}
+	
+	TLCError getCurrentTrace() {
+		return (TLCError)treeViewer.getInput();
+	}
+	
+	private void createContextMenu() {
+	    final MenuManager contextMenu = new MenuManager("#ViewerMenu"); //$NON-NLS-1$
+	    contextMenu.setRemoveAllWhenShown(true);
+	    contextMenu.addMenuListener(new IMenuListener() {
+	        @Override
+	        public void menuAboutToShow(final IMenuManager menuManager) {
+				final Object selection = ((IStructuredSelection)treeViewer.getSelection()).getFirstElement();
+				if (selection instanceof TLCState) {
+		        	menuManager.add(new Action("Run model from this point") {
+		    	        @Override
+		    	        public void run() {
+		    	        	if (modelEditor != null) {
+		    	        		final Model m = modelEditor.getModel();
+		    	        		
+		    	        		if (m != null) {
+									try {
+										final int specType = m.getAttribute(
+												IModelConfigurationConstants.MODEL_BEHAVIOR_SPEC_TYPE,
+												IModelConfigurationDefaults.MODEL_BEHAVIOR_TYPE_DEFAULT);
+
+										if (specType == IModelConfigurationDefaults.MODEL_BEHAVIOR_TYPE_NO_SPEC) {
+											return;
+										}
+										
+										final String init = ((TLCState) selection).getConjunctiveDescription(false);
+										final String next;
+										if (specType == IModelConfigurationDefaults.MODEL_BEHAVIOR_TYPE_SPEC_CLOSED) {
+											next = m.getAttribute(
+													IModelConfigurationConstants.MODEL_BEHAVIOR_CLOSED_SPECIFICATION,
+													"");
+										} else {
+											next = null;
+										}
+										final MainModelPage page = (MainModelPage)modelEditor.findPage(MainModelPage.ID);
+										page.setInitNextBehavior(init, next);
+										modelEditor.setActivePage(MainModelPage.ID);
+										
+										Display.getDefault().asyncExec(() -> {
+											MessageDialog.openInformation(null, "Model Reconfigured",
+													"The model has been set up to begin checking from the selected "
+														+ "state; please review the model parameters and run the checker.");
+										});										
+
+		// We previously handled the config alteration and model check launch behind the
+		//	scenes but have since stopped doing that. I'm leaving a portion of this here,
+		//	commented out, in case we decide to return to that workflow.
+//										final StringBuilder constraint = new StringBuilder();
+//										if (specType == IModelConfigurationDefaults.MODEL_BEHAVIOR_TYPE_SPEC_CLOSED) {
+//											final String temporalSpecification = m.getAttribute(IModelConfigurationConstants.MODEL_BEHAVIOR_CLOSED_SPECIFICATION, "");
+//										}
+//										
+//										constraint.append(((TLCState) selection).getConjunctiveDescription(false));
+//
+//										m.setAttribute(IModelConfigurationConstants.MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT, constraint.toString());
+//										m.save(null);
+//
+//										modelEditor.launchModel(TLCModelLaunchDelegate.MODE_MODELCHECK, true);
+		    	        			} catch (final CoreException e) {
+		    	        				TLCActivator.logError("Problem encountered attempting to launch checker.", e);
+		    	        			}
+		    	        		}
+		    	        	} else {
+		    	        		TLCActivator.logInfo(
+		    	        				"Were not able to launch ammended model because we have no model editor.");
+		    	        	}
+		    	        }
+		    	    });
+				}
+	        	/*
+	        	  In earlier versions of the Toolbox, we also provided:
+	        	  		Collapse All (treeViewer.collapseAll())
+	        	  		Expand to default level (treeViewer.collapseAll(); treeViewer.expandToLevel(2);)
+	        	  		Expand All (treeViewer.expandAll())
+	        	  But we now provide expand and collapse through the parent section's toolbar
+	        	 */
+	        }
+	    });
+
+	    final Control c = treeViewer.getControl();
+	    final Menu menu = contextMenu.createContextMenu(c);
+	    c.setMenu(menu);
+	}
+
+	
+    private class StateContentProvider implements ILazyTreeContentProvider {
+		private List<TLCState> states;
+		private final int numberOfStatesToShow;
+
+		StateContentProvider() {
+			states = new ArrayList<>(0);
+			
+			numberOfStatesToShow = TLCUIActivator.getDefault().getPreferenceStore()
+					.getInt(ITLCPreferenceConstants.I_TLC_TRACE_MAX_SHOW_ERRORS);
+    	}
+
+		@Override
+		public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) {
+			// Eagerly cache the list of states as it can be a sublist of the
+			// complete trace. Getting the sublist in the updateElement method
+			// means we obtain it over and over again for each top-level tree
+			// item.
+			if (newInput instanceof TLCError) {
+				this.states = ((TLCError) newInput).getStates();
+			} else if (newInput == null) {
+				this.states = new ArrayList<TLCState>(0);
+			} else {
+				throw new IllegalArgumentException();
+			}
+		}
+
+		@Override
+		public void updateElement(final Object parent, final int viewerIndex) {
+			if (parent instanceof TLCError) {
+				final TLCError error = (TLCError) parent;
+				if (error.isTraceRestricted() && (viewerIndex == 0)) {
+					// If only a subset of the trace is shown, show a dummy item
+					// at the top which can be double-clicked to load more.
+					treeViewer.replace(parent, viewerIndex, new RecordToSourceCoupler.LoaderTLCState(treeViewer,
+							Math.min(numberOfStatesToShow, error.getNumberOfRestrictedTraceStates()), error));
+					return;
+				}
+				
+				// decrease index into states by one if the viewers first element is a dummy item
+				final int statesIndex = viewerIndex - (error.isTraceRestricted() ? 1 : 0);
+				final TLCState child = states.get(statesIndex);
+				// Diffing is supposed to be lazy and thus is done here when
+				// the state is first used by the viewer. The reason why it
+				// has to be lazy is to be able to efficiently handle traces
+				// with hundreds or thousands of states where it would be a
+				// waste to diff all state pairs even if the user is never
+				// going to look at all states anyway.
+				// TODO If ever comes up as a performance problem again, the
+				// nested TLCVariableValues could also be diffed lazily.
+           		if (statesIndex > 0) {
+           			final TLCState predecessor = states.get(statesIndex - 1);
+           			predecessor.diff(child);
+           		}
+				treeViewer.replace(parent, viewerIndex, child);
+				// Always setHashChildren even if child has no children: This is
+				// a virtual table here meaning that it reduces the number of
+				// table items at the OS level by recycling them (the OS only
+				// creates a many items that fit into the visible area). If an
+				// item showing a regular state, is later recycled by a "back to
+				// state" or "stuttering" indicator (neither has children),
+				// the OS still incorrectly assumes the item has children. This
+				// crashes hard on Linux and results in erratic behavior on
+				// Windows and Mac.
+				treeViewer.setHasChildren(child, child.getVariablesAsList().size() > 0);
+				// Lazily expand the children
+				if (child.isExpandable()){
+					treeViewer.expandToLevel(child, 1);
+				}
+			} else if (parent instanceof TLCState) {
+				final TLCState state = (TLCState) parent;
+                if ((state.isStuttering() || state.isBackToState())) {
+                	treeViewer.setChildCount(state, 0);
+                } else {
+                	final List<TLCVariable> variablesAsList = state.getVariablesAsList();
+                	if (variablesAsList.size() > viewerIndex) {
+                		final TLCVariable child = variablesAsList.get(viewerIndex);
+                		treeViewer.replace(parent, viewerIndex, child);
+                		treeViewer.setHasChildren(child, child.getChildCount() > 0);
+                	}
+                }
+			} else if (parent instanceof TLCVariable
+					&& ((TLCVariable) parent).getValue() instanceof TLCMultiVariableValue) {
+				final TLCMultiVariableValue multiValue = (TLCMultiVariableValue) ((TLCVariable) parent).getValue();
+				final TLCVariableValue child = multiValue.asList().get(viewerIndex);
+				treeViewer.replace(parent, viewerIndex, child);
+				treeViewer.setHasChildren(child, child.getChildCount() > 0);
+			} else if (parent instanceof TLCVariable) {
+				final TLCVariable variable = (TLCVariable) parent;
+				final TLCVariableValue child = variable.getValue();
+				treeViewer.replace(parent, viewerIndex, child);
+				treeViewer.setChildCount(child, child.getChildCount());
+			} else if (parent instanceof TLCMultiVariableValue) {
+				final TLCMultiVariableValue multiValue = (TLCMultiVariableValue) parent;
+				final TLCVariableValue child = multiValue.asList().get(viewerIndex);
+				treeViewer.replace(parent, viewerIndex, child);
+				treeViewer.setHasChildren(child, child.getChildCount() > 0);
+			} else if (parent instanceof TLCVariableValue
+					&& ((TLCVariableValue) parent).getValue() instanceof TLCMultiVariableValue) {
+				final TLCMultiVariableValue multiValue = (TLCMultiVariableValue) ((TLCVariableValue) parent).getValue();
+				final TLCVariableValue child = multiValue.asList().get(viewerIndex);
+				treeViewer.replace(parent, viewerIndex, child);
+				treeViewer.setHasChildren(child, child.getChildCount() > 0);
+			} else {
+				throw new IllegalArgumentException();
+			}
+		}
+
+		@Override
+		public void updateChildCount(Object element, int currentChildCount) {
+			if (element instanceof TLCError) {
+				final TLCError error = (TLCError) element;
+				int traceSize = error.getTraceSize();
+				if (traceSize != currentChildCount) {
+					if (error.isTraceRestricted()) {
+						treeViewer.setChildCount(element, traceSize + 1);
+					} else {
+						treeViewer.setChildCount(element, traceSize);
+					}
+				}
+			} else if (element instanceof TLCState) {
+				final TLCState state = (TLCState) element;
+				if (((state.isStuttering() || state.isBackToState()) && currentChildCount != 0)) {
+					treeViewer.setChildCount(element, 0);
+				} else if (currentChildCount != state.getVariablesAsList().size()) {
+					treeViewer.setChildCount(element, state.getVariablesAsList().size());
+				}
+			} else if (element instanceof TLCVariable) {
+				final TLCVariable variable = (TLCVariable) element;
+				if (currentChildCount != variable.getChildCount()) {
+					treeViewer.setChildCount(element, variable.getChildCount());
+				}
+			} else if (element instanceof TLCVariableValue) {
+				final TLCVariableValue value = (TLCVariableValue) element;
+				if (currentChildCount != value.getChildCount()) {
+					treeViewer.setChildCount(element, value.getChildCount());
+				}
+			} else {
+				throw new IllegalArgumentException();
+			}
+		}
+
+		@Override
+		public Object getParent(Object element) {
+			return null;
+		}
+    }
+    
+    /**
+	 * Label provider for the tree table. Modified on 30 Aug 2009 by LL to implement
+	 * ITableColorProvider instead of IColorProvider. This allows coloring of
+	 * individual columns, not just of entire rows.
+	 */
+	static class StateLabelProvider extends CellLabelProvider {
+        private static final int NAME_COLUMN_INDEX = 0;
+        private static final int VALUE_COLUMN_INDEX = 1;
+
+		private static final Map<String, Color> LOCATION_COLOR_MAP = new ConcurrentHashMap<String, Color>();
+		//TODO Convert to Toolbox preference once this features proves useful.
+		private static final boolean COLORING_SYSTEM_PROPERTY = Boolean.getBoolean(TLCErrorView.class.getName() + ".coloring");
+
+    	
+        private final Image stateImage;
+        private final Image varImage;
+        private final Image recordImage;
+        private final Image setImage;
+        private final Image loadMoreImage;
+        
+		public StateLabelProvider() {
+            stateImage = TLCUIActivator.getImageDescriptor("/icons/full/default_co.gif").createImage();
+            varImage = TLCUIActivator.getImageDescriptor("/icons/full/private_co.gif").createImage();
+            recordImage = TLCUIActivator.getImageDescriptor("/icons/full/brkpi_obj.gif").createImage();
+            // setImage = TLCUIActivator.getImageDescriptor("/icons/full/over_co.gif").createImage();
+            setImage = TLCUIActivator.getImageDescriptor("/icons/full/compare_method.gif").createImage();
+            loadMoreImage = TLCUIActivator.getImageDescriptor("/icons/full/add.gif").createImage();
+            // other candidates are newstream_wiz.gif, nav_go.gif, debugt_obj.gif
+        }
+
+		@Override
+		public void dispose() {
+			stateImage.dispose();
+			varImage.dispose();
+			recordImage.dispose();
+			setImage.dispose();
+			loadMoreImage.dispose();
+			
+			super.dispose();
+		}
+
+		@Override
+		public String getToolTipText(final Object element) {
+			if (element instanceof LoaderTLCState) {
+				return LOADER_TOOL_TIP;
+			}
+			
+			return null;
+		}
+
+		@Override
+		public void update(final ViewerCell cell) {
+			// labels
+			cell.setText(getColumnText(cell.getElement(), cell.getColumnIndex()));
+			
+			// images
+			cell.setImage(getColumnImage(cell.getElement(), cell.getColumnIndex()));
+			
+			// font
+			cell.setFont(getFont(cell.getElement(), cell.getColumnIndex()));
+
+			
+			final Color bg = getBackground(cell.getElement(), cell.getColumnIndex());
+			cell.setBackground(bg);
+
+			if (TLAEditorActivator.getDefault().isCurrentThemeDark()) {
+				cell.setForeground((bg == null) ? null : Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
+			} else {
+				cell.setForeground(null);
+			}
+		}
+
+		private Image getColumnImage(Object element, int columnIndex) {
+			if (columnIndex == NAME_COLUMN_INDEX) {
+				if (element instanceof LoaderTLCState) {
+					return loadMoreImage;
+				}
+				if (element instanceof TLCState) {
+					return stateImage;
+				} else if (element instanceof TLCVariable) {
+					return varImage;
+				} else if (element instanceof TLCNamedVariableValue) {
+					return recordImage;
+				} else if (element instanceof TLCFcnElementVariableValue) {
+					return recordImage;
+				}
+				return setImage; // other things appear in unordered collections
+			}
+			return null;
+		}
+
+		private String getColumnText(final Object element, final int columnIndex) {
+			if (element instanceof TLCState) {
+				final TLCState state = (TLCState) element;
+
+				switch (columnIndex) {
+					case NAME_COLUMN_INDEX:
+						if (state.isStuttering()) {
+							return "<Stuttering>";
+						} else if (state.isBackToState()) {
+							return "<Back to state " + state.getStateNumber() + ">";
+						}
+						return state.getLabel();
+					case VALUE_COLUMN_INDEX:
+						if (state instanceof RecordToSourceCoupler.LoaderTLCState) {
+							return "";
+						} else {
+							return "State (num = " + state.getStateNumber() + ")";
+						}
+						// state.toString();
+					default:
+						break;
+				}
+			} else if (element instanceof TLCVariable) {
+				final TLCVariable var = (TLCVariable) element;
+				switch (columnIndex) {
+					case NAME_COLUMN_INDEX:
+						if (var.isTraceExplorerVar()) {
+							return var.getSingleLineName();
+						} else {
+							return var.getName();
+						}
+					case VALUE_COLUMN_INDEX:
+						return var.getValue().toSimpleString();
+					// Changed from toString by LL on 30 Aug 2009
+					default:
+						break;
+				}
+			} else if ((element instanceof TLCSetVariableValue)
+						|| (element instanceof TLCSequenceVariableValue)
+						|| (element instanceof TLCSimpleVariableValue)) {
+				final TLCVariableValue varValue = (TLCVariableValue) element;
+				switch (columnIndex) {
+					case VALUE_COLUMN_INDEX:
+						return varValue.toString();
+					case NAME_COLUMN_INDEX:
+						return ""; // added by LL on 5 Nov 2009
+					default:
+						break;
+				}
+			} else if (element instanceof TLCNamedVariableValue) {
+				final TLCNamedVariableValue namedValue = (TLCNamedVariableValue) element;
+				switch (columnIndex) {
+					case NAME_COLUMN_INDEX:
+						return namedValue.getName();
+					case VALUE_COLUMN_INDEX:
+						return ((TLCVariableValue) namedValue.getValue()).toSimpleString();
+					// Changed from toString by LL on 30 Aug 2009
+					default:
+						break;
+				}
+			} else if (element instanceof TLCFcnElementVariableValue) {
+				final TLCFcnElementVariableValue fcnElementValue = (TLCFcnElementVariableValue) element;
+				switch (columnIndex) {
+					case NAME_COLUMN_INDEX:
+						return fcnElementValue.getFrom().toSimpleString();
+					// Changed from toString by LL on 30 Aug 2009
+					case VALUE_COLUMN_INDEX:
+						return ((TLCVariableValue) fcnElementValue.getValue()).toSimpleString();
+					// Changed from toString by LL on 30 Aug 2009
+					default:
+						break;
+				}
+			} else if (element instanceof TLCRecordVariableValue) {
+				final TLCRecordVariableValue recordValue = (TLCRecordVariableValue) element;
+				switch (columnIndex) {
+					case NAME_COLUMN_INDEX:
+						return "";
+					case VALUE_COLUMN_INDEX:
+						return recordValue.toSimpleString();
+					default:
+						break;
+				}
+			} else if (element instanceof TLCFunctionVariableValue) {
+				final TLCFunctionVariableValue fcnValue = (TLCFunctionVariableValue) element;
+				switch (columnIndex) {
+					case NAME_COLUMN_INDEX:
+						return "";
+					case VALUE_COLUMN_INDEX:
+						return fcnValue.toSimpleString();
+					default:
+						break;
+				}
+			}
+
+			return null;
+		}
+
+        /**
+         * The following method sets the background color of a row or column of
+         * the table. It highlights the entire row for an added or deleted item.
+         * For a changed value, only the value is highlighted.
+         */
+		private Color getBackground(final Object element, final int column) {
+            if (element instanceof TLCVariable) {
+				final TLCVariable var = (TLCVariable) element;
+				if (var.isChanged() && (column == VALUE_COLUMN_INDEX)) {
+					return TLCUIActivator.getDefault().getChangedColor();
+				}
+			} else if (element instanceof TLCVariableValue) {
+				final TLCVariableValue value = (TLCVariableValue) element;
+				if (value.isChanged()) {
+					if (column == VALUE_COLUMN_INDEX) {
+						return TLCUIActivator.getDefault().getChangedColor();
+					}
+				} else if (value.isAdded()) {
+					// Added takes precedence over deleted. E.g. a value can be
+					// added to a set in this state and be removed in the next
+					// state.
+					return TLCUIActivator.getDefault().getAddedColor();
+				} else if (value.isDeleted()) {
+					return TLCUIActivator.getDefault().getDeletedColor();
+				}
+			} else if (COLORING_SYSTEM_PROPERTY && (element instanceof TLCState)) {
+				// Assign a color to each location to make actions in the error
+				// viewer more easily distinguishable.
+				final TLCState state = (TLCState) element;
+				final Location moduleLocation = state.getModuleLocation();
+				if (moduleLocation == null) {
+					return null;
+				}
+				Color c = LOCATION_COLOR_MAP.get(moduleLocation.toString());
+				if (c == null) {
+					final int color = SWT.COLOR_WHITE + (2 * LOCATION_COLOR_MAP.size());
+					c = TLCUIActivator.getColor(color);
+					LOCATION_COLOR_MAP.put(state.getModuleLocation().toString(), c);
+				}
+				return c;
+			}
+			return null;
+		}
+
+		private Font getFont(final Object element, final int columnIndex) {
+			boolean returnBoldVersion = false;
+			
+			if (element instanceof TLCVariable) {
+				if (((TLCVariable) element).isTraceExplorerVar()) {
+					returnBoldVersion = true;
+				}
+			} else if (element instanceof RecordToSourceCoupler.LoaderTLCState) {
+				returnBoldVersion = true;
+			}
+
+			final FontRegistry fr = JFaceResources.getFontRegistry();
+			return returnBoldVersion ? fr.getBold(TLCErrorView.JFACE_ERROR_TRACE_ID)
+									 : fr.get(TLCErrorView.JFACE_ERROR_TRACE_ID);
+		}
+    }
+	
+	
+    /**
+     * A control listener for the Provides method for resizing the columns of
+     * the error trace viewer. This is to solve the problem of a bogus
+     * "third column" being displayed when the window is made wider than the two
+     * real columns.
+     * 
+     * There are two listener methods in this class: controlResized - called
+     * when the tree is resized. handleEvent - called when column[0] is resized.
+     * The controlResized command can change the size of column[0], which
+     * triggers the calling of the handleEvent. Experimentation indicates that
+     * this call of handleEvent occurs in the middle of executing the call of
+     * controlResized. The boolean flag inControlResized is used to tell the
+     * handleEvent method whether it was called this way or by the user resizing
+     * the colulmn.
+     * 
+     * Note: I [N.B. no idea who "I" is] am assuming that the call of handleEvent that happens when
+     * controlResized is resizing column[0] happens during the execution of
+     * column[0].setWidth, and no funny races are possible.
+     * 
+     * Note that all the code here assumes that there are two columns. It needs
+     * to be modified if the number of columns is changed.
+     */
+	private static class TraceDisplayResizer extends ControlAdapter implements Listener {
+        private double firstColumnPercentageWidth = 0.5;
+
+        // See comments above for meaning of the following flag.
+        private boolean inControlResized = false;
+        
+        private final Tree tree;
+        private final TreeColumn[] columns;
+        private final Scrollable treeParentComponent;
+
+        TraceDisplayResizer(final Tree resizingTree) {
+        	tree = resizingTree;
+        	treeParentComponent = (Scrollable)tree.getParent();
+        	columns = new TreeColumn[COLUMN_TEXTS.length];
+        }
+        
+        @Override
+		public void controlResized(final ControlEvent e) {
+            inControlResized = true;
+
+            final int treeWidth = computeMaximumWidthOfAllColumns();
+            final int firstColWidth = Math.round(Math.round(firstColumnPercentageWidth * treeWidth));
+            final int secondColWidth = treeWidth - firstColWidth;
+            columns[0].setWidth(firstColWidth);
+            columns[1].setWidth(secondColWidth);
+            
+            inControlResized = false;
+        }
+
+        @Override
+		public void handleEvent(final Event event) {
+			if (inControlResized) {
+				return;
+			}
+
+			final int treeWidth = computeMaximumWidthOfAllColumns();
+			if (treeWidth == 0) {
+				return;
+			}
+
+			// the percentage that the first column will occupy
+			// until controlResized is called
+			// We do not want the width of either column
+			// to be less than 10% of the total width
+			// of the tree. Currently, the user
+			// can make a column smaller than 10%, but
+			// when controlResized is called, the column
+			// will be enlarged to 10%. It is not very nice
+			// to do the enlarging in this method. It creates
+			// very choppy performance.
+			int firstColWidth = columns[0].getWidth();
+			final double tentativefirstColPercentageWidth = (double) firstColWidth / (double) treeWidth;
+			if ((tentativefirstColPercentageWidth > 0.1) && (tentativefirstColPercentageWidth < 0.9)) {
+				firstColumnPercentageWidth = (double) firstColWidth / (double) treeWidth;
+			} else if (tentativefirstColPercentageWidth <= .1) {
+				firstColumnPercentageWidth = 0.1;
+			} else {
+				firstColumnPercentageWidth = 0.9;
+			}
+			firstColWidth = Math.round(Math.round(tentativefirstColPercentageWidth * treeWidth));
+			columns[1].setWidth(treeWidth - firstColWidth);
+		}
+        
+        void setColumnForIndex(final TreeViewerColumn column, final int index) {
+        	columns[index] = column.getColumn();
+        	
+        	if (index == 0) {
+                // I [N.B. no idea who "I" is] need to add a listener for size changes to column[0] to
+                // detect when the user has tried to resize the individual columns. The following might work,
+        		// if I can figure out the real event type to use.
+                columns[0].addListener(SWT.Resize, this);
+        	}
+        }
+
+        /*
+         * Computes the maximum width that columns of the tree can occupy
+         * without having a horizontal scrollbar.
+         * 
+         * This is not equal to the sash form's client area. From the client
+         * area we must subtract the tree's border width. We must also subtract
+         * the width of the grid lines used in the tree times the number of
+         * columns because there is one grid line per column. We must subtract
+         * the width of the vertical scroll bar if it is visible.
+         */
+		private int computeMaximumWidthOfAllColumns() {
+			final ScrollBar vBar = tree.getVerticalBar();
+			final boolean scrollBarShown = vBar.isVisible();
+			
+			return treeParentComponent.getClientArea().width
+							- tree.getBorderWidth()
+							- (tree.getColumnCount() * tree.getGridLineWidth())
+							- ((scrollBarShown) ? vBar.getSize().x : 0);
+		}
+    }
+}
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/view/TLCErrorView.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/view/TLCErrorView.java
index 2bb06132121c8663aab2ff61f4bd0f03cb1eab8e..a90270fc1637b97df92b6a14af7b2d534615a5d5 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/view/TLCErrorView.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/view/TLCErrorView.java
@@ -3,12 +3,12 @@ package org.lamport.tla.toolbox.tool.tlc.ui.view;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.Vector;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.regex.Pattern;
 
 import org.eclipse.core.runtime.Assert;
@@ -18,48 +18,42 @@ import org.eclipse.jface.action.Action;
 import org.eclipse.jface.action.ToolBarManager;
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.jface.dialogs.IDialogSettings;
-import org.eclipse.jface.resource.FontRegistry;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.resource.JFaceResources;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.Document;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.source.SourceViewer;
-import org.eclipse.jface.util.IPropertyChangeListener;
-import org.eclipse.jface.viewers.CellLabelProvider;
-import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
-import org.eclipse.jface.viewers.ILazyTreeContentProvider;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.viewers.TreeViewer;
-import org.eclipse.jface.viewers.TreeViewerColumn;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.jface.window.Window;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.SashForm;
 import org.eclipse.swt.custom.StyledText;
-import org.eclipse.swt.events.ControlAdapter;
-import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.events.MouseAdapter;
 import org.eclipse.swt.events.MouseEvent;
 import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.events.SelectionAdapter;
 import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.graphics.Font;
-import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
-import org.eclipse.swt.widgets.ScrollBar;
-import org.eclipse.swt.widgets.Scrollable;
+import org.eclipse.swt.widgets.Shell;
 import org.eclipse.swt.widgets.ToolBar;
 import org.eclipse.swt.widgets.Tree;
-import org.eclipse.swt.widgets.TreeColumn;
 import org.eclipse.ui.ISharedImages;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.forms.widgets.Form;
@@ -68,38 +62,30 @@ import org.eclipse.ui.forms.widgets.Section;
 import org.eclipse.ui.part.ViewPart;
 import org.eclipse.ui.texteditor.ITextEditor;
 import org.lamport.tla.toolbox.Activator;
-import org.lamport.tla.toolbox.tool.tlc.model.Formula;
 import org.lamport.tla.toolbox.tool.tlc.model.Model;
 import org.lamport.tla.toolbox.tool.tlc.output.data.TLCError;
-import org.lamport.tla.toolbox.tool.tlc.output.data.TLCFcnElementVariableValue;
-import org.lamport.tla.toolbox.tool.tlc.output.data.TLCFunctionVariableValue;
 import org.lamport.tla.toolbox.tool.tlc.output.data.TLCModelLaunchDataProvider;
-import org.lamport.tla.toolbox.tool.tlc.output.data.TLCMultiVariableValue;
-import org.lamport.tla.toolbox.tool.tlc.output.data.TLCNamedVariableValue;
-import org.lamport.tla.toolbox.tool.tlc.output.data.TLCRecordVariableValue;
-import org.lamport.tla.toolbox.tool.tlc.output.data.TLCSequenceVariableValue;
-import org.lamport.tla.toolbox.tool.tlc.output.data.TLCSetVariableValue;
-import org.lamport.tla.toolbox.tool.tlc.output.data.TLCSimpleVariableValue;
 import org.lamport.tla.toolbox.tool.tlc.output.data.TLCState;
 import org.lamport.tla.toolbox.tool.tlc.output.data.TLCVariable;
-import org.lamport.tla.toolbox.tool.tlc.output.data.TLCVariableValue;
 import org.lamport.tla.toolbox.tool.tlc.output.source.TLCOutputSourceRegistry;
 import org.lamport.tla.toolbox.tool.tlc.traceexplorer.TraceExplorerComposite;
 import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator;
+import org.lamport.tla.toolbox.tool.tlc.ui.dialog.ErrorViewTraceFilterDialog;
+import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor;
 import org.lamport.tla.toolbox.tool.tlc.ui.editor.TLACoverageEditor;
 import org.lamport.tla.toolbox.tool.tlc.ui.preference.ITLCPreferenceConstants;
-import org.lamport.tla.toolbox.tool.tlc.ui.util.RecordToSourceCoupler;
-import org.lamport.tla.toolbox.tool.tlc.ui.util.RecordToSourceCoupler.LoaderTLCState;
 import org.lamport.tla.toolbox.tool.tlc.ui.util.ExpandableSpaceReclaimer;
 import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper;
+import org.lamport.tla.toolbox.tool.tlc.ui.util.RecordToSourceCoupler;
 import org.lamport.tla.toolbox.tool.tlc.ui.util.TLCUIHelper;
 import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper;
 import org.lamport.tla.toolbox.util.FontPreferenceChangeListener;
 import org.lamport.tla.toolbox.util.IHelpConstants;
 import org.lamport.tla.toolbox.util.UIHelper;
 
-import tla2sany.st.Location;
+import tlc2.model.Formula;
 import tlc2.output.MP;
+import util.TLAConstants;
 
 /**
  * Error representation view containing the error description and the trace
@@ -111,9 +97,10 @@ public class TLCErrorView extends ViewPart
 {
 	public static final String ID = "toolbox.tool.tlc.view.TLCErrorView";
 
+	static final String JFACE_ERROR_TRACE_ID = ITLCPreferenceConstants.I_TLC_ERROR_TRACE_FONT + "_private";
+
 	private static final SimpleDateFormat sdf = new SimpleDateFormat("MMM dd,yyyy HH:mm:ss");
 	
-	private static final String JFACE_ERROR_TRACE_ID = ITLCPreferenceConstants.I_TLC_ERROR_TRACE_FONT + "_private";
 	private static final String CELL_TEXT_PROTOTYPE = "{|qgyA!#93^<[?";
 
 	private static final String INNER_WEIGHTS_KEY = "INNER_WEIGHTS_KEY";
@@ -121,11 +108,14 @@ public class TLCErrorView extends ViewPart
 	private static final String MID_WEIGHTS_KEY = "MID_WEIGHTS_KEY";
   
 	private static final String SYNCED_TRAVERSAL_KEY = "SYNCED_TRAVERSAL_KEY";
-	
-	private static final String DEFAULT_TOOL_TIP
-		= "Click on a row to see in viewer below.\nDouble-click to go to corresponding action in spec \u2014 "
-			+ "while holding\n   down " + (Platform.getOS().equals(Platform.OS_MACOSX) ? "\u2318" : "CTRL")
-			+ " to go to the original PlusCal code, if present.";
+
+    private static final String NO_VALUE_VIEWER_TEXT
+			= "\u2022 Select a line in Error Trace to show its value here.\n"
+				+ "\u2022 Double-click on a line to go to corresponding action in spec \u2014 "
+				+ "or while holding down " + (Platform.getOS().equals(Platform.OS_MACOSX) ? "\u2318" : "CTRL")
+				+ " to go to the original PlusCal code, if present.\n"
+				+ "\u2022 Click on a variable while holding down ALT to hide the variable from view.\n"
+				+ "\u2022 Right-click on a location row for a context menu.";
 
     /**
      * This is the pattern of an error message resulting from evaluating the constant
@@ -141,7 +131,11 @@ public class TLCErrorView extends ViewPart
 
     private static final IDocument NO_VALUE_DOCUMENT()
     {
-        return new Document("Select line in Error Trace to show its value here.");
+        return new Document(NO_VALUE_VIEWER_TEXT);
+    }
+    
+    private enum FilterType {
+    	NONE, VARIABLES, MODIFIED_VALUES_ALL_FRAMES, MODIFIED_VALUES_MODIFIED_FRAMES;
     }
     
     
@@ -151,47 +145,40 @@ public class TLCErrorView extends ViewPart
     private Form form;
 
     private SourceViewer errorViewer;
-    private TreeViewer variableViewer;
+    private ErrorTraceTreeViewer errorTraceTreeViewer;
     private RecordToSourceCoupler stackTraceActionListener;
     private SyncStackTraversal syncStackTraversalAction;
+    private Button valueReflectsFiltering;
     private SourceViewer valueViewer;
-    private Model model;
+    private ModelEditor modelEditor;
     private TraceExplorerComposite traceExplorerComposite;
     
-    @SuppressWarnings("unused")  // help onto for a nicer object graph
+    private TLCError unfilteredInput;
+    private final HashMap<TLCState, Integer> filteredStateIndexMap;
+    private FilterErrorTrace filterErrorTraceAction;
+    private Set<TLCVariable> currentErrorTraceFilterSet;
+    
+    @SuppressWarnings("unused")  // held onto for a nicer object graph
 	private ExpandableSpaceReclaimer spaceReclaimer;
 
     // listener on changes to the tlc output font preference
     private FontPreferenceChangeListener outputFontChangeListener;
-    // listener on changes to the error trace font preference
-    private final IPropertyChangeListener errorTraceFontChangeListener;
 
 	public TLCErrorView() {
 		numberOfStatesToShow = TLCUIActivator.getDefault().getPreferenceStore()
 				.getInt(ITLCPreferenceConstants.I_TLC_TRACE_MAX_SHOW_ERRORS);
-		
-		errorTraceFontChangeListener = (event) -> {
-			if ((event == null) || event.getProperty().equals(ITLCPreferenceConstants.I_TLC_ERROR_TRACE_FONT)) {
-				final Font f = JFaceResources.getFont(ITLCPreferenceConstants.I_TLC_ERROR_TRACE_FONT);
-				
-				JFaceResources.getFontRegistry().put(JFACE_ERROR_TRACE_ID, f.getFontData());
-
-				if (variableViewer != null) {
-					variableViewer.refresh(true);
-				}
-			}
-		};
-		errorTraceFontChangeListener.propertyChange(null);
-        JFaceResources.getFontRegistry().addListener(errorTraceFontChangeListener);
+        
+        currentErrorTraceFilterSet = new HashSet<>();
+        
+        filteredStateIndexMap = new HashMap<>();
 	}
     
     /**
      * Clears the view
      */
-    public void clear()
-    {
+	public void clear() {
         errorViewer.setDocument(EMPTY_DOCUMENT());
-        setTraceInput(new TLCError());
+        setTraceInput(new TLCError(), true);
         traceExplorerComposite.getTableViewer().setInput(new Vector<Formula>());
         valueViewer.setInput(EMPTY_DOCUMENT());
     }
@@ -260,12 +247,12 @@ public class TLCErrorView extends ViewPart
              * traces because resetting the trace input locks up the toolbox for a few
              * seconds, so it is important to not reset the trace if it is not necessary.
              */
-            TLCError oldTrace = (TLCError) variableViewer.getInput();
-            boolean isNewTrace = trace != null && oldTrace != null && !(trace == oldTrace);
+            final TLCError oldTrace = errorTraceTreeViewer.getCurrentTrace();
+            final boolean isNewTrace = (trace != null) && (oldTrace != null) && !(trace == oldTrace);
             // update the trace information
             if (isNewTrace)
             {
-                this.setTraceInput(trace);
+                this.setTraceInput(trace, true);
             }
             if (model.isSnapshot()) {
             	final String date = sdf.format(model.getSnapshotTimeStamp());
@@ -302,7 +289,8 @@ public class TLCErrorView extends ViewPart
         //
         // int sectionFlags = Section.DESCRIPTION | Section.TITLE_BAR
         // | Section.EXPANDED | Section.TWISTIE;
-        toolkit = new FormToolkit(parent.getDisplay());
+        final Display display = parent.getDisplay();
+		toolkit = new FormToolkit(display);
         form = toolkit.createForm(parent);
         form.setText("");
         toolkit.decorateFormHeading(form);
@@ -355,25 +343,15 @@ public class TLCErrorView extends ViewPart
          */
         final StyledText text = errorViewer.getTextWidget();
         text.addMouseListener(new MouseListener() {
+            public void mouseUp(final MouseEvent e) { }
 
-            public void mouseUp(MouseEvent e)
-            {
-                // TODO Auto-generated method stub
-
-            }
-
-            public void mouseDown(MouseEvent e)
-            {
+			public void mouseDown(final MouseEvent e) {
                 final Set<Class<? extends ITextEditor>> blacklist = new HashSet<>();
                 blacklist.add(TLACoverageEditor.class);
-                TLCUIHelper.openTLCLocationHyperlink(text, e, model, blacklist);
+                TLCUIHelper.openTLCLocationHyperlink(text, e, modelEditor.getModel(), blacklist);
             }
 
-            public void mouseDoubleClick(MouseEvent e)
-            {
-                // TODO Auto-generated method stub
-
-            }
+            public void mouseDoubleClick(final MouseEvent e) { }
         });
 
         /*
@@ -447,7 +425,7 @@ public class TLCErrorView extends ViewPart
 
         sashForm.setLayoutData(gd);
 
-        Tree tree = toolkit.createTree(sashForm, SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION | SWT.SINGLE
+        Tree tree = toolkit.createTree(sashForm, SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI
                 | SWT.VIRTUAL);
         tree.setHeaderVisible(true);
         tree.setLinesVisible(true);
@@ -461,13 +439,6 @@ public class TLCErrorView extends ViewPart
         // gd.grabExcessHorizontalSpace = true ;
 
         tree.setLayoutData(gd);
-
-        // Initialize the trace display's resizer.
-        TraceDisplayResizer resizer = new TraceDisplayResizer();
-        resizer.comp = sashForm;
-        resizer.tree = tree;
-        
-        tree.addControlListener(resizer);
         tree.addListener(SWT.MeasureItem, (event) -> {
         	final Font originalFont = event.gc.getFont();
         	
@@ -479,158 +450,121 @@ public class TLCErrorView extends ViewPart
         	event.gc.setFont(originalFont);
         });
 
-        variableViewer = new TreeViewer(tree);
-        final StateContentProvider provider = new StateContentProvider(variableViewer);
-        variableViewer.setUseHashlookup(true);
-		variableViewer.setContentProvider(provider);
-        ColumnViewerToolTipSupport.enableFor(variableViewer);
-        getSite().setSelectionProvider(variableViewer);
-
-        final StateLabelProvider labelProvider = new StateLabelProvider();
-		for (int i = 0; i < StateLabelProvider.COLUMN_TEXTS.length; i++) {
-			final TreeViewerColumn column = new TreeViewerColumn(variableViewer, i);
-			column.getColumn().setText(StateLabelProvider.COLUMN_TEXTS[i]);
-			column.getColumn().setWidth(StateLabelProvider.COLUMN_WIDTH[i]);
-			column.setLabelProvider(labelProvider);
-			resizer.column[i] = column.getColumn(); // set up the resizer.
-			column.getColumn().addSelectionListener(new SelectionAdapter() {
-				public void widgetSelected(final SelectionEvent e) {
-					// reverse the current trace
-					final TLCError error = (TLCError) variableViewer.getInput();
-					error.reverseTrace();
-					// Reset the viewer's selection to the empty selection. With empty
-					// selection, the subsequent refresh call does *not* invalidate the
-					// StateContentProvider's lazy policy.
-					// We know that the user clicked on the tree's column header
-					// and the real selection is of little importance.
-					variableViewer.setSelection(new ISelection() {
-						public boolean isEmpty() {
-							return true;
-						}
-					});
-					variableViewer.refresh(false);
-					
-					// remember the order for next trace shown
-					final IDialogSettings dialogSettings = Activator.getDefault().getDialogSettings();
-					dialogSettings.put(TLCModelLaunchDataProvider.STATESORTORDER,
-							!dialogSettings.getBoolean(TLCModelLaunchDataProvider.STATESORTORDER));
-				}
-			});
-		}
-
-        // I need to add a listener for size changes to column[0] to
-        // detect when the user has tried to resize the individual columns.
-        // The following might work, if I can figure out the real event type
-        // to use.
-        resizer.column[0].addListener(SWT.Resize, resizer);
+        errorTraceTreeViewer = new ErrorTraceTreeViewer(tree, modelEditor);
+        getSite().setSelectionProvider(errorTraceTreeViewer.getTreeViewer());
 
         
         final Set<Class<? extends ITextEditor>> blacklist = new HashSet<>();
         blacklist.add(TLACoverageEditor.class);
-		stackTraceActionListener = new RecordToSourceCoupler(variableViewer, blacklist, this,
+		stackTraceActionListener = new RecordToSourceCoupler(errorTraceTreeViewer.getTreeViewer(), blacklist, this,
 				RecordToSourceCoupler.FocusRetentionPolicy.ARROW_KEY_TRAVERSAL);
-		variableViewer.getTree().addMouseListener(stackTraceActionListener);
-        variableViewer.getTree().addKeyListener(stackTraceActionListener);
-        variableViewer.getTree().addDisposeListener((event) -> {
+		tree.addMouseListener(stackTraceActionListener);
+		tree.addKeyListener(stackTraceActionListener);
+		tree.addDisposeListener((event) -> {
 			final IDialogSettings ids = Activator.getDefault().getDialogSettings();
 			ids.put(SYNCED_TRAVERSAL_KEY, syncStackTraversalAction.isChecked());
         });
+		tree.addMouseListener(new MouseAdapter() {
+        	@Override
+        	public void mouseUp(final MouseEvent event) {
+        		if ((event.stateMask & SWT.ALT) != 0) {
+        			final TreeViewer treeViewer = errorTraceTreeViewer.getTreeViewer();
+        			final ISelection is = treeViewer.getSelection();
+        			if ((is != null) && !is.isEmpty() && (is instanceof StructuredSelection)) {
+        				final Object selection = ((StructuredSelection)is).getFirstElement();
+        				
+        				if (selection instanceof TLCVariable) {
+        					if (filterErrorTraceAction.isChecked()) {
+        						addVariableFamilyToFiltering((TLCVariable)selection);
+        					} else {
+        						currentErrorTraceFilterSet.clear();
+        						addVariableFamilyToFiltering((TLCVariable)selection);
+								filterErrorTraceAction.setChecked(true);
+        					}
+        					
+        					performVariableViewPopulation(EnumSet.of(FilterType.VARIABLES));
+        				}
+        			}
+        		}
+        	}
+        });
         
         // Make it possible to expand and collapse the error trace with the push of a button.
 		final ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
 		final ToolBar toolbar = toolBarManager.createControl(errorTraceSection);
 		final ShiftClickAction action = new ShiftClickAction(
 				"Toggle between expand and collapse all (Shift+Click to restore the default two-level expansion)",
-				TLCUIActivator.getImageDescriptor("icons/elcl16/toggle_expand_state.png")) {
+				TLCUIActivator.getImageDescriptor("icons/elcl16/toggle_expand_state.png"), display) {
 			@Override
 			void runWithKey(final boolean pressed) {
+    			final TreeViewer treeViewer = errorTraceTreeViewer.getTreeViewer();
 				if (pressed) {
 					// expandAll() followed by expandToLevel(2) requires us
 					// to collapse the viewer first.
-					variableViewer.collapseAll();
-					variableViewer.expandToLevel(2);
+					treeViewer.collapseAll();
+					treeViewer.expandToLevel(2);
 				} else {
-					final Object[] expandedElements = variableViewer.getExpandedElements();
+					final Object[] expandedElements = treeViewer.getExpandedElements();
 					if (expandedElements.length == 0) {
-						variableViewer.expandAll();
+						treeViewer.expandAll();
 					} else {
-						variableViewer.collapseAll();
+						treeViewer.collapseAll();
 					}
 				}
 			}
 		};
-		parent.getDisplay().addFilter(SWT.KeyDown, action);
-		parent.getDisplay().addFilter(SWT.KeyUp, action);
+		toolBarManager.add(new ExportErrorTrace2Clipboard(display));
+		filterErrorTraceAction = new FilterErrorTrace();
+		toolBarManager.add(filterErrorTraceAction);
 		toolBarManager.add(action);
 		syncStackTraversalAction = new SyncStackTraversal();
 		toolBarManager.add(syncStackTraversalAction);
 		toolBarManager.update(true);
 		errorTraceSection.setTextClient(toolbar);
-// This is working but now redundant to the buttons on the section (see above).
-// Also ActionClickListener has a keystroke to collapse the viewer.        
-//        // Add a right click context menu to expand and collapse all variables. 
-//		final MenuManager contextMenu = new MenuManager("#ViewerMenu"); //$NON-NLS-1$
-//		contextMenu.setRemoveAllWhenShown(true);
-//		contextMenu.addMenuListener(new IMenuListener() {
-//			@Override
-//			public void menuAboutToShow(IMenuManager mgr) {
-//				mgr.add(new Action("&Collapse All") {
-//					public void run() {
-//						variableViewer.collapseAll();
-//					}
-//				});
-//				mgr.add(new Action("Expand to &default level") {
-//					public void run() {
-//						// expandAll() followed by expandToLevel(2) requires us
-//						// to collapse the viewer first.
-//						variableViewer.collapseAll();
-//						variableViewer.expandToLevel(2);
-//					}
-//				});
-//				mgr.add(new Action("&Expand All") {
-//					public void run() {
-//						variableViewer.expandAll();
-//					}
-//				});
-//			}
-//		});
-//		final Menu menu = contextMenu.createContextMenu(variableViewer.getControl());
-//		variableViewer.getControl().setMenu(menu);
-//
-        variableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
-
-            public void selectionChanged(SelectionChangedEvent event)
-            {
-                if (!((IStructuredSelection) event.getSelection()).isEmpty())
-                {
-                    // Set selection to the selected element (or the
-                    // first if there are multiple
-                    // selections), and show its string representation
-                    // in the value viewer
-                    // (the lower sub-window).
-                    Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
-                    if (selection instanceof TLCState)
-                    {
-                        TLCState state = (TLCState) selection;
-                        valueViewer.setDocument(new Document(state.getDescriptionWithTraceExpressions()));
-                    } else
-                    {
-                        valueViewer.setDocument(new Document(selection.toString()));
-                    }
-                } else
-                {
-                    valueViewer.setDocument(NO_VALUE_DOCUMENT());
-                }
 
-            }
+		errorTraceTreeViewer.getTreeViewer().addSelectionChangedListener((event) -> {
+			handleValueViewerUpdate((IStructuredSelection)event.getSelection());
         });
 
+		final Composite valueViewerComposite = new Composite(sashForm, SWT.NONE);
+		final GridLayout gl = new GridLayout(1, false);
+		gl.marginHeight = 0;
+		gl.marginWidth = 0;
+		gl.verticalSpacing = 3;
+		valueViewerComposite.setLayout(gl);
+		gd = new GridData();
+		gd.horizontalAlignment = SWT.LEFT;
+		gd.verticalAlignment = SWT.TOP;
+		gd.grabExcessHorizontalSpace = true;
+		valueViewerComposite.setLayoutData(gd);
+		
+		valueReflectsFiltering = new Button(valueViewerComposite, SWT.CHECK);
+		valueReflectsFiltering.setText("Reflect filtering");
+		valueReflectsFiltering.setSelection(true);
+		valueReflectsFiltering.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				handleValueViewerUpdate((IStructuredSelection)errorTraceTreeViewer.getTreeViewer().getSelection());
+			}
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) { }
+		});
+		gd = new GridData();
+		gd.horizontalAlignment = SWT.RIGHT;
+		gd.verticalAlignment = SWT.TOP;
+		gd.exclude = true;
+		valueReflectsFiltering.setLayoutData(gd);
+		valueReflectsFiltering.setVisible(false);
+		
         /* Horizontal scroll bar added by LL on 26 Aug 2009 */
-        valueViewer = FormHelper.createFormsSourceViewer(toolkit, sashForm, SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI
-                | SWT.BORDER);
+        valueViewer = FormHelper.createFormsSourceViewer(toolkit, valueViewerComposite,
+        												 (SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.BORDER));
         valueViewer.setEditable(false);
-
-        gd = new GridData(SWT.LEFT, SWT.TOP, true, false);
+        gd = new GridData();
+        gd.horizontalAlignment = SWT.FILL;
+        gd.grabExcessHorizontalSpace = true;
+        gd.verticalAlignment = SWT.FILL;
+        gd.grabExcessVerticalSpace = true;
         valueViewer.getControl().setLayoutData(gd);
 
  
@@ -696,6 +630,35 @@ public class TLCErrorView extends ViewPart
         TLCUIHelper.setHelp(parent, IHelpConstants.TLC_ERROR_VIEW);
     }
     
+    private void handleValueViewerUpdate(final IStructuredSelection structuredSelection) {
+		if (!structuredSelection.isEmpty()) {
+			// Set selection to the selected element (or the first if there are multiple
+			// selections), and show its string representation in the value viewer (the lower sub-window).
+			final Object selection = structuredSelection.getFirstElement();
+			if (selection instanceof TLCState) {
+				final TLCState state;
+				if ((filteredStateIndexMap.size() != 0) && !valueReflectsFiltering.getSelection()) {
+					final Integer index = filteredStateIndexMap.get(selection);
+					
+					if (index != null) {
+						state = unfilteredInput.getStates(TLCError.Length.ALL).get(index.intValue());
+					} else {
+						TLCUIActivator.getDefault().logWarning("Could not find mapped index for state.");
+						
+						state = (TLCState) selection;
+					}
+				} else {
+					state = (TLCState) selection;
+				}
+				valueViewer.setDocument(new Document(state.getConjunctiveDescription(true)));
+			} else {
+				valueViewer.setDocument(new Document(selection.toString()));
+			}
+		} else {
+			valueViewer.setDocument(NO_VALUE_DOCUMENT());
+		}
+    }
+    
 	private int[] stringToIntArray(final String str) {
 		final String[] strings = str.replace("[", "").replace("]", "").split(", ");
 		int result[] = new int[strings.length];
@@ -711,10 +674,9 @@ public class TLCErrorView extends ViewPart
     }
 
 	public void dispose() {
-		final FontRegistry fr = JFaceResources.getFontRegistry();
-		
-        fr.removeListener(outputFontChangeListener);
-        fr.removeListener(errorTraceFontChangeListener);
+		JFaceResources.getFontRegistry().removeListener(outputFontChangeListener);
+        
+        errorTraceTreeViewer.dispose();
         
         toolkit.dispose();
         
@@ -771,61 +733,54 @@ public class TLCErrorView extends ViewPart
     }
 
 	public void updateErrorView() {
-		updateErrorView(this.model);
+		updateErrorView(modelEditor);
 	}
 
     /**
      * Display the errors in the view, or hides the view if no errors
      * Displays data from the most recent trace explorer run for config
      * iff {@link ModelHelper#isOriginalTraceShown(ILaunchConfiguration)} is false.
-     * 
-     * @param errors
-     *            a list of {@link TLCError}
      */
-    public static void updateErrorView(Model model) {
-    	updateErrorView(model, true);
+    public static void updateErrorView(final ModelEditor associatedModelEditor) {
+    	updateErrorView(associatedModelEditor, true);
     }
 
-    public static void updateErrorView(Model model, boolean openErrorView)
-    {
-        if (model == null)
-        {
-            return;
-        }
-        boolean isTraceExplorerUpdate;
-        isTraceExplorerUpdate = !model.isOriginalTraceShown();
+	public static void updateErrorView(final ModelEditor associatedModelEditor, final boolean openErrorView) {
+		if (associatedModelEditor == null) {
+			return;
+		}
+		final Model model = associatedModelEditor.getModel();
+		final boolean isTraceExplorerUpdate = !model.isOriginalTraceShown();
 
-        TLCModelLaunchDataProvider provider = null;
-        if (isTraceExplorerUpdate)
-        {
-            provider = TLCOutputSourceRegistry.getTraceExploreSourceRegistry().getProvider(model);
-        } else
-        {
-            provider = TLCOutputSourceRegistry.getModelCheckSourceRegistry().getProvider(model);
-        }
+		final TLCModelLaunchDataProvider provider;
+		if (isTraceExplorerUpdate) {
+			provider = TLCOutputSourceRegistry.getTraceExploreSourceRegistry().getProvider(model);
+		} else {
+			provider = TLCOutputSourceRegistry.getModelCheckSourceRegistry().getProvider(model);
+		}
 
-        if (provider == null)
-        {
-            return;
-        }
-        updateErrorView(provider, model, openErrorView);
-    }
+		if (provider == null) {
+			return;
+		}
+		
+		updateErrorView(provider, associatedModelEditor, openErrorView);
+	}
     
-	public static void updateErrorView(final TLCModelLaunchDataProvider provider, final Model model,
-			boolean openErrorView) {
-        TLCErrorView errorView;
-		if (provider.getErrors().size() > 0 && openErrorView == true) {
+	public static void updateErrorView(final TLCModelLaunchDataProvider provider, final ModelEditor associatedModelEditor,
+			final boolean openErrorView) {
+        final TLCErrorView errorView;
+		if ((provider.getErrors().size() > 0) && openErrorView) {
        		errorView = (TLCErrorView) UIHelper.openView(TLCErrorView.ID);
 		} else {
             errorView = (TLCErrorView) UIHelper.findView(TLCErrorView.ID);
         }
+		
 		if (errorView != null) {
-            errorView.model= model;
+			errorView.setModelEditor(associatedModelEditor);
 
-            final List<String> serializedInput = model.getTraceExplorerExpressions();
+            final List<String> serializedInput = associatedModelEditor.getModel().getTraceExplorerExpressions();
             // fill the name and the errors
-			errorView.fill(provider.getModel(), provider.getErrors(),
-					serializedInput);
+			errorView.fill(provider.getModel(), provider.getErrors(), serializedInput);
 
 			if (provider.getErrors().size() == 0) {
                 errorView.hide();
@@ -833,563 +788,22 @@ public class TLCErrorView extends ViewPart
         }
     }
 
-    /**
-     * A control listener for the Provides method for resizing the columns of
-     * the error trace viewer. This is to solve the problem of a bogus
-     * "third column" being displayed when the window is made wider than the two
-     * real columns.
-     * 
-     * There are two listener methods in this class: controlResized - called
-     * when the tree is resized. handleEvent - called when column[0] is resized.
-     * The controlResized command can change the size of column[0], which
-     * triggers the calling of the handleEvent. Experimentation indicates that
-     * this call of handleEvent occurs in the middle of executing the call of
-     * controlResized. The boolean flag inControlResized is used to tell the
-     * handleEvent method whether it was called this way or by the user resizing
-     * the colulmn.
-     * 
-     * Note: I am assuming that the call of handleEvent that happens when
-     * controlResized is resizing column[0] happens during the execution of
-     * column[0].setWidth, and no funny races are possible.
-     * 
-     * Note that all the code here assumes that there are two columns. It needs
-     * to be modified if the number of columns is changed.
-     */
-    static class TraceDisplayResizer extends ControlAdapter implements Listener
-    {
-        double firstColumnPercentageWidth = .5;
-
-        // See comments above for meaning of the following flag.
-        boolean inControlResized = false;
-        Scrollable comp; // The component containing the trace display.
-        TreeColumn[] column = new TreeColumn[StateLabelProvider.COLUMN_TEXTS.length];
-        Tree tree;
-
-        public void controlResized(ControlEvent e)
-        {
-            inControlResized = true;
-
-            int treeWidth = computeMaximumWidthOfAllColumns();
-            int firstColWidth = Math.round(Math.round(firstColumnPercentageWidth * treeWidth));
-            int secondColWidth = treeWidth - firstColWidth;
-            column[0].setWidth(firstColWidth);
-            column[1].setWidth(secondColWidth);
-            inControlResized = false;
-        }
-
-        int count = 0;
-
-        public void handleEvent(Event event)
-        {
-            if (inControlResized)
-            {
-                return;
-            }
-
-            int treeWidth = computeMaximumWidthOfAllColumns();
-            int firstColWidth = column[0].getWidth();
-
-            if (treeWidth == 0)
-            {
-                return;
-            }
-
-            // the percentage that the first column will occupy
-            // until controlResized is called
-            // We do not want the width of either column
-            // to be less than 10% of the total width
-            // of the tree. Currently, the user
-            // can make a column smaller than 10%, but
-            // when controlResized is called, the column
-            // will be enlarged to 10%. It is not very nice
-            // to do the enlarging in this method. It creates
-            // very choppy performance.
-            double tentativefirstColPercentageWidth = (double) firstColWidth / (double) treeWidth;
-            if (tentativefirstColPercentageWidth > .1 && tentativefirstColPercentageWidth < .9)
-            {
-                firstColumnPercentageWidth = (double) firstColWidth / (double) treeWidth;
-
-            } else if (tentativefirstColPercentageWidth <= .1)
-            {
-                firstColumnPercentageWidth = .1;
-            } else
-            {
-                firstColumnPercentageWidth = .9;
-            }
-            firstColWidth = Math.round(Math.round(tentativefirstColPercentageWidth * treeWidth));
-            int secondColWidth = treeWidth - firstColWidth;
-            column[1].setWidth(secondColWidth);
-        }
-
-        /*
-         * Computes the maximum width that columns of the tree can occupy
-         * without having a horizontal scrollbar.
-         * 
-         * This is not equal to the sash form's client area. From the client
-         * area we must subtract the tree's border width. We must also subtract
-         * the width of the grid lines used in the tree times the number of
-         * columns because there is one grid line per column. We must subtract
-         * the width of the vertical scroll bar if it is visible.
-         */
-        private int computeMaximumWidthOfAllColumns()
-        {
-            ScrollBar vBar = tree.getVerticalBar();
-            boolean scrollBarShown = vBar.isVisible();
-            return comp.getClientArea().width - tree.getBorderWidth() - tree.getColumnCount() * tree.getGridLineWidth()
-                    - ((scrollBarShown) ? vBar.getSize().x : 0);
-        }
-
-    }
-
-    /**
-     * Content provider for the tree table
-     */
-    private class StateContentProvider implements ILazyTreeContentProvider {
-       	
-    	private final TreeViewer viewer;
-		private List<TLCState> states = new ArrayList<TLCState>(0);
-
-		public StateContentProvider(TreeViewer viewer) {
-			this.viewer = viewer;
-    	}
-
-		/* (non-Javadoc)
-		 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
-		 */
-		public void dispose() {
-		}
-
-		/* (non-Javadoc)
-		 * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
-		 */
-		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-			// Eagerly cache the list of states as it can be a sublist of the
-			// complete trace. Getting the sublist in the updateElement method
-			// means we obtain it over and over again for each top-level tree
-			// item.
-			if (newInput instanceof TLCError) {
-				this.states = ((TLCError) newInput).getStates();
-			} else if (newInput == null) {
-				this.states = new ArrayList<TLCState>(0);
-			} else {
-				throw new IllegalArgumentException();
-			}
-		}
-
-		/* (non-Javadoc)
-		 * @see org.eclipse.jface.viewers.ILazyTreeContentProvider#updateElement(java.lang.Object, int)
-		 */
-		public void updateElement(Object parent, int viewerIndex) {
-			if (parent instanceof TLCError) {
-				final TLCError error = (TLCError) parent;
-				if (error.isTraceRestricted() && viewerIndex == 0) {
-					// If only a subset of the trace is shown, show a dummy item
-					// at the top which can be double-clicked to load more.
-					viewer.replace(parent, viewerIndex, new RecordToSourceCoupler.LoaderTLCState(viewer,
-							Math.min(numberOfStatesToShow, error.getNumberOfRestrictedTraceStates()), error));
-					return;
-				}
-				// decrease index into states by one if the viewers first element is a dummy item
-				final int statesIndex = viewerIndex - (error.isTraceRestricted() ? 1 : 0);
-				final TLCState child = states.get(statesIndex);
-				// Diffing is supposed to be lazy and thus is done here when
-				// the state is first used by the viewer. The reason why it
-				// has to be lazy is to be able to efficiently handle traces
-				// with hundreds or thousands of states where it would be a
-				// waste to diff all state pairs even if the user is never
-				// going to look at all states anyway.
-				// TODO If ever comes up as a performance problem again, the
-				// nested TLCVariableValues could also be diffed lazily.
-           		if (statesIndex > 0) {
-           			final TLCState predecessor = states.get(statesIndex - 1);
-           			predecessor.diff(child);
-           		}
-				viewer.replace(parent, viewerIndex, child);
-				// Always setHashChildren even if child has no children: This is
-				// a virtual table here meaning that it reduces the number of
-				// table items at the OS level by recycling them (the OS only
-				// creates a many items that fit into the visible area). If an
-				// item showing a regular state, is later recycled by a "back to
-				// state" or "stuttering" indicator (neither has children),
-				// the OS still incorrectly assumes the item has children. This
-				// crashes hard on Linux and results in erratic behavior on
-				// Windows and Mac.
-				viewer.setHasChildren(child, child.getVariablesAsList().size() > 0);
-				// Lazily expand the children
-				if (child.isExpandable()){
-					viewer.expandToLevel(child, 1);
-				}
-			} else if (parent instanceof TLCState) {
-				final TLCState state = (TLCState) parent;
-                if ((state.isStuttering() || state.isBackToState())) {
-					viewer.setChildCount(state, 0);
-                } else {
-                	final List<TLCVariable> variablesAsList = state.getVariablesAsList();
-                	if (variablesAsList.size() > viewerIndex) {
-                		final TLCVariable child = variablesAsList.get(viewerIndex);
-                		viewer.replace(parent, viewerIndex, child);
-        				viewer.setHasChildren(child, child.getChildCount() > 0);
-                	}
-                }
-			} else if (parent instanceof TLCVariable
-					&& ((TLCVariable) parent).getValue() instanceof TLCMultiVariableValue) {
-				final TLCMultiVariableValue multiValue = (TLCMultiVariableValue) ((TLCVariable) parent).getValue();
-				final TLCVariableValue child = multiValue.asList().get(viewerIndex);
-				viewer.replace(parent, viewerIndex, child);
-				viewer.setHasChildren(child, child.getChildCount() > 0);
-			} else if (parent instanceof TLCVariable) {
-				final TLCVariable variable = (TLCVariable) parent;
-				final TLCVariableValue child = variable.getValue();
-				viewer.replace(parent, viewerIndex, child);
-				viewer.setChildCount(child, child.getChildCount());
-			} else if (parent instanceof TLCMultiVariableValue) {
-				final TLCMultiVariableValue multiValue = (TLCMultiVariableValue) parent;
-				final TLCVariableValue child = multiValue.asList().get(viewerIndex);
-				viewer.replace(parent, viewerIndex, child);
-				viewer.setHasChildren(child, child.getChildCount() > 0);
-			} else if (parent instanceof TLCVariableValue
-					&& ((TLCVariableValue) parent).getValue() instanceof TLCMultiVariableValue) {
-				final TLCMultiVariableValue multiValue = (TLCMultiVariableValue) ((TLCVariableValue) parent).getValue();
-				final TLCVariableValue child = multiValue.asList().get(viewerIndex);
-				viewer.replace(parent, viewerIndex, child);
-				viewer.setHasChildren(child, child.getChildCount() > 0);
-			} else {
-				throw new IllegalArgumentException();
-			}
-		}
-		
-		/* (non-Javadoc)
-		 * @see org.eclipse.jface.viewers.ILazyTreeContentProvider#updateChildCount(java.lang.Object, int)
-		 */
-		public void updateChildCount(Object element, int currentChildCount) {
-			if (element instanceof TLCError) {
-				final TLCError error = (TLCError) element;
-				int traceSize = error.getTraceSize();
-				if (traceSize != currentChildCount) {
-					if (error.isTraceRestricted()) {
-						viewer.setChildCount(element, traceSize + 1);
-					} else {
-						viewer.setChildCount(element, traceSize);
-					}
-				}
-			} else if (element instanceof TLCState) {
-				final TLCState state = (TLCState) element;
-				if (((state.isStuttering() || state.isBackToState()) && currentChildCount != 0)) {
-					viewer.setChildCount(element, 0);
-				} else if (currentChildCount != state.getVariablesAsList().size()) {
-					viewer.setChildCount(element, state.getVariablesAsList().size());
-				}
-			} else if (element instanceof TLCVariable) {
-				final TLCVariable variable = (TLCVariable) element;
-				if (currentChildCount != variable.getChildCount()) {
-					viewer.setChildCount(element, variable.getChildCount());
-				}
-			} else if (element instanceof TLCVariableValue) {
-				final TLCVariableValue value = (TLCVariableValue) element;
-				if (currentChildCount != value.getChildCount()) {
-					viewer.setChildCount(element, value.getChildCount());
-				}
-			} else {
-				throw new IllegalArgumentException();
-			}
-		}
-
-		/* (non-Javadoc)
-		 * @see org.eclipse.jface.viewers.ILazyTreeContentProvider#getParent(java.lang.Object)
-		 */
-		public Object getParent(Object element) {
-			return null;
-		}
-    }
-    
-    /**
-     * Label provider for the tree table. Modified on 30 Aug 2009 by LL to
-     * implement ITableColorProvider instead of IColorProvider. This allows
-     * coloring of individual columns, not just of entire rows.
-     */
-    static class StateLabelProvider extends CellLabelProvider
-    {
-        public static final int NAME = 0;
-        public static final int VALUE = 1;
-
-        public static final int[] COLUMN_WIDTH = { 200, 200 };
-        public static final String[] COLUMN_TEXTS = { "Name", "Value" };
-
-        private final Image stateImage;
-        private final Image varImage;
-        private final Image recordImage;
-        private final Image setImage;
-        private final Image loadMoreImage;
-        
-        public StateLabelProvider()
-        {
-            stateImage = TLCUIActivator.getImageDescriptor("/icons/full/default_co.gif").createImage();
-            varImage = TLCUIActivator.getImageDescriptor("/icons/full/private_co.gif").createImage();
-            recordImage = TLCUIActivator.getImageDescriptor("/icons/full/brkpi_obj.gif").createImage();
-            // setImage = TLCUIActivator.getImageDescriptor("/icons/full/over_co.gif").createImage();
-            setImage = TLCUIActivator.getImageDescriptor("/icons/full/compare_method.gif").createImage();
-            loadMoreImage = TLCUIActivator.getImageDescriptor("/icons/full/add.gif").createImage(); // other candidate is newstream_wiz.gif, nav_go.gif, debugt_obj.gif
-        }
-
-        private Image getColumnImage(Object element, int columnIndex)
-        {
-            if (columnIndex == NAME)
-            {
-            	if (element instanceof LoaderTLCState) {
-            		return loadMoreImage;	
-            	}
-                if (element instanceof TLCState)
-                {
-                    return stateImage;
-                } else if (element instanceof TLCVariable)
-                {
-                    return varImage;
-                } else if (element instanceof TLCNamedVariableValue)
-                {
-                    return recordImage;
-                } else if (element instanceof TLCFcnElementVariableValue)
-                {
-                    return recordImage;
-                }
-                return setImage; // other things appear in unordered collections
-            }
-            return null;
-        }
-
-        private String getColumnText(Object element, int columnIndex)
-        {
-            if (element instanceof TLCState)
-            {
-                TLCState state = (TLCState) element;
-
-                switch (columnIndex) {
-                case NAME:
-                    if (state.isStuttering())
-                    {
-                        return "<Stuttering>";
-                    } else if (state.isBackToState())
-                    {
-                        return "<Back to state " + state.getStateNumber() + ">";
-                    }
-                    return state.getLabel();
-                case VALUE:
-                	if (state instanceof RecordToSourceCoupler.LoaderTLCState) {
-                    	return "";
-                    } else {
-                    	return "State (num = " + state.getStateNumber() + ")";
-                    }
-                    // state.toString();
-                default:
-                    break;
-                }
-            } else if (element instanceof TLCVariable)
-            {
-                TLCVariable var = (TLCVariable) element;
-                switch (columnIndex) {
-                case NAME:
-                    if (var.isTraceExplorerVar())
-                    {
-                        return var.getSingleLineName();
-                    } else
-                    {
-                        return var.getName();
-                    }
-                case VALUE:
-                    return var.getValue().toSimpleString();
-                    // Changed from toString by LL on 30 Aug 2009
-                default:
-                    break;
-                }
-            } else if (element instanceof TLCSetVariableValue || element instanceof TLCSequenceVariableValue
-                    || element instanceof TLCSimpleVariableValue)
-            {
-
-                TLCVariableValue varValue = (TLCVariableValue) element;
-                switch (columnIndex) {
-                case VALUE:
-                    return varValue.toString();
-                case NAME:
-                    return ""; // added by LL on 5 Nov 2009
-                default:
-                    break;
-                }
-            } else if (element instanceof TLCNamedVariableValue)
-            {
-                TLCNamedVariableValue namedValue = (TLCNamedVariableValue) element;
-                switch (columnIndex) {
-                case NAME:
-                    return namedValue.getName();
-                case VALUE:
-                    return ((TLCVariableValue) namedValue.getValue()).toSimpleString();
-                    // Changed from toString by LL on 30 Aug 2009
-                default:
-                    break;
-                }
-            } else if (element instanceof TLCFcnElementVariableValue)
-            {
-                TLCFcnElementVariableValue fcnElementValue = (TLCFcnElementVariableValue) element;
-                switch (columnIndex) {
-                case NAME:
-                    return fcnElementValue.getFrom().toSimpleString();
-                    // Changed from toString by LL on 30 Aug 2009
-                case VALUE:
-                    return ((TLCVariableValue) fcnElementValue.getValue()).toSimpleString();
-                    // Changed from toString by LL on 30 Aug 2009
-                default:
-                    break;
-                }
-            } else if (element instanceof TLCRecordVariableValue)
-            {
-                TLCRecordVariableValue recordValue = (TLCRecordVariableValue) element;
-                switch (columnIndex) {
-                case NAME:
-                    return "";
-                case VALUE:
-                    return recordValue.toSimpleString();
-                default:
-                    break;
-                }
-            } else if (element instanceof TLCFunctionVariableValue)
-            {
-                TLCFunctionVariableValue fcnValue = (TLCFunctionVariableValue) element;
-                switch (columnIndex) {
-                case NAME:
-                    return "";
-                case VALUE:
-                    return fcnValue.toSimpleString();
-                default:
-                    break;
-                }
-            }
-
-            return null;
-        }
-
-		private static final Map<String, Color> LOCATION_COLOR_MAP = new ConcurrentHashMap<String, Color>();
-		//TODO Convert to Toolbox preference once this features proves useful.
-		private static final boolean COLORING_SYSTEM_PROPERTY = Boolean
-				.getBoolean(TLCErrorView.class.getName() + ".coloring");
-
-        /**
-         * The following method sets the background color of a row or column of
-         * the table. It highlights the entire row for an added or deleted item.
-         * For a changed value, only the value is highlighted.
-         */
-		private Color getBackground(Object element, int column) {
-            if (element instanceof TLCVariable) {
-				final TLCVariable var = (TLCVariable) element;
-				if (var.isChanged() && column == VALUE) {
-					return TLCUIActivator.getDefault().getChangedColor();
-				}
-			} else if (element instanceof TLCVariableValue) {
-				final TLCVariableValue value = (TLCVariableValue) element;
-				if (value.isChanged()) {
-					if (column == VALUE) {
-						return TLCUIActivator.getDefault().getChangedColor();
-					}
-				} else if (value.isAdded()) {
-					// Added takes precedence over deleted. E.g. a value can be
-					// added to a set in this state and be removed in the next
-					// state.
-					return TLCUIActivator.getDefault().getAddedColor();
-				} else if (value.isDeleted()) {
-					return TLCUIActivator.getDefault().getDeletedColor();
-				}
-			} else if (COLORING_SYSTEM_PROPERTY && element instanceof TLCState) {
-				// Assign a color to each location to make actions in the error
-				// viewer more easily distinguishable.
-				final TLCState state = (TLCState) element;
-				Location moduleLocation = state.getModuleLocation();
-				if (moduleLocation == null) {
-					return null;
-				}
-				Color c = LOCATION_COLOR_MAP.get(moduleLocation.toString());
-				if (c == null) {
-					int color = SWT.COLOR_WHITE + (2 * LOCATION_COLOR_MAP.size());
-					c = TLCUIActivator.getColor(color);
-					LOCATION_COLOR_MAP.put(state.getModuleLocation().toString(), c);
-				}
-				return c;
-			}
+	public TLCError getTrace() {
+		if (errorTraceTreeViewer == null) {
 			return null;
 		}
-
-        private Color getForeground(Object element, int i)
-        {
-            return null;
-        }
-
-		private Font getFont(Object element, int columnIndex) {
-			boolean returnBoldVersion = false;
-			
-			if (element instanceof TLCVariable) {
-				if (((TLCVariable) element).isTraceExplorerVar()) {
-					returnBoldVersion = true;
-				}
-			} else if (element instanceof RecordToSourceCoupler.LoaderTLCState) {
-				returnBoldVersion = true;
-			}
-
-			final FontRegistry fr = JFaceResources.getFontRegistry();
-			return returnBoldVersion ? fr.getBold(JFACE_ERROR_TRACE_ID) : fr.get(JFACE_ERROR_TRACE_ID);
-		}
-
-        /* (non-Javadoc)
-         * @see org.eclipse.jface.viewers.BaseLabelProvider#dispose()
-         */
-        public void dispose()
-        {
-            /*
-             * Remove images
-             */
-            stateImage.dispose();
-            varImage.dispose();
-            recordImage.dispose();
-            setImage.dispose();
-            loadMoreImage.dispose();
-           super.dispose();
-        }
-
-		/* (non-Javadoc)
-		 * @see org.eclipse.jface.viewers.IToolTipProvider#getToolTipText(java.lang.Object)
-		 */
-		public String getToolTipText(Object element) {
-			if (element instanceof LoaderTLCState) {
-				return "Double-click to load more states.\nIf the number of states is large, this might take a few seconds.";
-			}
-			return DEFAULT_TOOL_TIP;
-		}
-
-		/* (non-Javadoc)
-		 * @see org.eclipse.jface.viewers.CellLabelProvider#update(org.eclipse.jface.viewers.ViewerCell)
-		 */
-		public void update(ViewerCell cell) {
-			// labels
-			cell.setText(getColumnText(cell.getElement(), cell.getColumnIndex()));
-			
-			// images
-			cell.setImage(getColumnImage(cell.getElement(), cell.getColumnIndex()));
-			
-			// font
-			cell.setFont(getFont(cell.getElement(), cell.getColumnIndex()));
-			
-			// colors
-			cell.setForeground(getForeground(cell.getElement(), cell.getColumnIndex()));
-			cell.setBackground(getBackground(cell.getElement(), cell.getColumnIndex()));
-		}
-    }
-
-	public TLCError getTrace()
-    {
-        if (variableViewer == null)
-        {
-            return null;
-        }
-        return (TLCError) variableViewer.getInput();
-    }
+		return errorTraceTreeViewer.getCurrentTrace();
+	}
 
 	public Model getModel() {
-		return model;
+		return modelEditor.getModel();
+	}
+	
+	private void setModelEditor(final ModelEditor associatedModelEditor) {
+		modelEditor = associatedModelEditor;
+		if (errorTraceTreeViewer != null) {
+			errorTraceTreeViewer.setModelEditor(associatedModelEditor);
+		}
 	}
 
     private class HelpAction extends Action
@@ -1414,15 +828,19 @@ public class TLCErrorView extends ViewPart
      * 
      * @param states
      */
-    void setTraceInput(TLCError error)
-    {
+	void setTraceInput(final TLCError error, final boolean isNew) {
+		if (isNew) {
+			unfilteredInput = error;
+		}
+		
 		// If itemCount is large (>10.000 items), the underlying OS window
 		// toolkit can be slow. As a possible fix, look into
 		// http://www.eclipse.org/nattable/. For background, read
 		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=129457#c27
     	error.restrictTraceTo(numberOfStatesToShow);
-		variableViewer.getTree().setItemCount(error.getTraceSize() + (error.isTraceRestricted() ? 1 : 0));
-        variableViewer.setInput(error);
+    	final TreeViewer treeViewer = errorTraceTreeViewer.getTreeViewer();
+    	treeViewer.getTree().setItemCount(error.getTraceSize() + (error.isTraceRestricted() ? 1 : 0));
+    	treeViewer.setInput(error);
 		// If the number of states in the trace is sufficiently small, eagerly
 		// expand all root level items (which translates to the states
 		// variables). This causes the TreeViewer to correctly determine the
@@ -1437,7 +855,7 @@ public class TLCErrorView extends ViewPart
         // https://bugs.eclipse.org/bugs/show_bug.cgi?id=266189
         final int level = 1;
         if (error.getTraceSize(level) < 1000) {
-        	variableViewer.expandToLevel(level + 1); // viewer counts root node. 
+        	treeViewer.expandToLevel(level + 1); // viewer counts root node. 
         }
         if (!error.isTraceEmpty())
         {
@@ -1448,12 +866,118 @@ public class TLCErrorView extends ViewPart
         }
     }
 
-	public void setOriginalTraceShown(boolean b) {
-		this.model.setOriginalTraceShown(b);
+	public void setOriginalTraceShown(final boolean b) {
+		modelEditor.getModel().setOriginalTraceShown(b);
 	}
 	
 	TreeViewer getViewer() {
-		return variableViewer;
+		return errorTraceTreeViewer.getTreeViewer();
+	}
+	
+	private void addVariableFamilyToFiltering(final TLCVariable protoVariable) {
+		for (final TLCState state : unfilteredInput.getStates(TLCError.Length.ALL)) {
+			for (final TLCVariable variable : state.getVariablesAsList()) {
+				if (protoVariable.representsTheSameAs(variable)) {
+					currentErrorTraceFilterSet.add(variable);
+				}
+			}
+		}
+	}
+	
+	private void performVariableViewPopulation(final EnumSet<FilterType> filters) {
+        filteredStateIndexMap.clear();
+		if (filters.contains(FilterType.NONE)) {
+			setTraceInput(unfilteredInput, false);
+			final GridData gd = (GridData)valueReflectsFiltering.getLayoutData();
+			gd.exclude = true;
+			valueReflectsFiltering.setLayoutData(gd);
+			valueReflectsFiltering.setVisible(false);
+		} else {
+			final TLCError filtered = unfilteredInput.clone();
+			
+			final GridData gd = (GridData)valueReflectsFiltering.getLayoutData();
+			gd.exclude = false;
+			valueReflectsFiltering.setLayoutData(gd);
+			valueReflectsFiltering.setVisible(true);
+			if (filters.contains(FilterType.VARIABLES) && (currentErrorTraceFilterSet.size() > 0)) {
+				// It would be much nicer (from both a time and space perspective) were there a veto-ing
+				//		ability provided by TableViewer - like "vetoRow(Object element)". Alas, there is not and
+				//		so we do this clone and filter of the input data.
+				int index = 0;
+				for (final TLCState filteredState : filtered.getStates(TLCError.Length.ALL)) {
+					final List<TLCVariable> variables = filteredState.getVariablesAsList();
+					final ArrayList<TLCVariable> removals = new ArrayList<>();
+					
+					for (final TLCVariable variable : variables) {
+						for (final TLCVariable filterVariable : currentErrorTraceFilterSet) {
+							if (filterVariable.representsTheSameAs(variable)) {
+								removals.add(variable);
+								break;
+							}
+						}
+					}
+					
+					variables.removeAll(removals);
+					
+					filteredStateIndexMap.put(filteredState, new Integer(index));
+					index++;
+				}
+			}
+
+			if (filters.contains(FilterType.MODIFIED_VALUES_MODIFIED_FRAMES)) {
+				final ArrayList<TLCState> emptyStates = new ArrayList<>();
+				
+				filteredStateIndexMap.clear();
+				int index = 0;
+				for (final TLCState state : filtered.getStates(TLCError.Length.ALL)) {
+					final List<TLCVariable> variables = state.getVariablesAsList();
+					final ArrayList<TLCVariable> removals = new ArrayList<>();
+					
+					for (final TLCVariable variable : variables) {
+						if (!variable.isChanged()) {
+							removals.add(variable);
+						}
+					}
+					
+					variables.removeAll(removals);
+					if (variables.size() == 0) {
+						emptyStates.add(state);
+					} else {
+						filteredStateIndexMap.put(state, new Integer(index));
+					}
+					
+					index++;
+				}
+				
+				filtered.removeStates(emptyStates);
+			} else if (filters.contains(FilterType.MODIFIED_VALUES_ALL_FRAMES)) {
+				final Set<TLCVariable> changedVariables = new HashSet<>();
+				
+				for (final TLCState state : filtered.getStates(TLCError.Length.ALL)) {
+					final List<TLCVariable> variables = state.getVariablesAsList();
+					
+					for (final TLCVariable variable : variables) {
+						if (variable.isChanged()) {
+							changedVariables.add(variable);
+						}
+					}
+				}
+				
+				filteredStateIndexMap.clear();
+				int index = 0;
+				for (final TLCState filteredState : filtered.getStates(TLCError.Length.ALL)) {
+					final List<TLCVariable> variables = filteredState.getVariablesAsList();
+					
+					variables.retainAll(changedVariables);
+					
+					filteredStateIndexMap.put(filteredState, new Integer(index));
+					index++;
+				}
+			}
+			
+			setTraceInput(filtered, false);
+		}
+		valueReflectsFiltering.getParent().layout(true, true);
 	}
 	
 	
@@ -1485,11 +1009,97 @@ public class TLCErrorView extends ViewPart
 	}
 	
 	
+	private class FilterErrorTrace extends Action {
+		private static final String DEFAULT_TOOL_TIP_TEXT
+					= "Click to select variables and expressions to omit from the trace display; "
+									+ "ALT-click on an individual item below to omit it immediately.";
+		private static final String SELECTED_TOOL_TIP_TEXT = "Click to display all variables and expressions.";
+		
+		FilterErrorTrace() {
+			super("Filter the displayed variables and expressions", AS_CHECK_BOX);
+			
+			final ImageDescriptor id = TLCUIActivator.getImageDescriptor("icons/elcl16/trace_filter.png");
+			setImageDescriptor(id);
+			
+			setToolTipText(DEFAULT_TOOL_TIP_TEXT);
+		}
+		
+	    /**
+	     * {@inheritDoc}
+	     */
+		@Override
+		public void setChecked(final boolean flag) {
+			super.setChecked(flag);
+			
+			setToolTipText(SELECTED_TOOL_TIP_TEXT);
+		}
+		
+	    /**
+	     * {@inheritDoc}
+	     */
+		@Override
+		public void run() {
+			if (isChecked()) {
+				setToolTipText(SELECTED_TOOL_TIP_TEXT);
+			} else {
+				setToolTipText(DEFAULT_TOOL_TIP_TEXT);
+			}
+			
+			final TLCError trace = errorTraceTreeViewer.getCurrentTrace();
+			final List<TLCState> states = trace.getStates();
+			
+			if (states.size() == 0) {
+				return;
+			}
+			
+			if (isChecked()) {
+				final Shell s = PlatformUI.getWorkbench().getDisplay().getActiveShell();
+				final TLCState state = states.get(0);
+				final ErrorViewTraceFilterDialog dialog = new ErrorViewTraceFilterDialog(s, state.getVariablesAsList());
+
+				dialog.setSelection(currentErrorTraceFilterSet);
+				if (dialog.open() == Window.OK) { // (Currently can only ever be Windows.OK)
+					currentErrorTraceFilterSet = dialog.getSelection();
+					
+					final ErrorViewTraceFilterDialog.MutatedFilter mutated = dialog.getMutatedFilterSelection();
+					
+					if (ErrorViewTraceFilterDialog.MutatedFilter.NO_FILTER.equals(mutated)) {
+						performVariableViewPopulation(EnumSet.of(FilterType.VARIABLES));
+					} else {
+						final FilterType filterType;
+						
+						switch (mutated) {
+							case CHANGED_ALL_FRAMES:
+								filterType = FilterType.MODIFIED_VALUES_ALL_FRAMES;
+								break;
+							default:
+								filterType = FilterType.MODIFIED_VALUES_MODIFIED_FRAMES;
+								break;
+						}
+						
+						performVariableViewPopulation(EnumSet.of(FilterType.VARIABLES, filterType));
+					}
+				}
+			} else {
+				performVariableViewPopulation(EnumSet.of(FilterType.NONE));
+			}
+		}
+	}	
+	
+	
 	private static abstract class ShiftClickAction extends Action implements Listener {
 		private boolean holdDown = false;
 
-		public ShiftClickAction(final String text, final ImageDescriptor imageDescriptor) {
+		public ShiftClickAction(final String text, final ImageDescriptor imageDescriptor, final Display display) {
 			super(text, imageDescriptor);
+			display.addFilter(SWT.KeyDown, this);
+			display.addFilter(SWT.KeyUp, this);
+		}
+		
+		public ShiftClickAction(final String text, final int style, final Display display) {
+			super(text, style);
+			display.addFilter(SWT.KeyDown, this);
+			display.addFilter(SWT.KeyUp, this);
 		}
 
 		@Override
@@ -1510,4 +1120,55 @@ public class TLCErrorView extends ViewPart
 			}
 		}
 	}
+	
+	
+	private class ExportErrorTrace2Clipboard extends ShiftClickAction implements ISelectionChangedListener {
+		private static final String DEFAULT_TOOL_TIP_TEXT
+			= "Click to export error-trace to clipboard as\nsequence of records. "
+					+ "Shift-click to \nomit the action's position ("
+					+ TLAConstants.TraceExplore.POSITION + "), \nname, and location.";
+		
+		
+		private final Display display;
+		
+		ExportErrorTrace2Clipboard(final Display display) {
+			super("Export the error-trace to the OS clipboard.", AS_PUSH_BUTTON, display);
+			this.display = display;
+			
+			errorTraceTreeViewer.getTreeViewer().addSelectionChangedListener(this);
+			
+			setImageDescriptor(TLCUIActivator
+					.getImageDescriptor("platform:/plugin/org.eclipse.ui.ide/icons/full/etool16/export_wiz.png"));
+			
+			setToolTipText(DEFAULT_TOOL_TIP_TEXT);
+		}
+		
+		/* Disable export when variables are part of the selection */
+		@Override
+		public void selectionChanged(SelectionChangedEvent event) {
+			// it seems impossible this could ever be null since we treat it as non-null in the constructor.
+			if (errorTraceTreeViewer == null) {
+				this.setEnabled(false);
+			}
+			this.setEnabled(errorTraceTreeViewer.getCurrentTrace().hasTrace());
+		}
+		
+		@Override
+		public void runWithKey(final boolean excludeActionHeader) {
+			// it seems impossible this could ever be null since we treat it as non-null in the constructor.
+			if (errorTraceTreeViewer == null) {
+				return;
+			}
+			final TLCError trace = errorTraceTreeViewer.getCurrentTrace();
+			if (!trace.hasTrace()) {
+				// safeguard in addition to isEnabled 
+				return;
+			}
+
+			final Clipboard clipboard = new Clipboard(display);
+			clipboard.setContents(new Object[] { trace.toSequenceOfRecords(!excludeActionHeader) },
+					new Transfer[] { TextTransfer.getInstance() });
+			clipboard.dispose();
+		}
+	}	
 }
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/AssignmentWizard.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/AssignmentWizard.java
index 740052597bc214a00ca930c3d2ec3cd14e7c5052..85f79bcf1b91e92dd7ce7d521cb531750819b3b4 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/AssignmentWizard.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/AssignmentWizard.java
@@ -2,7 +2,8 @@ package org.lamport.tla.toolbox.tool.tlc.ui.wizard;
 
 import org.eclipse.jface.wizard.Wizard;
 import org.eclipse.jface.wizard.WizardDialog;
-import org.lamport.tla.toolbox.tool.tlc.model.Assignment;
+
+import tlc2.model.Assignment;
 
 /**
  * Wizard for editing a constant assignement
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/AssignmentWizardPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/AssignmentWizardPage.java
index bd4844678c8cc21ae978ad282a5f9dc3962979e1..1d2637741de001c800a74aae47e0401c074b7ef9 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/AssignmentWizardPage.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/AssignmentWizardPage.java
@@ -15,14 +15,14 @@ import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Combo;
 import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.lamport.tla.toolbox.tool.tlc.model.Assignment;
-import org.lamport.tla.toolbox.tool.tlc.model.TypedSet;
+import org.eclipse.ui.PlatformUI;
 import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper;
 import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper;
 import org.lamport.tla.toolbox.util.UIHelper;
 
 import tla2sany.semantic.OpDefNode;
+import tlc2.model.Assignment;
+import tlc2.model.TypedSet;
 
 /**
  * @author Simon Zambrovski
@@ -59,18 +59,8 @@ public class AssignmentWizardPage extends WizardPage
     // selection adapter reacting on the choice
     final private SelectionListener optionSelectionAdapter = new SelectionAdapter() {
         @Override
-        public void widgetSelected(SelectionEvent e)
-        {
-            boolean modelValueSelected = optionModelValue.getSelection();
-
-            if (modelValueSelected)
-            {
-                source.getTextWidget().setBackground(getControl().getBackground());
-            } else
-            {
-                source.getTextWidget().setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
-            }
-            source.getControl().setEnabled(!modelValueSelected);
+		public void widgetSelected(SelectionEvent e) {
+        	configureTextWidget(optionModelValue.getSelection());
 
             if (fieldFlags == AssignmentWizard.SHOW_OPTION)
             {
@@ -91,6 +81,17 @@ public class AssignmentWizardPage extends WizardPage
         setTitle(action);
         setDescription(description);
     }
+    
+    private void configureTextWidget(final boolean forModelValue) {
+    	final StyledText textWidget = source.getTextWidget();
+    	
+		if (forModelValue) {
+			textWidget.setBackground(textWidget.getParent().getBackground());
+		} else {
+			textWidget.setBackground(PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_WHITE));
+		}		
+		textWidget.setEnabled(!forModelValue);
+    }
 
     /* (non-Javadoc)
      * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
@@ -120,7 +121,7 @@ public class AssignmentWizardPage extends WizardPage
 
         // set data
         source.setDocument(new Document(assignment.getRight()));
-        StyledText styledText = source.getTextWidget();
+        final StyledText styledText = source.getTextWidget();
         styledText.addModifyListener(new ModifyListener() {
 
             public void modifyText(ModifyEvent e)
@@ -212,6 +213,7 @@ public class AssignmentWizardPage extends WizardPage
                 optionSetModelValues.addSelectionListener(optionSelectionAdapter);
 
                 // set the value from the assignment object
+                configureTextWidget(assignment.isModelValue());
                 if (assignment.isModelValue())
                 {
                     // single model value
@@ -221,7 +223,6 @@ public class AssignmentWizardPage extends WizardPage
                         smvTypeCombo.setEnabled(false);
                         optionSMVUntyped.setEnabled(false);
                         optionModelValue.setSelection(assignment.isModelValue());
-                        source.getTextWidget().setBackground(container.getBackground());
                         // set of model values
                     } else
                     {
@@ -236,6 +237,9 @@ public class AssignmentWizardPage extends WizardPage
 							smvTypeCombo.setText(set.getType());
 			                smvTypeCombo.setEnabled(true);
 						}
+						
+						styledText.setBackground(PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_WHITE));
+						styledText.setEnabled(true);
                     }
                 } else
                 {
@@ -266,15 +270,18 @@ public class AssignmentWizardPage extends WizardPage
                 optionOrdinaryValue.addSelectionListener(optionSelectionAdapter);
                 optionModelValue.addSelectionListener(optionSelectionAdapter);
 
+                configureTextWidget(assignment.isModelValue());
                 // set the value from the assignment object
                 if (assignment.isModelValue())
                 {
                     // single model value
-                    if (!assignment.isSetOfModelValues())
-                    {
+                    if (!assignment.isSetOfModelValues()) {
                         optionModelValue.setSelection(assignment.isModelValue());
                         source.getTextWidget().setBackground(container.getBackground());
                         // set of model values
+                    } else {
+						styledText.setBackground(PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_WHITE));
+						styledText.setEnabled(true);
                     }
                 } else
                 {
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/FormulaWizard.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/FormulaWizard.java
index 6b22a6cb50e86d57ca22e9da40b86efcb254f466..e47294683b20fa8e5aa3d9d8c01af65719aa199a 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/FormulaWizard.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/FormulaWizard.java
@@ -2,9 +2,10 @@ package org.lamport.tla.toolbox.tool.tlc.ui.wizard;
 
 import org.eclipse.jface.text.Document;
 import org.eclipse.jface.wizard.Wizard;
-import org.lamport.tla.toolbox.tool.tlc.model.Formula;
 import org.lamport.tla.toolbox.tool.tlc.ui.util.FormHelper;
 
+import tlc2.model.Formula;
+
 /**
  * A wizard for entering formulas
  * @author Simon Zambrovski
diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/TypingWizardPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/TypingWizardPage.java
index 397c8617ac09955c3f0128947a7988f9881e751a..d35e8b94516d4e75e0795b443676cbf232c46e6f 100644
--- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/TypingWizardPage.java
+++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/wizard/TypingWizardPage.java
@@ -10,10 +10,11 @@ import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Combo;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Label;
-import org.lamport.tla.toolbox.tool.tlc.model.Assignment;
-import org.lamport.tla.toolbox.tool.tlc.model.TypedSet;
 import org.lamport.tla.toolbox.util.UIHelper;
 
+import tlc2.model.Assignment;
+import tlc2.model.TypedSet;
+
 /**
  * A wizard page for typing sets of model values
  * @author Simon Zambrovski
diff --git a/org.lamport.tla.toolbox.tool.tlc/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.tool.tlc/META-INF/MANIFEST.MF
index c267356c51e34edeecaa3013c27fb03c6de511b0..98604215258d2a84308ea2dbc6fba45d322211d4 100644
--- a/org.lamport.tla.toolbox.tool.tlc/META-INF/MANIFEST.MF
+++ b/org.lamport.tla.toolbox.tool.tlc/META-INF/MANIFEST.MF
@@ -7,6 +7,7 @@ Bundle-Activator: org.lamport.tla.toolbox.tool.tlc.TLCActivator
 Bundle-Vendor: Simon Zambrovski, Leslie Lamport
 Require-Bundle: org.eclipse.ui,
  org.eclipse.core.runtime,
+ org.eclipse.core.filesystem;bundle-version="1.7.200",
  org.eclipse.debug.core,
  org.lamport.tla.toolbox,
  org.eclipse.jdt.launching;bundle-version="3.4.1",
@@ -23,7 +24,7 @@ Export-Package: org.lamport.tla.toolbox.tool.tlc,
  org.lamport.tla.toolbox.tool.tlc.model,
  org.lamport.tla.toolbox.tool.tlc.output,
  org.lamport.tla.toolbox.tool.tlc.result,
- org.lamport.tla.toolbox.tool.tlc.traceexplorer,
  org.lamport.tla.toolbox.tool.tlc.util
-Import-Package: org.eclipse.ui.part
+Import-Package: org.eclipse.ui.console,
+ org.eclipse.ui.part
 Automatic-Module-Name: org.lamport.tla.toolbox.tool.tlc
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/ITLCJobStatus.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/ITLCJobStatus.java
index f2c113ddb92935e07e3fc2f6edc5ec1d5152be8b..18d63fd5159807fe0a3282c455cc3c1896e78e66 100644
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/ITLCJobStatus.java
+++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/ITLCJobStatus.java
@@ -1,5 +1,6 @@
 package org.lamport.tla.toolbox.tool.tlc.job;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
 
@@ -14,4 +15,6 @@ public interface ITLCJobStatus extends IStatus {
 	void killTLC();
 
 	boolean isReconnect();
+
+	void getJavaFlightRecording() throws IOException;
 }
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCJob.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCJob.java
index 7e7cc9da00eb2b49f748ef0c7fd40c54af933939..2895e958978c11847717cc4ca07354d8b2c32771 100644
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCJob.java
+++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCJob.java
@@ -25,6 +25,7 @@ import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants;
 import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationDefaults;
 import org.lamport.tla.toolbox.tool.tlc.launch.TraceExplorerDelegate;
 import org.lamport.tla.toolbox.tool.tlc.model.Model;
+import org.lamport.tla.toolbox.tool.tlc.model.ModelCoverage;
 import org.lamport.tla.toolbox.tool.tlc.result.IResultPresenter;
 import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper;
 import org.lamport.tla.toolbox.util.ResourceHelper;
@@ -32,6 +33,7 @@ import org.lamport.tla.toolbox.util.ToolboxJob;
 
 import tlc2.TLCGlobals;
 import tlc2.util.FP64;
+import util.TLAConstants;
 
 /**
  * Abstract TLC job
@@ -98,9 +100,9 @@ public abstract class TLCJob extends AbstractJob implements IModelConfigurationC
             this.outFile = this.launchDir.getFile(ModelHelper.TE_FILE_OUT);
         } else
         {
-            this.rootModule = this.launchDir.getFile(ModelHelper.FILE_TLA);
-            this.cfgFile = this.launchDir.getFile(ModelHelper.FILE_CFG);
-            this.outFile = this.launchDir.getFile(ModelHelper.FILE_OUT);
+            this.rootModule = this.launchDir.getFile(TLAConstants.Files.MODEL_CHECK_TLA_FILE);
+            this.cfgFile = this.launchDir.getFile(TLAConstants.Files.MODEL_CHECK_CONFIG_FILE);
+            this.outFile = this.launchDir.getFile(TLAConstants.Files.MODEL_CHECK_OUTPUT_FILE);
         }
     }
 
@@ -276,7 +278,7 @@ public abstract class TLCJob extends AbstractJob implements IModelConfigurationC
 
     protected boolean collectCoverage() throws CoreException {
 		final ILaunchConfiguration launchConfiguration = launch.getLaunchConfiguration();
-		if (launchConfiguration.getAttribute(LAUNCH_COVERAGE, LAUNCH_COVERAGE_DEFAULT) != Model.Coverage.OFF.ordinal()) {
+		if (launchConfiguration.getAttribute(LAUNCH_COVERAGE, LAUNCH_COVERAGE_DEFAULT) != ModelCoverage.OFF.ordinal()) {
 			return launchConfiguration.getAttribute(MODEL_BEHAVIOR_SPEC_TYPE,
 					MODEL_BEHAVIOR_TYPE_DEFAULT) != MODEL_BEHAVIOR_TYPE_NO_SPEC;
 		} else {
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCProcessJob.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCProcessJob.java
index a8f678d99fc80d37c4f7b9f8d10b78a852050e93..bebf3280fdda9875d9b46c13ac17f2f0d575a477 100644
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCProcessJob.java
+++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCProcessJob.java
@@ -1,8 +1,13 @@
 package org.lamport.tla.toolbox.tool.tlc.job;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
@@ -15,9 +20,15 @@ import org.eclipse.debug.core.ILaunch;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.ILaunchManager;
 import org.eclipse.debug.core.model.IProcess;
+import org.eclipse.debug.core.model.IStreamsProxy;
 import org.eclipse.jdt.launching.IVMInstall;
 import org.eclipse.jdt.launching.IVMRunner;
 import org.eclipse.jdt.launching.VMRunnerConfiguration;
+import org.eclipse.ui.console.ConsolePlugin;
+import org.eclipse.ui.console.IConsole;
+import org.eclipse.ui.console.IConsoleManager;
+import org.eclipse.ui.console.IOConsole;
+import org.eclipse.ui.console.IOConsoleInputStream;
 import org.lamport.tla.toolbox.Activator;
 import org.lamport.tla.toolbox.spec.Spec;
 import org.lamport.tla.toolbox.tool.ToolboxHandle;
@@ -238,9 +249,19 @@ public class TLCProcessJob extends TLCJob
 
                 listener = new BroadcastStreamListener(model, kind);
 
-                process.getStreamsProxy().getOutputStreamMonitor().addListener(listener);
-                process.getStreamsProxy().getErrorStreamMonitor().addListener(listener);
-
+                // stdout, stderr, stdin of the forked TLC process.
+                final IStreamsProxy streamsProxy = process.getStreamsProxy();
+				streamsProxy.getOutputStreamMonitor().addListener(listener);
+				streamsProxy.getErrorStreamMonitor().addListener(listener);
+				
+				// This is a reader wrapping the input stream of the Toolbox console. In other
+				// words, if a user types a string into the Toolbox console, we can read the
+				// string from the reader. Iff consoleStdIn is not null (there is a Toolbox
+				// console), the loop below reads from consoleStdIn and writes (forwards) the
+				// string to stdin of the TLC process.  Because the while loop sleeps for a
+				// second, the response time isn't perfect but is good enough for now.
+				final BufferedReader consoleReader = getConsoleReader();
+				
                 // loop until the process is terminated
 				while (checkAndSleep()) {
 					// check the cancellation status
@@ -293,6 +314,16 @@ public class TLCProcessJob extends TLCJob
 						tlcEndTime = System.currentTimeMillis();
 						return Status.CANCEL_STATUS;
 					}
+					
+					
+					try {
+						if (consoleReader != null && consoleReader.ready()) {
+							streamsProxy.write(consoleReader.readLine() + "\n");
+						}
+					} catch (IOException e) {
+						throw new CoreException(new Status(IStatus.ERROR, TLCActivator.PLUGIN_ID,
+								"Error reading from Toolbox console or writing to stdin of TLC process", e));
+					}
 				}
 
                 // step 6
@@ -340,6 +371,20 @@ public class TLCProcessJob extends TLCJob
         }
     }
 
+	private static BufferedReader getConsoleReader() {
+		final IConsoleManager consoleManager = ConsolePlugin.getDefault().getConsoleManager();
+		final List<IConsole> tlcConsole = Arrays.asList(consoleManager.getConsoles()).stream()
+				.filter(c -> "TLC-Console".equals(c.getName())).collect(Collectors.toList());
+		if (!tlcConsole.isEmpty()) {
+			final IConsole iConsole = tlcConsole.get(0);
+			if (iConsole instanceof IOConsole) {
+				IOConsoleInputStream inputStream = ((IOConsole) iConsole).getInputStream();
+				return new BufferedReader(new InputStreamReader(inputStream));
+			}
+		}
+		return null;
+	}
+
 	protected String getOptimalFPsetImpl() throws CoreException {
 		return launch.getLaunchConfiguration().getAttribute(LAUNCH_FPSET_IMPL, (String) null);
 	}
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TraceExplorerJob.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TraceExplorerJob.java
index a9d4e0fe560628d3e05779952d421cddfff6b784..9a03cf17919feb3015f1eb2476eadd3f0c24c23d 100644
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TraceExplorerJob.java
+++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TraceExplorerJob.java
@@ -5,10 +5,10 @@ import java.util.List;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.debug.core.ILaunch;
 import org.eclipse.swt.widgets.Display;
-import org.lamport.tla.toolbox.tool.tlc.model.TraceExpressionModelWriter;
 
 import tlc2.tool.fp.FPSetFactory;
 import tlc2.tool.impl.SpecProcessor;
+import util.TLAConstants;
 
 /**
  * Extends {@link TLCProcessJob}.
@@ -70,7 +70,7 @@ public class TraceExplorerJob extends TLCProcessJob
 	protected List<String> getAdditionalVMArgs() throws CoreException {
 		final List<String> additionalVMArgs = super.getAdditionalVMArgs();
 		additionalVMArgs.add(
-				String.format("-D%s=%s", SpecProcessor.LAZY_CONSTANT_OPERATORS, TraceExpressionModelWriter.POSITION));
+				String.format("-D%s=%s", SpecProcessor.LAZY_CONSTANT_OPERATORS, TLAConstants.TraceExplore.POSITION));
 		return additionalVMArgs;
 	}
 
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/IModelConfigurationConstants.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/IModelConfigurationConstants.java
index 5e39863dd558beaa6848624f49052f044d94f660..18e1588ca0fb7f4fd2149df9d0fb6dda137381d1 100644
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/IModelConfigurationConstants.java
+++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/IModelConfigurationConstants.java
@@ -3,8 +3,7 @@ package org.lamport.tla.toolbox.tool.tlc.launch;
 /**
  * @author Simon Zambrovski
  */
-public interface IModelConfigurationConstants extends IConfigurationConstants
-{
+public interface IModelConfigurationConstants extends IConfigurationConstants {
     /**
      * Comments
      */
@@ -89,20 +88,9 @@ public interface IModelConfigurationConstants extends IConfigurationConstants
      */
     public static final String MODEL_EXPRESSION_EVAL = "modelExpressionEval";
     /**
-     * Conjunction of variable values in the initial state of a trace
-     * Should only include spec variables, not trace expression variables.
+     * Extra modules to extended by TE.tla.
      */
-    public static final String TRACE_EXPLORE_INIT = "traceExploreInit";
-    /**
-     * Disjunction of actions used for trace exploration without the trace
-     * expression variables.
-     */
-    public static final String TRACE_EXPLORE_NEXT = "traceExploreNext";
-    /**
-     * expressions to be evaluated at each state of the trace
-     * when the trace explorer is run
-     */
-    public static final String TRACE_EXPLORE_EXPRESSIONS = "traceExploreExpressions";
+    public static final String TRACE_EXPLORE_EXTENDS = "traceExploreExtends";
     
     /**
      * a bitwise OR'd value representing which of the closeable tabs should be open on a model editor opening
@@ -115,5 +103,18 @@ public interface IModelConfigurationConstants extends IConfigurationConstants
 	public static final int EDITOR_OPEN_TAB_NONE = 0;
 	public static final int EDITOR_OPEN_TAB_ADVANCED_MODEL = 1 << 1;
 	public static final int EDITOR_OPEN_TAB_ADVANCED_TLC = 1 << 2;
-
+	public static final int EDITOR_OPEN_TAB_RESULTS = 1 << 3;
+    
+    /**
+     * an integer representing the model version - we'll probably use YYYYMMDD
+     */
+    public static final String MODEL_VERSION = "modelVersion";
+    
+    /**
+     * values to use with the {@link #MODEL_VERSION} attribute
+     */
+    public static final int VERSION_160 = 20190710;
+    // this value needn't be cemented before release, as long as kept consistently increasing during development
+    public static final int VERSION_161 = 20191005;
+    
 }
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TLCModelLaunchDelegate.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TLCModelLaunchDelegate.java
index 7db19e7d1f9c177db6f47057f59d6f6d51f0b24a..aebc2f6ddb47e28e2faeb9910cfb96cfb9ca8a52 100644
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TLCModelLaunchDelegate.java
+++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TLCModelLaunchDelegate.java
@@ -7,14 +7,22 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.net.URL;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Hashtable;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Random;
+import java.util.Set;
 import java.util.Vector;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
 import org.eclipse.core.internal.resources.ResourceException;
@@ -33,7 +41,7 @@ import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
 import org.eclipse.core.runtime.jobs.IJobChangeEvent;
 import org.eclipse.core.runtime.jobs.ISchedulingRule;
 import org.eclipse.core.runtime.jobs.Job;
@@ -46,14 +54,18 @@ import org.eclipse.debug.core.Launch;
 import org.eclipse.debug.core.model.IProcess;
 import org.eclipse.debug.core.model.IStreamsProxy;
 import org.eclipse.debug.core.model.LaunchConfigurationDelegate;
+import org.eclipse.jface.dialogs.IDialogConstants;
 import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.MessageDialogWithToggle;
 import org.eclipse.jface.text.FindReplaceDocumentAdapter;
 import org.eclipse.jface.text.IDocument;
+import org.eclipse.swt.SWT;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.editors.text.FileDocumentProvider;
 import org.eclipse.ui.part.FileEditorInput;
+import org.lamport.tla.toolbox.spec.Module;
 import org.lamport.tla.toolbox.tool.IParseResult;
 import org.lamport.tla.toolbox.tool.ToolboxHandle;
 import org.lamport.tla.toolbox.tool.tlc.TLCActivator;
@@ -61,26 +73,31 @@ import org.lamport.tla.toolbox.tool.tlc.job.DistributedTLCJob;
 import org.lamport.tla.toolbox.tool.tlc.job.ITLCJobStatus;
 import org.lamport.tla.toolbox.tool.tlc.job.TLCJobFactory;
 import org.lamport.tla.toolbox.tool.tlc.job.TLCProcessJob;
-import org.lamport.tla.toolbox.tool.tlc.model.Assignment;
-import org.lamport.tla.toolbox.tool.tlc.model.Formula;
 import org.lamport.tla.toolbox.tool.tlc.model.Model;
 import org.lamport.tla.toolbox.tool.tlc.model.ModelWriter;
 import org.lamport.tla.toolbox.tool.tlc.model.TLCSpec;
-import org.lamport.tla.toolbox.tool.tlc.model.TypedSet;
 import org.lamport.tla.toolbox.tool.tlc.output.IProcessOutputSink;
 import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper;
+import org.lamport.tla.toolbox.ui.handler.ShowHistoryHandler;
 import org.lamport.tla.toolbox.util.AdapterFactory;
 import org.lamport.tla.toolbox.util.ResourceHelper;
 import org.lamport.tla.toolbox.util.TLAMarkerInformationHolder;
+import org.lamport.tla.toolbox.util.UIHelper;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.ServiceReference;
 
+import pcal.Validator;
 import tla2sany.semantic.ModuleNode;
 import tla2sany.semantic.OpDeclNode;
 import tlc2.TLCGlobals;
+import tlc2.model.Assignment;
+import tlc2.model.Formula;
+import tlc2.model.TypedSet;
+import tlc2.output.SpecWriterUtilities;
 import tlc2.util.FP64;
 import util.ExecutionStatisticsCollector;
+import util.TLAConstants;
 
 /**
  * Represents a launch delegate for TLC<br>
@@ -98,12 +115,8 @@ import util.ExecutionStatisticsCollector;
  * Modified on 10 Sep 2009 to add No Spec TLC launch option.
  */
 @SuppressWarnings("restriction")
-public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implements IModelConfigurationConstants,
-        IModelConfigurationDefaults
-{
-    // Mutex rule for the following jobs to run after each other
-    protected MutexRule mutexRule = new MutexRule();
-
+public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate
+		implements IModelConfigurationConstants, IModelConfigurationDefaults {
     /**
      * Configuration type
      */
@@ -116,8 +129,25 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
      * Only generate the models but do not run TLC
      */
     public static final String MODE_GENERATE = "generate";
+    
+    private static final AtomicBoolean PERFORM_VALIDATION_BEFORE_LAUNCH = new AtomicBoolean(true);
+    
+    private static final Integer DIVERGENCE_CONTINUE_LAUNCH = Integer.valueOf(1);
+    private static final Integer DIVERGENCE_SHOW_HISTORY = Integer.valueOf(2);
+    private static final LinkedHashMap<String, Integer> DIVERGENCE_DIALOG_BUTTONS;
+    
+    static {
+    	DIVERGENCE_DIALOG_BUTTONS = new LinkedHashMap<>();
+    	DIVERGENCE_DIALOG_BUTTONS.put("&Abort Launch", Integer.valueOf(0));
+    	DIVERGENCE_DIALOG_BUTTONS.put("Continue &Launch", DIVERGENCE_CONTINUE_LAUNCH);
+    	DIVERGENCE_DIALOG_BUTTONS.put("Abort Launch && Show &History", DIVERGENCE_SHOW_HISTORY); // "&&" because "&" is mnemonic.
+    }
+
+
+    // Mutex rule for the following jobs to run after each other
+    protected MutexRule mutexRule = new MutexRule();
 
-	private Launch launch;
+    private Launch launch;
 
     /**
      * 1. method called during the launch
@@ -146,24 +176,122 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
      * @return whether the launch should proceed
      * @see org.eclipse.debug.core.model.ILaunchConfigurationDelegate2#preLaunchCheck(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.core.runtime.IProgressMonitor)
      */
-    public boolean preLaunchCheck(ILaunchConfiguration config, String mode, IProgressMonitor monitor)
-            throws CoreException
-    {
-
+	public boolean preLaunchCheck(final ILaunchConfiguration config, final String mode, final IProgressMonitor monitor)
+			throws CoreException {
         // check the config existence
-        if (!config.exists())
-        {
+		if (!config.exists()) {
             return false;
         }
-        
-        try
-        {
-            monitor.beginTask("Reading model parameters", 1);
-        } finally
-        {
-            // finish the monitor
-            monitor.done();
+
+        final int specType = config.getAttribute(MODEL_BEHAVIOR_SPEC_TYPE, MODEL_BEHAVIOR_TYPE_DEFAULT);
+        if ((specType != MODEL_BEHAVIOR_TYPE_NO_SPEC)
+        		&& PERFORM_VALIDATION_BEFORE_LAUNCH.get()
+        		&& mode.equals(MODE_MODELCHECK)) {
+            final Model model = config.getAdapter(Model.class);
+            final IFile rootModule = model.getSpec().toSpec().getRootFile();
+            final Validator.ValidationResult result;
+
+            try (final InputStream is = rootModule.getContents()) {
+            	result = Validator.validate(is);
+            } catch (final IOException e) {
+            	monitor.done();
+            	
+            	throw new CoreException(new Status(IStatus.ERROR, TLCActivator.PLUGIN_ID, e.getMessage()));
+            }
+            
+    		final Display d = PlatformUI.getWorkbench().getDisplay();
+    		final AtomicInteger returnCode = new AtomicInteger(-1);
+            switch (result) {
+            	case NO_PLUSCAL_EXISTS:
+            	case NO_DIVERGENCE:
+            		break;
+            	case ERROR_ENCOUNTERED:
+            		d.syncExec(() -> {
+            			final MessageDialogWithToggle dialog = MessageDialogWithToggle.openYesNoQuestion(
+    							d.getActiveShell(), "Error encountered",
+    							"Something went wrong attempting to detect divergence between PlusCal and its translation, continue anyway?",
+    							"Do not bug me about PlusCal verification during the rest of my Toolbox session.", false,
+    							null, null);
+    					
+    					if (dialog.getToggleState()) {
+    						PERFORM_VALIDATION_BEFORE_LAUNCH.set(false);
+    					}
+    					
+    					returnCode.set(dialog.getReturnCode());
+            		});
+					
+					if (returnCode.get() == IDialogConstants.NO_ID) {
+						return false;
+					}
+        			break;
+            	case NO_TRANSLATION_EXISTS:
+            		d.syncExec(() -> {
+            			final MessageDialogWithToggle dialog = MessageDialogWithToggle.openYesNoQuestion(
+    							d.getActiveShell(), "Translation missing",
+    							"Your spec appears to contain PlusCal but no TLA+ translation, are you sure you want to continue?",
+    							"Do not bug me about PlusCal verification during the rest of my Toolbox session.", false,
+    							null, null);
+    					
+    					if (dialog.getToggleState()) {
+    						PERFORM_VALIDATION_BEFORE_LAUNCH.set(false);
+    					}
+    					
+    					returnCode.set(dialog.getReturnCode());
+            		});
+					
+					if (returnCode.get() == IDialogConstants.NO_ID) {
+						return false;
+					}
+        			break;
+            	case NO_CHECKSUMS_EXIST:
+            		d.syncExec(() -> {
+            			final MessageDialogWithToggle dialog = MessageDialogWithToggle.openInformation(
+    							d.getActiveShell(), "A note about your spec",
+    							"Your spec contains PlusCal and a TLA+ translation - but they have not been verified to "
+    									+ "be in sync; consider re-translating the PlusCal algorithm.",
+    							"Do not bug me about PlusCal verification during the rest of my Toolbox session.", false,
+    							null, null);
+    					
+    					if (dialog.getToggleState()) {
+    						PERFORM_VALIDATION_BEFORE_LAUNCH.set(false);
+    					}
+            		});
+					
+            		break;
+            	case DIVERGENCE_EXISTS:
+            		d.syncExec(() -> {
+            			final MessageDialogWithToggle dialog = MessageDialogWithToggle.open(MessageDialogWithToggle.QUESTION,
+    							d.getActiveShell(), "PlusCal out of sync",
+    							"The PlusCal and TLA+ translation in your spec appear to be out of sync - would you like to"
+    									+ " stop the launch?",
+    							"Do not bug me about PlusCal verification during the rest of my Toolbox session.", false,
+    							null, null, SWT.NONE, DIVERGENCE_DIALOG_BUTTONS);
+    					
+    					if (dialog.getToggleState()) {
+    						PERFORM_VALIDATION_BEFORE_LAUNCH.set(false);
+    					}
+    					
+    					returnCode.set(dialog.getReturnCode());
+            		});
+					
+					if (returnCode.get() != DIVERGENCE_CONTINUE_LAUNCH.intValue()) {
+						if (returnCode.get() == DIVERGENCE_SHOW_HISTORY.intValue()) {
+							final Module m = new Module(model.getSpec().getRootFile());
+							ShowHistoryHandler.openHistoryForModule(m);
+						}
+						
+						return false;
+					}
+            		break;
+            }
         }
+        
+		try {
+			monitor.beginTask("Reading model parameters", 1);
+		} finally {
+			// finish the monitor
+			monitor.done();
+		}
 
         return true;
     }
@@ -193,22 +321,23 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
             // step 1
             monitor.subTask("Creating directories");
 
-            // retrieve the project containing the specification
-            final IProject project = model.getSpec().getProject();
+            final TLCSpec spec = model.getSpec();
+			// retrieve the project containing the specification
+            final IProject project = spec.getProject();
             if (project == null)
             {
                 // project could not be found
                 throw new CoreException(new Status(IStatus.ERROR, TLCActivator.PLUGIN_ID,
-                        "Error accessing the spec project " + model.getSpec().getName()));
+                        "Error accessing the spec project " + spec.getName()));
             }
 
             // retrieve the root file
-            final IFile specRootFile = model.getSpec().getRootFile();
+            final IFile specRootFile = spec.getRootFile();
             if (specRootFile == null)
             {
                 // root module file not found
                 throw new CoreException(new Status(IStatus.ERROR, TLCActivator.PLUGIN_ID,
-                        "Error accessing the root module " + model.getSpec().getRootFilename()));
+                        "Error accessing the root module " + spec.getRootFilename()));
             }
 
             // retrieve the model folder
@@ -216,9 +345,9 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
             IPath targetFolderPath = modelFolder.getProjectRelativePath().addTrailingSeparator();
 
             // create the handles: MC.tla, MC.cfg and MC.out
-            IFile tlaFile = project.getFile(targetFolderPath.append(ModelHelper.FILE_TLA));
-            IFile cfgFile = project.getFile(targetFolderPath.append(ModelHelper.FILE_CFG));
-            IFile outFile = project.getFile(targetFolderPath.append(ModelHelper.FILE_OUT));
+            IFile tlaFile = project.getFile(targetFolderPath.append(TLAConstants.Files.MODEL_CHECK_TLA_FILE));
+            IFile cfgFile = project.getFile(targetFolderPath.append(TLAConstants.Files.MODEL_CHECK_CONFIG_FILE));
+            IFile outFile = project.getFile(targetFolderPath.append(TLAConstants.Files.MODEL_CHECK_OUTPUT_FILE));
 
             final IFile[] files = new IFile[] { tlaFile, cfgFile, outFile };
 
@@ -261,7 +390,7 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
                             {
                                 if (!members[i].getName().equals(ModelHelper.TE_TRACE_SOURCE))
                                 {
-                                    members[i].delete(IResource.FORCE, new SubProgressMonitor(monitor, 1));
+                                    members[i].delete(IResource.FORCE, SubMonitor.convert(monitor).split(1));
                                 }
                             } catch (CoreException e)
                             {
@@ -278,7 +407,7 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
             } else
             {
                 // create it
-                modelFolder.create(IResource.DERIVED | IResource.FORCE, true, new SubProgressMonitor(monitor, STEP));
+                modelFolder.create(IResource.DERIVED | IResource.FORCE, true, SubMonitor.convert(monitor).split(STEP));
             }
 
             // step 2
@@ -286,7 +415,7 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
 
             // copy
             specRootFile.copy(targetFolderPath.append(specRootFile.getProjectRelativePath()), IResource.DERIVED
-                    | IResource.FORCE, new SubProgressMonitor(monitor, 1));
+                    | IResource.FORCE, SubMonitor.convert(monitor).split(1));
             // find the result
             IResource specRootFileCopy = modelFolder.findMember(specRootFile.getProjectRelativePath());
 
@@ -294,20 +423,20 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
             if (specRootFileCopy == null)
             {
                 throw new CoreException(new Status(IStatus.ERROR, TLCActivator.PLUGIN_ID, "Error copying "
-                        + model.getSpec().getRootFilename() + " into " + targetFolderPath.toOSString()));
+                        + spec.getRootFilename() + " into " + targetFolderPath.toOSString()));
             }
             
             // Copy the spec's root file userModule override if any.
             copyUserModuleOverride(monitor, 2, project, targetFolderPath, specRootFile);
             
             // get the list of dependent modules
-            List extendedModules = ToolboxHandle.getExtendedModules(specRootFile.getName());
+            List<String> extendedModules = ToolboxHandle.getExtendedModules(specRootFile.getName());
 
             // iterate and copy modules that are needed for the spec
             IFile moduleFile = null;
             for (int i = 0; i < extendedModules.size(); i++)
             {
-                String module = (String) extendedModules.get(i);
+                String module = extendedModules.get(i);
 				// Only take care of user modules and actually *linked* files
 				// (not files defined via TLA_LIBRARY_PATH)
                 if (ToolboxHandle.isUserModule(module) && ResourceHelper.isLinkedFile(project, module))
@@ -317,7 +446,7 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
                     {
 						try {
 	                        moduleFile.copy(targetFolderPath.append(moduleFile.getProjectRelativePath()), IResource.DERIVED
-	                                | IResource.FORCE, new SubProgressMonitor(monitor, STEP / extendedModules.size()));
+	                                | IResource.FORCE, SubMonitor.convert(monitor).split(STEP / extendedModules.size()));
 							copyUserModuleOverride(monitor, STEP / extendedModules.size(), project, targetFolderPath, moduleFile);
 						} catch (ResourceException re) {
                     		// Trying to copy the file to the targetFolderPath produces an exception.
@@ -346,16 +475,35 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
                     }
                     // TODO check the existence of copied files
                 }
-            }
+            }
+            
+			// CloudTLC deploys a custom packaged tla2tools.jar on the remote instance,
+			// which is self-contained. I.e. it contains all of the spec's dependencies such
+			// as modules from the library path and TLC module overrides. Here we make sure
+            // these dependencies get included in the custom tla2tools.jar (see PayloadHelper)
+            // by copying them to the model directory.
+            if (!local.contains(getMode(config))) {
+				final Path modelDirectoryPath = Paths.get(modelFolder.getRawLocation().makeAbsolute().toFile().toURI());
+            	for (Module m : spec.getModulesSANY()) {
+					if (m.isLibraryModule() && !m.isStandardModule()) {
+						try {
+							m.copyTo(modelDirectoryPath);
+						} catch (IOException e) {
+							throw new CoreException(new Status(Status.ERROR, "org.lamport.tlc.toolbox.tool.tlc",
+									String.format("Error copying file %s to %s.", m.getFile(), modelDirectoryPath), e));
+						}
+					}
+				}
+            }
 
             // create files
 			for (int i = 0; i < files.length; i++) {
 				if (files[i].exists()) {
 					files[i].setContents(new ByteArrayInputStream("".getBytes()), IResource.DERIVED | IResource.FORCE,
-							new SubProgressMonitor(monitor, 1));
+							SubMonitor.convert(monitor).split(1));
 				} else {
 					files[i].create(new ByteArrayInputStream("".getBytes()), IResource.DERIVED | IResource.FORCE,
-							new SubProgressMonitor(monitor, 1));
+							SubMonitor.convert(monitor).split(1));
 				}
 			}
 
@@ -365,15 +513,15 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
             ModelWriter writer = new ModelWriter();
        
             // add the MODULE beginning and EXTENDS statement
-            writer.addPrimer(ModelHelper.MC_MODEL_NAME, model.getSpec().getRootModuleName());
+            writer.addPrimer(TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, spec.getRootModuleName());
 
             // Sets constants to a Vector of the substitutions for the CONSTANT substitutions
             List<Assignment> constants = ModelHelper.deserializeAssignmentList(config.getAttribute(MODEL_PARAMETER_CONSTANTS,
-                    new Vector<String>()));
+                    new ArrayList<String>()));
 
             // Sets modelValues to a TypedSet object whose value is a String array containing
             // the names of the model values declared on the Advanced model page.
-            TypedSet modelValues = TypedSet.parseSet(config.getAttribute(MODEL_PARAMETER_MODEL_VALUES, EMPTY_STRING));
+            TypedSet modelValues = TypedSet.parseSet(config.getAttribute(MODEL_PARAMETER_MODEL_VALUES, TLAConstants.EMPTY_STRING));
 
             // Adds to MC.cfg the CONSTANT declarations for (in order) 
             //  - The model values declared on the advanced model page.
@@ -387,7 +535,7 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
             writer.addConstants(constants, modelValues, MODEL_PARAMETER_CONSTANTS, MODEL_PARAMETER_MODEL_VALUES);
             
             // The additional definitions from the Advanced model page.
-            writer.addNewDefinitions(config.getAttribute(MODEL_PARAMETER_NEW_DEFINITIONS, EMPTY_STRING),
+            writer.addNewDefinitions(config.getAttribute(MODEL_PARAMETER_NEW_DEFINITIONS, TLAConstants.EMPTY_STRING),
                     MODEL_PARAMETER_NEW_DEFINITIONS);
 
             // Adds to MC.cfg the CONSTANT declarations for CONSTANT parameters instantiated with ordinary values. 
@@ -396,12 +544,13 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
 
             // Sets overrides to the Vector of definition overrides.
             List<Assignment> overrides = ModelHelper.deserializeAssignmentList(config.getAttribute(MODEL_PARAMETER_DEFINITIONS,
-                    new Vector<String>()));
+                    new ArrayList<String>()));
             
             // For the definition overrides, it adds the definitions to the MC.tla file and the
             // overriding CONSTANT statements to the MC.cfg file.
-            writer.addFormulaList(ModelWriter.createOverridesContent(overrides, ModelWriter.DEFOV_SCHEME), "CONSTANT",
-                    MODEL_PARAMETER_DEFINITIONS);
+            writer.addFormulaList(SpecWriterUtilities.createOverridesContent(overrides, TLAConstants.Schemes.DEFOV_SCHEME,
+            		ToolboxHandle.getCurrentSpec().getValidRootModule()), TLAConstants.KeyWords.CONSTANT,
+            		MODEL_PARAMETER_DEFINITIONS);
 
             /* 
              * specType is used to write the desired spec or lack of spec to the MC files.
@@ -422,19 +571,21 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
             int specType = config.getAttribute(MODEL_BEHAVIOR_SPEC_TYPE, MODEL_BEHAVIOR_TYPE_DEFAULT);
             boolean hasSpec = specType != MODEL_BEHAVIOR_TYPE_NO_SPEC;
 
-            if (hasSpec)
-            {
+			if (hasSpec) {
                 // constraint
-                writer.addFormulaList(ModelWriter.createSourceContent(MODEL_PARAMETER_CONSTRAINT,
-                        ModelWriter.CONSTRAINT_SCHEME, config), "CONSTRAINT", MODEL_PARAMETER_CONSTRAINT);
+				String constraintValue = config.getAttribute(MODEL_PARAMETER_CONSTRAINT, TLAConstants.EMPTY_STRING);
+                writer.addFormulaList(SpecWriterUtilities.createSourceContent(constraintValue,
+                        TLAConstants.Schemes.CONSTRAINT_SCHEME), "CONSTRAINT", MODEL_PARAMETER_CONSTRAINT);
+                
                 // action constraint
-                writer.addFormulaList(ModelWriter.createSourceContent(MODEL_PARAMETER_ACTION_CONSTRAINT,
-                        ModelWriter.ACTIONCONSTRAINT_SCHEME, config), "ACTION_CONSTRAINT",
+                constraintValue = config.getAttribute(MODEL_PARAMETER_ACTION_CONSTRAINT, TLAConstants.EMPTY_STRING);
+                writer.addFormulaList(SpecWriterUtilities.createSourceContent(constraintValue,
+                		TLAConstants.Schemes.ACTIONCONSTRAINT_SCHEME), TLAConstants.KeyWords.ACTION_CONSTRAINT,
                         MODEL_PARAMETER_ACTION_CONSTRAINT);
                 // Changed from incorrect "ACTION-CONSTRAINT" on 11 Sep 2009
 
                 // view
-                writer.addView(config.getAttribute(LAUNCH_VIEW, EMPTY_STRING), MODEL_PARAMETER_VIEW);
+                writer.addView(config.getAttribute(LAUNCH_VIEW, TLAConstants.EMPTY_STRING), MODEL_PARAMETER_VIEW);
             }
 
             // calculator expression
@@ -450,38 +601,45 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
                     if (vars != null && vars.length > 0)
                     {
                         String var = rootModuleNode.getVariableDecls()[0].getName().toString();
-                        writer.addFormulaList(ModelWriter.createFalseInit(var), "INIT", MODEL_BEHAVIOR_NO_SPEC);
-                        writer.addFormulaList(ModelWriter.createFalseNext(var), "NEXT", MODEL_BEHAVIOR_NO_SPEC);
+                        writer.addFormulaList(SpecWriterUtilities.createFalseInit(var), TLAConstants.KeyWords.INIT,
+                        		MODEL_BEHAVIOR_NO_SPEC);
+                        writer.addFormulaList(SpecWriterUtilities.createFalseNext(var), TLAConstants.KeyWords.NEXT,
+                        		MODEL_BEHAVIOR_NO_SPEC);
                     }
                 }
                 break;
             case MODEL_BEHAVIOR_TYPE_SPEC_CLOSED:
 
                 // the specification name-formula pair
-            	final String spec = config.getAttribute(MODEL_BEHAVIOR_CLOSED_SPECIFICATION, EMPTY_STRING);
-    			if (model.getSpec().declares(spec) && !isExpression(spec)) {
-            		writer.addFormulaList(spec, "SPECIFICATION", MODEL_BEHAVIOR_CLOSED_SPECIFICATION);
+            	final String specIdentifier = config.getAttribute(MODEL_BEHAVIOR_CLOSED_SPECIFICATION, TLAConstants.EMPTY_STRING);
+    			if (spec.declares(specIdentifier) && !isExpression(specIdentifier)) {
+            		writer.addFormulaList(specIdentifier, TLAConstants.KeyWords.SPECIFICATION, MODEL_BEHAVIOR_CLOSED_SPECIFICATION);
     			} else {
-    				writer.addFormulaList(ModelWriter.createSourceContent(MODEL_BEHAVIOR_CLOSED_SPECIFICATION,
-    						ModelWriter.SPEC_SCHEME, config), "SPECIFICATION", MODEL_BEHAVIOR_CLOSED_SPECIFICATION);
+    				final String value = config.getAttribute(MODEL_BEHAVIOR_CLOSED_SPECIFICATION, TLAConstants.EMPTY_STRING);
+    				writer.addFormulaList(SpecWriterUtilities.createSourceContent(value,
+    						TLAConstants.Schemes.SPEC_SCHEME), TLAConstants.KeyWords.SPECIFICATION, MODEL_BEHAVIOR_CLOSED_SPECIFICATION);
     			}
                 break;
             case MODEL_BEHAVIOR_TYPE_SPEC_INIT_NEXT:
             	// the init and next formulas
-            	final String init = config.getAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT, EMPTY_STRING);
-				if (model.getSpec().declares(init) && !isExpression(init)) {
-            		writer.addFormulaList(init, "INIT", MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT);
+            	final String init = config.getAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT, TLAConstants.EMPTY_STRING);
+				if (spec.declares(init) && !isExpression(init)) {
+            		writer.addFormulaList(init, TLAConstants.KeyWords.INIT, MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT);
             	} else {
-            		writer.addFormulaList(ModelWriter.createSourceContent(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT,
-            				ModelWriter.INIT_SCHEME, config), "INIT", MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT);
+    				final String value = config.getAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT, TLAConstants.EMPTY_STRING);
+            		writer.addFormulaList(SpecWriterUtilities.createSourceContent(value,
+            				TLAConstants.Schemes.INIT_SCHEME), TLAConstants.KeyWords.INIT,
+            				MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT);
             	}
 				
-            	final String next = config.getAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT, EMPTY_STRING);
-				if (model.getSpec().declares(next) && !isExpression(next)) {
-	           		writer.addFormulaList(next, "NEXT", MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT);
+            	final String next = config.getAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT, TLAConstants.EMPTY_STRING);
+				if (spec.declares(next) && !isExpression(next)) {
+	           		writer.addFormulaList(next, TLAConstants.KeyWords.NEXT, MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_INIT);
             	} else {
-	                writer.addFormulaList(ModelWriter.createSourceContent(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT,
-	                        ModelWriter.NEXT_SCHEME, config), "NEXT", MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT);
+    				final String value = config.getAttribute(MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT, TLAConstants.EMPTY_STRING);
+	                writer.addFormulaList(SpecWriterUtilities.createSourceContent(value,
+	                		TLAConstants.Schemes.NEXT_SCHEME), TLAConstants.KeyWords.NEXT,
+	                		MODEL_BEHAVIOR_SEPARATE_SPECIFICATION_NEXT);
             	}
                 break;
             }
@@ -494,15 +652,15 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
             if (hasSpec)
             {
             	// invariants (separate those declared in the spec from those declared in the model).
-				final List<String> invariants = config.getAttribute(MODEL_CORRECTNESS_INVARIANTS, new Vector<String>());
+				final List<String> invariants = config.getAttribute(MODEL_CORRECTNESS_INVARIANTS, new ArrayList<String>());
 				writer.addFormulaList(
-						createProperties(writer, model.getSpec(), invariants, ModelWriter.INVARIANT_SCHEME),
-						"INVARIANT", MODEL_CORRECTNESS_INVARIANTS);
+						createProperties(writer, spec, invariants, TLAConstants.Schemes.INVARIANT_SCHEME),
+						TLAConstants.KeyWords.INVARIANT, MODEL_CORRECTNESS_INVARIANTS);
 
 				// properties
-				final List<String> properties = config.getAttribute(MODEL_CORRECTNESS_PROPERTIES, new Vector<String>());
-				writer.addFormulaList(createProperties(writer, model.getSpec(), properties, ModelWriter.PROP_SCHEME),
-						"PROPERTY", MODEL_CORRECTNESS_PROPERTIES);
+				final List<String> properties = config.getAttribute(MODEL_CORRECTNESS_PROPERTIES, new ArrayList<String>());
+				writer.addFormulaList(createProperties(writer, spec, properties, TLAConstants.Schemes.PROP_SCHEME),
+						TLAConstants.KeyWords.PROPERTY, MODEL_CORRECTNESS_PROPERTIES);
             }
 
             monitor.worked(STEP);
@@ -512,7 +670,7 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
             writer.writeFiles(tlaFile, cfgFile, monitor);
 
             // refresh the model folder
-            modelFolder.refreshLocal(IResource.DEPTH_ONE, new SubProgressMonitor(monitor, STEP));
+            modelFolder.refreshLocal(IResource.DEPTH_ONE, SubMonitor.convert(monitor).split(STEP));
 
         } finally
         {
@@ -539,10 +697,10 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
 		
 		// Convert list of strings such as {"1Inv", "0x \in Nat"} into a subset of
 		// checked formulas (prefixed with 1).
-		final List<Formula> checkedFormula = ModelHelper.deserializeFormulaList(properties);
+		final List<Formula> checkedFormula = Formula.deserializeFormulaList(properties);
 
 		// Create the input for the model writer out of all formula...
-		final List<String[]> createFormulaListContent = ModelWriter.createFormulaListContentFormula(checkedFormula,
+		final List<String[]> createFormulaListContent = SpecWriterUtilities.createFormulaListContentFormula(checkedFormula,
 				scheme);
 
 		// Collect those formula that are declared in the spec, not the MC.tla file.
@@ -552,7 +710,7 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
 		// Override each declared formula with its original declaration. This will cause
 		// ModelWriter.addFormulaList to omit it from the MC.tla file and only add it to MC.cfg.
 		declaredFormula.forEach(f -> createFormulaListContent.set(checkedFormula.indexOf(f),
-				new String[] { f.getFormula(), EMPTY_STRING, String.valueOf(checkedFormula.indexOf(f)) }));
+				new String[] { f.getFormula(), TLAConstants.EMPTY_STRING, String.valueOf(checkedFormula.indexOf(f)) }));
 
 		// createFormulaListContent has to be in the same order as checkedFormula.
 		// Otherwise, TLCModelLaunchDataProvider.createError(TLCRegion,
@@ -575,7 +733,7 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
 		for (IFile userModuleOverride : userModuleOverrides) {
 			try {
 				userModuleOverride.copy(targetFolderPath.append(userModuleOverride.getProjectRelativePath()),
-						IResource.DERIVED | IResource.FORCE, new SubProgressMonitor(monitor, ticks));
+						IResource.DERIVED | IResource.FORCE, SubMonitor.convert(monitor).split(ticks));
 			} catch (CoreException e) {
 				// If the file could not be copied, the link is obviously stale
 				// and has to be removed to not create any problems in the
@@ -603,7 +761,7 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
 
         monitor.worked(1);
         // parse the MC file
-        IParseResult parseResult = ToolboxHandle.parseModule(rootModule, new SubProgressMonitor(monitor, 1), false,
+        IParseResult parseResult = ToolboxHandle.parseModule(rootModule, SubMonitor.convert(monitor).split(1), false,
                 false);
         final Vector<TLAMarkerInformationHolder> detectedErrors = parseResult.getDetectedErrors();
         boolean status = !AdapterFactory.isProblemStatus(parseResult.getStatus());
@@ -742,22 +900,7 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
         // number of workers
         int numberOfWorkers = config.getAttribute(LAUNCH_NUMBER_OF_WORKERS, LAUNCH_NUMBER_OF_WORKERS_DEFAULT);
 
-        // distributed launch (legacy launch configurations pre-dating TLC distributed functionality 
-        // do not have the LAUNCH_DISTRIBUTED attribute. Then, it obviously defaults to distribution turned off.
-        // Trying to lookup a non-existing attribute would cause a runtime exception.)
-        // Then it could also be true or false. The legacy flag showing if "ad hoc" distribution is turned
-        // on or not. Simply map it to "ad hoc" or "off".
-        String cloud = "off";
-        if (config.hasAttribute(LAUNCH_DISTRIBUTED)) {
-        	try {
-        		cloud = config.getAttribute(LAUNCH_DISTRIBUTED, LAUNCH_DISTRIBUTED_DEFAULT);
-        	} catch (CoreException e) {
-        		boolean distributed = config.getAttribute(LAUNCH_DISTRIBUTED, false);
-        		if (distributed) {
-        			cloud = "ad hoc";
-        		}
-        	}
-        }
+        final String cloud = getMode(config);
         
         // TLC job
         Job job = null;
@@ -808,6 +951,16 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
 					// The parameters below are the only one currently useful with CloudDistributedTLC
 					final StringBuffer tlcParams = new StringBuffer();
 					
+					if (!launch.getLaunchConfiguration().getAttribute(LAUNCH_MC_MODE, LAUNCH_MC_MODE_DEFAULT)) {
+						tlcParams.append("-simulate");
+			        	tlcParams.append(" ");
+						tlcParams.append("-depth");
+			        	tlcParams.append(" ");
+						final int depth = launch.getLaunchConfiguration().getAttribute(LAUNCH_SIMU_DEPTH, LAUNCH_SIMU_DEPTH_DEFAULT);
+						tlcParams.append(Integer.toString(depth));
+			        	tlcParams.append(" ");
+					}
+					
 			        // fp seed offset (decrease by one to map from [1, 64] interval to [0, 63] array address)
 					if (launch.getLaunchConfiguration().getAttribute(LAUNCH_FP_INDEX_RANDOM, LAUNCH_FP_INDEX_RANDOM_DEFAULT)) {
 						final int fpIndex = new Random().nextInt(FP64.Polys.length);
@@ -881,6 +1034,27 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
         job.addJobChangeListener(tlcJobListener);
         job.schedule();
     }
+
+    private static final Set<String> local = new HashSet<>(Arrays.asList("ad hoc", "off"));
+    
+	private static String getMode(final ILaunchConfiguration config) throws CoreException {
+        // distributed launch (legacy launch configurations pre-dating TLC distributed functionality 
+        // do not have the LAUNCH_DISTRIBUTED attribute. Then, it obviously defaults to distribution turned off.
+        // Trying to lookup a non-existing attribute would cause a runtime exception.)
+        // Then it could also be true or false. The legacy flag showing if "ad hoc" distribution is turned
+        // on or not. Simply map it to "ad hoc" or "off".
+		if (config.hasAttribute(LAUNCH_DISTRIBUTED)) {
+        	try {
+        		return  config.getAttribute(LAUNCH_DISTRIBUTED, LAUNCH_DISTRIBUTED_DEFAULT);
+        	} catch (CoreException e) {
+        		boolean distributed = config.getAttribute(LAUNCH_DISTRIBUTED, false);
+        		if (distributed) {
+        			return "ad hoc";
+        		}
+        	}
+        }
+		return "off";
+	}
     
 	// A DummyProcess instance has to be attached to the corresponding ILaunch
 	// when the Job launched neither creates an IProcess nor IDebugTarget. In
@@ -940,7 +1114,7 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
 	}
 
 	// This opens up a dialog at the end of the job showing the status message
-    class WithStatusJobChangeListener extends SimpleJobChangeListener {
+    class WithStatusJobChangeListener extends JobChangeAdapter {
 
 		private final Model model;
 		private final DummyProcess process;
@@ -998,7 +1172,7 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
     /**
      * listens to the termination of the TLC run 
      */
-    class TLCJobChangeListener extends SimpleJobChangeListener
+    class TLCJobChangeListener extends JobChangeAdapter
     {
         private Model model;
 
@@ -1156,6 +1330,22 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
 							}
 						};
 						j.schedule();
+						
+						// Open the ModelEditor on the snapshot. The output/result of the remote
+						// CloudTLC run is *not* reported into Model_1 but into its most recent
+						// snapshots. Without opening the ModelEditor on the snapshot, it appears
+						// as if nothing is happening (unless the TLCConsole happens to be open).
+						final IFile launchFile = snapshot.getLaunchConfiguration().getFile();
+						if (launchFile.exists()) {
+							PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+								@Override
+								public void run() {
+									//TODO Refactor constant into a class accessible by this bundle.
+									UIHelper.openEditor("org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor",
+											launchFile);
+								}
+							});
+						}
 					}
 					monitor.done();
 					return Status.OK_STATUS;
@@ -1183,37 +1373,6 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen
         }
     }
 
-    /**
-     * A listener writing the job state to the System.out
-     */
-    class SimpleJobChangeListener extends JobChangeAdapter
-    {
-
-        public void done(IJobChangeEvent event)
-        {
-            String jobName = event.getJob().getName();
-            String status = null;
-            if (event.getResult().isOK())
-            {
-                status = "Done";
-            } else
-            {
-                // analyze the cause
-                switch (event.getResult().getSeverity()) {
-                case IStatus.CANCEL:
-                    status = "Cancelled";
-                    break;
-                case IStatus.ERROR:
-                    status = "Error";
-                    break;
-                default:
-                    status = "Unknown";
-                    break;
-                }
-            }
-        }
-    };
-
     /**
      * A simple mutex rule 
      */
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TraceExplorerDelegate.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TraceExplorerDelegate.java
index be9717994ce3094c0ea75ebec2877d0665618537..76bf6b1b7cd26cceb507e97b852c8e84ea35718e 100644
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TraceExplorerDelegate.java
+++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TraceExplorerDelegate.java
@@ -25,11 +25,13 @@
  ******************************************************************************/
 package org.lamport.tla.toolbox.tool.tlc.launch;
 
+import java.util.ArrayList;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Vector;
+import java.util.stream.Collectors;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
@@ -45,7 +47,7 @@ import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
 import org.eclipse.core.runtime.jobs.ISchedulingRule;
 import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.debug.core.ILaunch;
@@ -60,19 +62,23 @@ import org.lamport.tla.toolbox.tool.tlc.TLCActivator;
 import org.lamport.tla.toolbox.tool.tlc.job.TLCJob;
 import org.lamport.tla.toolbox.tool.tlc.job.TLCProcessJob;
 import org.lamport.tla.toolbox.tool.tlc.job.TraceExplorerJob;
-import org.lamport.tla.toolbox.tool.tlc.model.Assignment;
 import org.lamport.tla.toolbox.tool.tlc.model.Model;
-import org.lamport.tla.toolbox.tool.tlc.model.ModelWriter;
 import org.lamport.tla.toolbox.tool.tlc.model.TLCSpec;
 import org.lamport.tla.toolbox.tool.tlc.model.TraceExpressionModelWriter;
-import org.lamport.tla.toolbox.tool.tlc.model.TypedSet;
-import org.lamport.tla.toolbox.tool.tlc.traceexplorer.SimpleTLCState;
 import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper;
 import org.lamport.tla.toolbox.util.ResourceHelper;
 import org.lamport.tla.toolbox.util.TLAMarkerInformationHolder;
 import org.lamport.tla.toolbox.util.UIHelper;
 
 import tla2sany.semantic.OpDefNode;
+import tlc2.model.Assignment;
+import tlc2.model.Formula;
+import tlc2.model.MCState;
+import tlc2.model.TraceExpressionInformationHolder;
+import tlc2.model.TypedSet;
+import tlc2.output.AbstractSpecWriter;
+import tlc2.output.SpecWriterUtilities;
+import util.TLAConstants;
 
 /**
  * Methods in this class are executed when the user clicks the explore
@@ -114,9 +120,10 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa
     private IFile tlaFile;
     private IFile cfgFile;
     private IFile outFile;
-    private List<SimpleTLCState> trace;
+    private List<MCState> trace;
     private String initId;
     private String nextId;
+    private String actionConstraintId;
 
     /**
      * Writes data to TE.tla so that SANY can be run on that module in the next
@@ -325,9 +332,9 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa
                         try
                         {
                             if ((checkpoints.length > 0 && checkpoints[0].equals(members[i]))
-                                    || members[i].getName().equals(ModelHelper.FILE_CFG)
-                                    || members[i].getName().equals(ModelHelper.FILE_TLA)
-                                    || members[i].getName().equals(ModelHelper.FILE_OUT)
+                                    || members[i].getName().equals(TLAConstants.Files.MODEL_CHECK_CONFIG_FILE)
+                                    || members[i].getName().equals(TLAConstants.Files.MODEL_CHECK_TLA_FILE)
+                                    || members[i].getName().equals(TLAConstants.Files.MODEL_CHECK_OUTPUT_FILE)
                                     || members[i].getName().equals(ModelHelper.TE_TRACE_SOURCE)
 									// Iff the model has been run with a module
 									// override, then there is a .class (and
@@ -343,7 +350,7 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa
                                 // or any of the MC files or the MC_TE.out file.
                                 continue;
                             }
-                            members[i].delete(IResource.FORCE, new SubProgressMonitor(monitor, 1));
+                            members[i].delete(IResource.FORCE, SubMonitor.convert(monitor).split(1));
                         } catch (CoreException e)
                         {
                             // catch the exception if
@@ -356,7 +363,7 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa
                     }
                     monitor.done();
                 }
-            }, deleteRule, IWorkspace.AVOID_UPDATE, new SubProgressMonitor(monitor, STEP));
+            }, deleteRule, IWorkspace.AVOID_UPDATE, SubMonitor.convert(monitor).split(STEP));
         }
         /******************************************************************
          * Finished deleting files.                                       *
@@ -378,7 +385,7 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa
 
         // copy
         specRootFile.copy(targetFolderPath.append(specRootFile.getProjectRelativePath()), IResource.DERIVED
-                | IResource.FORCE, new SubProgressMonitor(monitor, 1));
+                | IResource.FORCE, SubMonitor.convert(monitor).split(1));
         // find the result
         IResource specRootFileCopy = modelFolder.findMember(specRootFile.getProjectRelativePath());
 
@@ -390,6 +397,17 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa
         }
 
         ModelHelper.copyExtendedModuleFiles(specRootFile, targetFolderPath, monitor, STEP, project);
+        
+        // Copy extra extends defined in the Trace Explorer UI.
+		ModelHelper.copyModuleFiles(specRootFile, targetFolderPath, monitor, STEP, project,
+				// Append ".tla" extensions without which copyModuleFiles silently skips the
+				// file.
+				model.getTraceExplorerExtends().stream().map(m -> m + TLAConstants.Files.TLA_EXTENSION).collect(Collectors.toSet()),
+				// Unconditionally copy all extra modules to where TLC (trace exploration) will
+				// be able to resolve them with the SimpleFilenameToStream resolver. These are
+				// modules which are at the root of the spec directory but not extended by the
+				// root module.
+				e -> true);
 
         /******************************************************************
          * Finished copying files.                                        *
@@ -417,7 +435,8 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa
         final TraceExpressionModelWriter writer = new TraceExpressionModelWriter();
 
         // add extend primer
-        writer.addPrimer(ModelHelper.TE_MODEL_NAME, ResourceHelper.getModuleName(model.getSpec().getRootFilename()));
+		writer.addPrimer(ModelHelper.TE_MODEL_NAME, ResourceHelper.getModuleName(model.getSpec().getRootFilename()),
+				model.getTraceExplorerExtends());
 
         writeModelInfo(config, writer);
         
@@ -440,19 +459,19 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa
          * of each expression. This is done in finalLaunchCheck() using the ParseResult
          * object returned by SANY.
          */
-        traceExpressionData = writer.createAndAddVariablesAndDefinitions(ModelHelper.deserializeFormulaList(config
-                .getAttribute(IModelConfigurationConstants.TRACE_EXPLORE_EXPRESSIONS, new Vector<String>())),
-                TRACE_EXPLORE_EXPRESSIONS);
+        traceExpressionData = writer.createAndAddVariablesAndDefinitions(Formula.deserializeFormulaList(config
+                .getAttribute(TLAConstants.TraceExplore.TRACE_EXPLORE_EXPRESSIONS, new ArrayList<String>())),
+        		TLAConstants.TraceExplore.TRACE_EXPLORE_EXPRESSIONS);
 
         // add the initial state predicate and next state action without
         // the trace exploration expressions in order to determine if they parse
         // initNext[0] is the identifier for init, initNext[1] is the identifier for next
-        String[] initNext = writer.addInitNext(trace, null);
-        if (initNext != null)
-        {
-            initId = initNext[0];
-            nextId = initNext[1];
-        }
+        final String[] initNextActionConstraint = writer.addInitNext(trace, null);
+		if (initNextActionConstraint != null) {
+			initId = initNextActionConstraint[0];
+			nextId = initNextActionConstraint[1];
+			actionConstraintId = initNextActionConstraint[2];
+		}
 
         monitor.worked(STEP);
         monitor.subTask("Writing contents");
@@ -479,7 +498,7 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa
 
         monitor.worked(1);
         // parse the TE.tla file
-        IParseResult parseResult = ToolboxHandle.parseModule(rootModule, new SubProgressMonitor(monitor, 1), false,
+        IParseResult parseResult = ToolboxHandle.parseModule(rootModule, SubMonitor.convert(monitor).split(1), false,
                 false);
         Assert
                 .isTrue(parseResult instanceof ParseResult,
@@ -551,7 +570,7 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa
          * We use the following object to collect level three expressions in order to display
          * these in a message to the user.
          */
-        Vector<TraceExpressionInformationHolder> levelThreeExpressions = new Vector<TraceExpressionInformationHolder>();
+        final ArrayList<TraceExpressionInformationHolder> levelThreeExpressions = new ArrayList<TraceExpressionInformationHolder>();
         for (int i = 0; i < traceExpressionData.length; i++)
         {
             OpDefNode opDefNode = (OpDefNode) nodeTable.get(traceExpressionData[i].getIdentifier());
@@ -623,7 +642,8 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa
         writer.addInfoComments(traceExpressionData);
 
         // add extend primer
-        writer.addPrimer(ModelHelper.TE_MODEL_NAME, ResourceHelper.getModuleName(model.getSpec().getRootFilename()));
+		writer.addPrimer(ModelHelper.TE_MODEL_NAME, ResourceHelper.getModuleName(model.getSpec().getRootFilename()),
+				model.getTraceExplorerExtends());
 
         // write constants, model values, new definitions, definition overrides
         writeModelInfo(configuration, writer);
@@ -631,12 +651,12 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa
         writer.addTraceFunction(trace);
 
         // variables declarations for trace explorer expressions
-        writer.addVariablesAndDefinitions(traceExpressionData, TRACE_EXPLORE_EXPRESSIONS, false);
+        writer.addVariablesAndDefinitions(traceExpressionData, TLAConstants.TraceExplore.TRACE_EXPLORE_EXPRESSIONS, false);
 
         // add init and next
-        writer.addInitNext(trace, traceExpressionData, initId, nextId);
+        writer.addInitNext(trace, traceExpressionData, initId, nextId, actionConstraintId);
 
-        SimpleTLCState finalState = (SimpleTLCState) trace.get(trace.size() - 1);
+        MCState finalState = trace.get(trace.size() - 1);
         boolean isBackToState = finalState.isBackToState();
         boolean isStuttering = finalState.isStuttering();
 
@@ -644,11 +664,10 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa
         // read the method comments to see the form of the invariant or property
         if (isStuttering)
         {
-            writer.addStutteringProperty((SimpleTLCState) trace.get(trace.size() - 2));
+            writer.addStutteringProperty(trace.get(trace.size() - 2));
         } else if (isBackToState)
         {
-            writer.addBackToStateProperty((SimpleTLCState) trace.get(trace.size() - 2),
-                    (SimpleTLCState) trace.get(finalState.getStateNumber() - 1));
+            writer.addBackToStateProperty(trace.get(trace.size() - 2), trace.get(finalState.getStateNumber() - 1));
         } else
         {
             // checking deadlock eliminates the need for the following
@@ -660,7 +679,7 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa
         // retrieve the model folder
         IFolder modelFolder = model.getFolder();
         // refresh the model folder
-        modelFolder.refreshLocal(IResource.DEPTH_ONE, new SubProgressMonitor(monitor, 100));
+        modelFolder.refreshLocal(IResource.DEPTH_ONE, SubMonitor.convert(monitor).split(100));
 
         // set the model to have the trace with trace explorer expression shown
         configuration.getAdapter(Model.class).setOriginalTraceShown(false);
@@ -710,11 +729,11 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa
      * @param writer
      * @throws CoreException
      */
-    private void writeModelInfo(ILaunchConfiguration config, ModelWriter writer) throws CoreException
+    private void writeModelInfo(final ILaunchConfiguration config, final AbstractSpecWriter writer) throws CoreException
     {
         // constants list
     	final List<Assignment> constants = ModelHelper.deserializeAssignmentList(config.getAttribute(MODEL_PARAMETER_CONSTANTS,
-                new Vector<String>()), true);
+                new ArrayList<String>()), true);
 
         // the advanced model values
         TypedSet modelValues = TypedSet.parseSet(config.getAttribute(MODEL_PARAMETER_MODEL_VALUES, EMPTY_STRING));
@@ -730,8 +749,9 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa
         writer.addConstantsBis(constants, MODEL_PARAMETER_CONSTANTS);
         // definition overrides list
         List<Assignment> overrides = ModelHelper.deserializeAssignmentList(config.getAttribute(MODEL_PARAMETER_DEFINITIONS,
-                new Vector<String>()));
-        writer.addFormulaList(ModelWriter.createOverridesContent(overrides, ModelWriter.DEFOV_SCHEME), "CONSTANT",
-                MODEL_PARAMETER_DEFINITIONS);
+                new ArrayList<String>()));
+        writer.addFormulaList(SpecWriterUtilities.createOverridesContent(overrides, TLAConstants.Schemes.DEFOV_SCHEME,
+        		ToolboxHandle.getCurrentSpec().getValidRootModule()), TLAConstants.KeyWords.CONSTANT,
+        		MODEL_PARAMETER_DEFINITIONS);
     }
 }
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/AbstractModelStateChangeListener.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/AbstractModelStateChangeListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..2eeb409f587e373dde022a6aea85a0895f7d58e0
--- /dev/null
+++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/AbstractModelStateChangeListener.java
@@ -0,0 +1,48 @@
+package org.lamport.tla.toolbox.tool.tlc.model;
+
+/**
+ * An instance of this is notified when the running state of the model changes. There is no guarantee as to which thread
+ * is being used to send the notification.
+ * 
+ * @see Model#add(AbstractModelStateChangeListener)
+ * @see Model#remove(AbstractModelStateChangeListener)
+ */
+public abstract class AbstractModelStateChangeListener {
+	public enum State {
+		RUNNING, NOT_RUNNING, DELETED, REMOTE_RUNNING, REMOTE_NOT_RUNNING;
+		
+		public boolean in(final State ... states) {
+			for (final State state : states) {
+				if (state == this) {
+					return true;
+				}
+			}
+			return false;
+		}
+	}
+
+	
+	public static class ChangeEvent {
+		private final State state;
+		private final Model model;
+
+		public ChangeEvent(final Model model, final State state) {
+			this.model = model;
+			this.state = state;
+		}
+
+		public State getState() {
+			return state;
+		}
+
+		public Model getModel() {
+			return model;
+		}
+	}
+
+	
+	/**
+	 * @return true iff the listener should be unsubscribed from receiving future events after it handled the event.
+	 */
+	public abstract boolean handleChange(final ChangeEvent event);
+}
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Formula.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Formula.java
deleted file mode 100644
index 8fb02ecb2a841f86d280e0655ee3dcc4897a071b..0000000000000000000000000000000000000000
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Formula.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package org.lamport.tla.toolbox.tool.tlc.model;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Representation of a formula.
- * @author Simon Zambrovski
- * @version $Id$
- */
-public class Formula
-{
-    private String formula;
-
-    /**
-     * Constructs a formula representation
-     * @param formula
-     */
-    public Formula(String formula)
-    {
-        this.formula = formula;
-    }
-    
-    /**
-     * Retrives formula
-     * @return
-     */
-    public String getFormula()
-    {
-        return formula;
-    }
-    
-    public String toString()
-    {
-        return formula;
-    }
-
-    /**
-     * @param formula2
-     */
-    public void setFormula(String formula)
-    {
-        this.formula = formula;
-    }
-
-	// MAK 03/2019: This methods below appear redundant to the Assignment subclass
-	// but I don't have time to look into it.
-    
-    public boolean isNamed()  {
-    	return !getLeftHandSide().equals(getFormula());
-    }
-    
-    // DOTALL to match beyond line endings.
-    private static final Pattern pattern = Pattern.compile("^\\s*(\\w+)\\s*==(.*)$", Pattern.DOTALL);
-    
-    public String getLeftHandSide() {
-		final Matcher matcher = pattern.matcher(this.formula);
-		if (matcher.find()) {
-			return matcher.group(1).trim();
-		}
-		return getFormula();
-    }
-    
-    public String getRightHandSide() {
-		final Matcher matcher = pattern.matcher(this.formula);
-		if (matcher.find()) {
-			return matcher.group(2).trim();
-		}
-		return getFormula();
-    }
-}
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Model.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Model.java
index 53b9447d5637f023e6979da8fedab3cee2347a9e..8278d3ef3c058c16d3e720288fd88c780a87dfcb 100644
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Model.java
+++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Model.java
@@ -29,12 +29,15 @@ package org.lamport.tla.toolbox.tool.tlc.model;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.URI;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -42,10 +45,12 @@ import java.util.Vector;
 import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.filefilter.DirectoryFileFilter;
 import org.apache.commons.io.filefilter.NotFileFilter;
+import org.eclipse.core.filesystem.IFileStore;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IMarker;
@@ -72,10 +77,12 @@ import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.ILaunchConfigurationType;
 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
 import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.internal.core.LaunchConfiguration;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.FindReplaceDocumentAdapter;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.IRegion;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.ui.editors.text.FileDocumentProvider;
 import org.eclipse.ui.part.FileEditorInput;
 import org.lamport.tla.toolbox.spec.Spec;
@@ -85,17 +92,18 @@ import org.lamport.tla.toolbox.tool.tlc.launch.IConfigurationConstants;
 import org.lamport.tla.toolbox.tool.tlc.launch.IConfigurationDefaults;
 import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants;
 import org.lamport.tla.toolbox.tool.tlc.launch.TLCModelLaunchDelegate;
-import org.lamport.tla.toolbox.tool.tlc.model.Model.StateChangeListener.ChangeEvent;
-import org.lamport.tla.toolbox.tool.tlc.model.Model.StateChangeListener.ChangeEvent.State;
-import org.lamport.tla.toolbox.tool.tlc.traceexplorer.SimpleTLCState;
 import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper;
 import org.lamport.tla.toolbox.util.ResourceHelper;
 
+import tlc2.model.Formula;
+import tlc2.model.MCState;
 import tlc2.output.MP;
+import util.TLAConstants;
 
 /**
  * This class represents a Toolbox Model that can be executed by TLC.
  */
+@SuppressWarnings("restriction")		// org.eclipse.debug.internal.core.LaunchConfiguration discouraged
 public class Model implements IModelConfigurationConstants, IAdaptable {
 	/**
      * Marker indicating an error in the model
@@ -119,6 +127,8 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
      */
     private static final String TRACE_EXPLORER_MARKER = "org.lamport.tla.toolbox.tlc.traceExplorerMarker";
 
+    private static final Collection<Model> EMPTY_MODEL_SET = Collections.unmodifiableList(new ArrayList<>());
+    
     public static final String SPEC_MODEL_DELIM = "___";
 
 	static String sanitizeName(String aModelName) {
@@ -145,57 +155,8 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
 	public static String fullyQualifiedNameFromSpecNameAndModelName(final String specName, final String modelName) {
 		return specName + SPEC_MODEL_DELIM + modelName;
 	}
-	       
-	/**
-	 * A {@link StateChangeListener} is notified when the running state of the model
-	 * changes. There is no guarantee as to which thread is being used to send the
-	 * notification. A {@link StateChangeListener} has subscribe and unsubscribe
-	 * via {@link Model#add(StateChangeListener)} and {@link Model#remove(StateChangeListener)}.
-	 */
-	public static class StateChangeListener {
 
-		public static class ChangeEvent {
-
-			public enum State {
-				RUNNING, NOT_RUNNING, DELETED, REMOTE_RUNNING, REMOTE_NOT_RUNNING;
-				
-				public boolean in(State ... states) {
-					for (State state : states) {
-						if (state == this) {
-							return true;
-						}
-					}
-					return false;
-				}
-			}
-
-			private final State state;
-			private final Model model;
-
-			private ChangeEvent(Model model, State state) {
-				this.model = model;
-				this.state = state;
-			}
-
-			public State getState() {
-				return state;
-			}
-
-			public Model getModel() {
-				return model;
-			}
-		}
-
-		/**
-		 * @return true iff the listener should be unsubscribed from receiving future
-		 *         events after it handled the event.
-		 */
-		public boolean handleChange(ChangeEvent event) {
-			return false;
-		}
-	}
-
-	private final Set<StateChangeListener> listeners = new CopyOnWriteArraySet<StateChangeListener>();
+	private final Set<AbstractModelStateChangeListener> listeners = new CopyOnWriteArraySet<AbstractModelStateChangeListener>();
 	private TLCSpec spec;
 	private ILaunchConfiguration launchConfig;
 
@@ -229,16 +190,16 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
 		this.launchConfig = launchConfig;
 	}
 	
-	public boolean add(StateChangeListener stateChangeListener) {
-		return this.listeners.add(stateChangeListener);
+	public boolean add(final AbstractModelStateChangeListener stateChangeListener) {
+		return listeners.add(stateChangeListener);
 	}
 
-	public boolean remove(StateChangeListener stateChangeListener) {
-		return this.listeners.remove(stateChangeListener);
+	public boolean remove(final AbstractModelStateChangeListener stateChangeListener) {
+		return listeners.remove(stateChangeListener);
 	}
 
-	private void notifyListener(final StateChangeListener.ChangeEvent event) {
-		for (StateChangeListener scl : listeners) {
+	private void notifyListener(final AbstractModelStateChangeListener.ChangeEvent event) {
+		for (AbstractModelStateChangeListener scl : listeners) {
 			if (scl.handleChange(event)) {
 				// Listener wants to be deregistered as a listener.
 				listeners.remove(scl);
@@ -252,7 +213,8 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
 			Assert.isTrue(launchName.contains(SPEC_MODEL_DELIM));
 			
 			final Spec spec = ToolboxHandle.getSpecByName(launchName.split(SPEC_MODEL_DELIM)[0]);
-			Assert.isNotNull(spec, "Failed to lookup spec with name " + launchName.split(SPEC_MODEL_DELIM)[0]);
+			Assert.isNotNull(spec, "Failed to lookup spec with name " + launchName.split(SPEC_MODEL_DELIM)[0]
+										+ " (" + launchName + ")");
 			
 			this.spec = spec.getAdapter(TLCSpec.class);
 		}
@@ -342,7 +304,7 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
 		this.spec = null;
 		
 		for (Model snapshot : snapshots) {
-			snapshot.specRename(newSpec);;
+			snapshot.specRename(newSpec);
 		}
 	}
 
@@ -356,9 +318,31 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
 			copy.setContainer(newSpec.getProject());
 			final ILaunchConfiguration renamed = copy.doSave();
 
+			final IFileStore ifs = ((LaunchConfiguration)launchConfig).getFileStore();
+			
+			// delete the copy of the old model in the new toolbox directory
+			if (ifs != null) {
+				final IPath newToolboxName = renamed.getFile().getFullPath().removeLastSegments(1);
+				final URI u = ifs.toURI();
+				final File oldLaunchConfigFile = new File(u);
+				final File grandParentDirectory = oldLaunchConfigFile.getParentFile().getParentFile();
+				final String newToolboxDirectoryName = newToolboxName.toString() + ResourceHelper.TOOLBOX_DIRECTORY_SUFFIX;
+				final File fileToDelete = Paths.get(grandParentDirectory.getAbsolutePath(),
+													newToolboxDirectoryName,
+													oldLaunchConfigFile.getName()).toFile();
+				
+				if (!fileToDelete.delete()) {
+					TLCActivator.logInfo("Could not delete old launch file [" + fileToDelete.getAbsolutePath()
+											+ "] - will attempt on app exit, which is better than nothing.");
+					fileToDelete.deleteOnExit();
+				}
+			} else {
+				TLCActivator.logInfo("Could not get filestore for the original launch config; this is problematic.");
+			}
+
 			// delete the old model
-			this.launchConfig.delete();
-			this.launchConfig = renamed;
+			launchConfig.delete();
+			launchConfig = renamed;
 		} catch (CoreException e) {
 			TLCActivator.logError("Error renaming model.", e);
 		}
@@ -403,7 +387,9 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
 			// running now.
 			recover();
 		}
-		notifyListener(new StateChangeListener.ChangeEvent(this, isRunning ? State.RUNNING : State.NOT_RUNNING));
+		notifyListener(new AbstractModelStateChangeListener.ChangeEvent(this, 
+				isRunning ? AbstractModelStateChangeListener.State.RUNNING
+						  : AbstractModelStateChangeListener.State.NOT_RUNNING));
 	}
 
     /**
@@ -444,7 +430,9 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
 
 	public void setRunningRemotely(boolean isRunning) {
 		this.isRunningRemotely = isRunning;
-		notifyListener(new StateChangeListener.ChangeEvent(this, isRunning ? State.REMOTE_RUNNING : State.REMOTE_NOT_RUNNING));
+		notifyListener(new AbstractModelStateChangeListener.ChangeEvent(this,
+				isRunning ? AbstractModelStateChangeListener.State.REMOTE_RUNNING
+						  : AbstractModelStateChangeListener.State.REMOTE_NOT_RUNNING));
 	}
 
 	/*
@@ -468,6 +456,11 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
 	}
 	
 	public Collection<Model> getSnapshots() {
+		if (isSnapshot()) {
+			// Snapshots do not have snapshots
+			return EMPTY_MODEL_SET;
+		}
+		
 		return getSpec().getModels(Pattern.quote(getName()) + SNAPSHOT_REGEXP, true).values();
 	}
 
@@ -548,7 +541,9 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
 	private void pruneOldestSnapshots() throws CoreException {
 		// Sort model by snapshot timestamp and remove oldest ones.
 		final int snapshotKeepCount = TLCActivator.getDefault().getPreferenceStore().getInt(TLCActivator.I_TLC_SNAPSHOT_KEEP_COUNT);
-		final List<Model> snapshotModels = new ArrayList<>(getSnapshots());
+		// Filter out running snapshots such as remotely running ones (CloudTLC).
+		final List<Model> snapshotModels = new ArrayList<>(getSnapshots().stream()
+				.filter(m -> !m.isRunning() && !m.isRunningRemotely()).collect(Collectors.toList()));
 		if (snapshotModels.size() > snapshotKeepCount) {
 		    final int pruneCount = snapshotModels.size() - snapshotKeepCount;
 		    Collections.sort(snapshotModels, new Comparator<Model>() {
@@ -754,7 +749,7 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
 			model.delete(SubMonitor.convert(monitor));
 		}
 		
-		notifyListener(new ChangeEvent(this, State.DELETED));
+		notifyListener(new AbstractModelStateChangeListener.ChangeEvent(this, AbstractModelStateChangeListener.State.DELETED));
 		
 		final IResource[] members;
 
@@ -844,7 +839,7 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
 	 * @return a file handle or <code>null</code>
 	 */
 	public IFile getTLAFile() {
-		return getFile(ModelHelper.FILE_TLA);
+		return getFile(TLAConstants.Files.MODEL_CHECK_TLA_FILE);
 	}
 
 	/**
@@ -875,7 +870,7 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
 		if (getTraceExplorerOutput) {
 			return getFile(ModelHelper.TE_FILE_OUT);
 		} else {
-			return getFile(ModelHelper.FILE_OUT);
+			return getFile(TLAConstants.Files.MODEL_CHECK_OUTPUT_FILE);
 		}
 	}
 
@@ -936,7 +931,7 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
         	targetFolder.refreshLocal(IFolder.DEPTH_INFINITE, monitor);
         	
         	// Import MC.out
-        	IFile mcOutFile = targetFolder.getFile(ModelHelper.FILE_OUT);
+        	IFile mcOutFile = targetFolder.getFile(TLAConstants.Files.MODEL_CHECK_OUTPUT_FILE);
         	if (mcOutFile.exists()) {
         		mcOutFile.delete(true, monitor);
         	}
@@ -958,7 +953,7 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
 		return getSpec().getProject().getFolder(getName());
 	}
 
-    private static final String CHECKPOINT_STATES = ModelHelper.MC_MODEL_NAME + ".st.chkpt";
+    private static final String CHECKPOINT_STATES = TLAConstants.Files.MODEL_CHECK_FILE_BASENAME + ".st.chkpt";
     private static final String CHECKPOINT_QUEUE = "queue.chkpt";
     private static final String CHECKPOINT_VARS = "vars.chkpt";
 
@@ -1038,15 +1033,12 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
         return result;
     }
 
-    private static final String CR = "\n";
-    private static final String SPACE = " ";
-
     /**
      * Returns a possibly empty List of {@link SimpleTLCState} that represents
      * the error trace produced by the most recent run of TLC on config, if an error
      * trace was produced.
      */
-    public List<SimpleTLCState> getErrorTrace()
+    public List<MCState> getErrorTrace()
     {
         /*
          * Use a file editor input and file document provider to gain access to the
@@ -1062,17 +1054,14 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
             FindReplaceDocumentAdapter logFileSearcher = new FindReplaceDocumentAdapter(logFileDocument);
 
             // the regular expression for searching for the start tag for state print outs
-            String regExStartTag = MP.DELIM + MP.STARTMSG + "[0-9]{4}" + MP.COLON + MP.STATE + SPACE + MP.DELIM + CR;
+            String regExStartTag = MP.DELIM + MP.STARTMSG + "[0-9]{4}" + MP.COLON + MP.STATE + MP.SPACE + MP.DELIM + MP.CR;
             // the regular expression for searching for the end tag for state print outs
-            String regExEndTag = MP.DELIM + MP.ENDMSG + "[0-9]{4}" + SPACE + MP.DELIM;
+            String regExEndTag = MP.DELIM + MP.ENDMSG + "[0-9]{4}" + MP.SPACE + MP.DELIM;
 
             IRegion startTagRegion = logFileSearcher.find(0, regExStartTag, true, true, false, true);
 
-            // vector of SimpleTLCStates
-            Vector<SimpleTLCState> trace = new Vector<SimpleTLCState>();
-
-            while (startTagRegion != null)
-            {
+            final ArrayList<MCState> trace = new ArrayList<>();
+			while (startTagRegion != null) {
                 IRegion endTagRegion = logFileSearcher.find(startTagRegion.getOffset() + startTagRegion.getLength(),
                         regExEndTag, true, true, false, true);
 
@@ -1083,7 +1072,7 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
                     // string from which the state can be parsed
                     String stateInputString = logFileDocument.get(stateInputStart, stateInputLength);
 
-                    trace.add(SimpleTLCState.parseSimpleTLCState(stateInputString));
+                    trace.add(MCState.parseState(stateInputString));
 
                 } else
                 {
@@ -1115,7 +1104,7 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
             logFileDocumentProvider.disconnect(logFileEditorInput);
         }
 
-        return new Vector<SimpleTLCState>();
+        return new Vector<MCState>();
     }
     
     /**
@@ -1137,10 +1126,28 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
     	return fullyQualifiedNameFromSpecNameAndModelName(getSpec().getName(), getName());
     }
 
+	public void setTraceExplorerExtends(final Set<String> modules) {
+        try {
+        	getWorkingCopy().setAttribute(IModelConfigurationConstants.TRACE_EXPLORE_EXTENDS, modules);
+		} catch (CoreException shouldNotHappen) {
+			TLCActivator.logError(shouldNotHappen.getMessage(), shouldNotHappen);
+		}
+	}
+	
+	public Set<String> getTraceExplorerExtends() {
+		final Set<String> defaultValue = new HashSet<String>();
+		try {
+			return this.launchConfig.getAttribute(IModelConfigurationConstants.TRACE_EXPLORE_EXTENDS, defaultValue);
+		} catch (CoreException shouldNotHappen) {
+			TLCActivator.logError(shouldNotHappen.getMessage(), shouldNotHappen);
+			return defaultValue;
+		}
+	}
+
 	public List<String> getTraceExplorerExpressions() {
 		final Vector<String> defaultValue = new Vector<String>();
 		try {
-			return this.launchConfig.getAttribute(IModelConfigurationConstants.TRACE_EXPLORE_EXPRESSIONS, defaultValue);
+			return this.launchConfig.getAttribute(TLAConstants.TraceExplore.TRACE_EXPLORE_EXPRESSIONS, defaultValue);
 		} catch (CoreException shouldNotHappen) {
 			TLCActivator.logError(shouldNotHappen.getMessage(), shouldNotHappen);
 			return defaultValue;
@@ -1149,7 +1156,7 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
 
 	public List<Formula> getTraceExplorerExpressionsAsFormula() {
 		final List<String> traceExplorerExpressions = getTraceExplorerExpressions();
-		return ModelHelper.deserializeFormulaList(traceExplorerExpressions);
+		return Formula.deserializeFormulaList(traceExplorerExpressions);
 	}
 	
 	public Map<String, Formula> getNamedTraceExplorerExpressionsAsFormula() {
@@ -1168,12 +1175,28 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
 		// into a working copy, which is synced on save. Thus, make sure never
 		// to write to different copies concurrently.
         try {
-        	getWorkingCopy().setAttribute(IModelConfigurationConstants.TRACE_EXPLORE_EXPRESSIONS, serializedInput);
+        	getWorkingCopy().setAttribute(TLAConstants.TraceExplore.TRACE_EXPLORE_EXPRESSIONS, serializedInput);
+		} catch (CoreException shouldNotHappen) {
+			TLCActivator.logError(shouldNotHappen.getMessage(), shouldNotHappen);
+		}
+	}
+	
+	public void setModelVersion(final int version) {
+        try {
+        	getWorkingCopy().setAttribute(IModelConfigurationConstants.MODEL_VERSION, version);
 		} catch (CoreException shouldNotHappen) {
 			TLCActivator.logError(shouldNotHappen.getMessage(), shouldNotHappen);
 		}
 	}
 	
+	public int getModelVersion() {
+        try {
+			return getWorkingCopy().getAttribute(IModelConfigurationConstants.MODEL_VERSION, 0);
+		} catch (CoreException shouldNotHappen) {
+			return -1;
+		}
+	}
+
 	public void setOpenTabsValue(final int value) {
         try {
         	getWorkingCopy().setAttribute(IModelConfigurationConstants.EDITOR_OPEN_TABS, value);
@@ -1208,8 +1231,15 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
 	}
 
 	public Model save(final IProgressMonitor monitor) {
+    	// Uncomment the following for development time forced restoration of all closeable tabs.
+//    	setOpenTabsValue((1 << 1) | (1 << 2) | (1 << 3));
+		setModelVersion(IModelConfigurationConstants.VERSION_161);
+		
 		if (this.workingCopy != null) {
-			//TODO This is a workspace operation and thus should be decoupled from the UI thread.
+			if (Thread.currentThread().equals(Display.getDefault().getThread())) {
+				TLCActivator.logInfo("Model save is occurring on the SWT thread, this should be addressed.");
+			}
+
 			try {
 				this.launchConfig = this.workingCopy.doSave();
 				// Null the temporary working copy . Save effectively merges the
@@ -1313,40 +1343,22 @@ public class Model implements IModelConfigurationConstants, IAdaptable {
 		}
 	}
 	
-	// TLC's coverage implementation (see tlc2.tool.coverage.CostModelCreator) only
-	// supports two modes: Off and On. However, we consider On too much information
-	// for novice users who are (likely) only interested in identifying spec errors
-	// that leave a subset of actions permanently disabled. The Toolbox therefore
-	// adds a third mode "Action" which filters TLC's output for All. This obviously
-	// means that the overhead of collecting coverage in Action and On mode is
-	// identical.  This shouldn't matter however as novice users don't create large
-	// specs anyway and the Toolbox warns users when a large spec has been
-	// configured with coverage.
-	// (see org.lamport.tla.toolbox.tool.tlc.output.data.CoverageUINotification)
-	// Alternatively, tlc2.tool.coverage.ActionWrapper.report() could be changed to
-	// omit the report of its children (line 126) to effectively create the Action
-	// mode at the TLC layer. I decided against it though, because I didn't want to
-	// extend the -coverage TLC parameter.
-	public enum Coverage {
-		OFF, ACTION, ON;
-	}
-	
-	public Coverage setCoverage(final Coverage c) {
+	public ModelCoverage setCoverage(final ModelCoverage c) {
 		setAttribute(LAUNCH_COVERAGE, c.ordinal());
 		return c;
 	}
 	
-	public Coverage getCoverage() {
+	public ModelCoverage getCoverage() {
 		try {
 			final int ordinal = getAttribute(LAUNCH_COVERAGE, IConfigurationDefaults.LAUNCH_COVERAGE_DEFAULT);
-			return Coverage.values()[ordinal];
+			return ModelCoverage.values()[ordinal];
 		} catch (DebugException legacyException) {
 			// Occurs for old models where the type wasn't int but bool.
 		} catch (CoreException shouldNotHappen) {
 			// We log the exceptions on setAttribute but expose exceptions with getAttribute %-)
 			TLCActivator.logError(shouldNotHappen.getMessage(), shouldNotHappen);
 		}
-		return Coverage.ACTION;
+		return ModelCoverage.ACTION;
 	}
 	
 	/* IAdaptable */
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/ModelCoverage.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/ModelCoverage.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf17bcc869c894684cd0c40acea8e9bb79643778
--- /dev/null
+++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/ModelCoverage.java
@@ -0,0 +1,30 @@
+package org.lamport.tla.toolbox.tool.tlc.model;
+
+/**
+ * TLC's coverage implementation (see tlc2.tool.coverage.CostModelCreator) only
+ * supports two modes: Off and On. However, we consider On too much information
+ * for novice users who are (likely) only interested in identifying spec errors
+ * that leave a subset of actions permanently disabled. The Toolbox therefore
+ * adds a third mode "Action" which filters TLC's output for All. This obviously
+ * means that the overhead of collecting coverage in Action and On mode is
+ * identical. This shouldn't matter however as novice users don't create large
+ * specs anyway and the Toolbox warns users when a large spec has been
+ * configured with coverage. (see
+ * org.lamport.tla.toolbox.tool.tlc.output.data.CoverageUINotification)
+ * Alternatively, tlc2.tool.coverage.ActionWrapper.report() could be changed to
+ * omit the report of its children (line 126) to effectively create the Action
+ * mode at the TLC layer. I decided against it though, because I didn't want to
+ * extend the -coverage TLC parameter.
+ */
+public enum ModelCoverage {
+	/**
+	 * This was an inner-enum to the {@link Model} class, but the Eclipse IDE's
+	 * syntax colorer was breaking on code that refers to inner-enums (and
+	 * inner-inner-enums that were refactored out of Model's state change listener
+	 * related code.)
+	 */
+	
+	OFF,
+	ACTION,
+	ON;
+}
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/ModelWriter.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/ModelWriter.java
index db9283d25dac23ae7c5502edb3002d3066a8fcdc..0722395aafc4294eb9c00b66264152cc50c88b64 100644
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/ModelWriter.java
+++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/ModelWriter.java
@@ -25,90 +25,40 @@
  ******************************************************************************/
 package org.lamport.tla.toolbox.tool.tlc.model;
 
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Vector;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.io.IOException;
 
 import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.debug.core.ILaunchConfiguration;
-import org.eclipse.jface.text.IRegion;
-import org.eclipse.jface.text.Region;
-import org.lamport.tla.toolbox.tool.ToolboxHandle;
-import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.PlatformUI;
 import org.lamport.tla.toolbox.util.ResourceHelper;
 
-import tla2sany.modanalyzer.SpecObj;
-import tla2sany.semantic.OpDefNode;
+import tlc2.output.AbstractSpecWriter;
 
 /**
- * Encapsulates two buffers and provides semantic methods to add content to the _MC file and the CFG file of the model 
+ * Encapsulates two buffers and provides semantic methods to add content to the TLA file and the CFG file of the model 
  */
-public class ModelWriter
-{
+public class ModelWriter extends AbstractSpecWriter {
     /**
-     * Counter to be able to generate unique identifiers
+     * Constructs new model writer
      */
-    private static final AtomicLong COUNTER = new AtomicLong(1L);
-
-    public static final String SPEC_SCHEME = "spec";
-    public static final String INIT_SCHEME = "init";
-    public static final String NEXT_SCHEME = "next";
-    public static final String CONSTANT_SCHEME = "const";
-    public static final String SYMMETRY_SCHEME = "symm";
-    public static final String DEFOV_SCHEME = "def_ov";
-    public static final String CONSTRAINT_SCHEME = "constr";
-    public static final String ACTIONCONSTRAINT_SCHEME = "action_constr";
-    public static final String INVARIANT_SCHEME = "inv";
-    public static final String PROP_SCHEME = "prop";
-    public static final String VIEW_SCHEME = "view";
-    public static final String CONSTANTEXPR_SCHEME = "const_expr";
-    public static final String TRACE_EXPR_VAR_SCHEME = "__trace_var";
-    public static final String TRACE_EXPR_DEF_SCHEME = "trace_def";
-
-    public static final String SPACE = " ";
-    public static final String CR = "\n";
-    public static final String SEP = "----";
-    public static final String EQ = " = ";
-    public static final String ARROW = " <- ";
-    public static final String DEFINES = " == ";
-    public static final String DEFINES_CR = " ==\n";
-    public static final String COMMENT = "\\* ";
-    public static final String ATTRIBUTE = "@";
-    public static final String INDEX = ":";
-    public static final String EMPTY_STRING = "";
-    public static final String CONSTANT_EXPRESSION_EVAL_IDENTIFIER = "\"$!@$!@$!@$!@$!\"";
-    public static final String COMMA = ",";
-    public static final String BEGIN_TUPLE = "<<";
-    public static final String END_TUPLE = ">>";
-    public static final String PRIME = "'";
-    public static final String VARIABLES = "VARIABLES ";
-    public static final String TLA_AND = "/\\";
-    public static final String TLA_OR = "\\/";
-    public static final String TLA_NOT = "~";
-    public static final String TLA_EVENTUALLY_ALWAYS = "<>[]";
-    public static final String TLA_INF_OFTEN = "[]<>";
-    public static final String TRACE_NA = "\"--\"";
-    public static final String L_PAREN = "(";
-    public static final String R_PAREN = ")";
-
-    protected final StringBuffer tlaBuffer;
-    protected final StringBuffer cfgBuffer;
+	public ModelWriter() {
+		super(true);
+	}
 
     /**
-     * Constructs new model writer
+     * {@inheritDoc}
      */
-    public ModelWriter()
-    {
-        this.tlaBuffer = new StringBuffer(1024);
-        this.cfgBuffer = new StringBuffer(1024);
+	@Override
+    protected String getTLAModuleClosingTag() {
+        final StringBuilder sb = ResourceHelper.getModuleClosingTag();
+    	
+    	return sb.toString();
     }
-
+	
     /**
      * Write the content to files
      * @param tlaFile
@@ -116,662 +66,26 @@ public class ModelWriter
      * @param monitor
      * @throws CoreException
      */
-    public void writeFiles(IFile tlaFile, IFile cfgFile, IProgressMonitor monitor) throws CoreException
-    {
-        tlaBuffer.append(ResourceHelper.getModuleClosingTag());
-        cfgBuffer.append(ResourceHelper.getConfigClosingTag());
-        ResourceHelper.replaceContent(tlaFile, tlaBuffer, monitor);
-        ResourceHelper.replaceContent(cfgFile, cfgBuffer, monitor);
-    }
-
-    /**
-     * Add file header, which consists of the module-beginning ----- MODULE ... ---- line and
-     * the EXTENDS statement.
-     * @param moduleFilename
-     * @param extendedModuleName
-     */
-    public void addPrimer(String moduleFilename, String extendedModuleName)
-    {
-        tlaBuffer.append(ResourceHelper.getExtendingModuleContent(moduleFilename, new String[] {extendedModuleName, "TLC"}));
-    }
-
-    /**
-     * Add spec definition
-     * @param specDefinition
-     */
-    public void addSpecDefinition(String[] specDefinition, String attributeName)
-    {
-        cfgBuffer.append("SPECIFICATION").append(SPACE);
-        cfgBuffer.append(specDefinition[0]).append(CR);
-
-        tlaBuffer.append(COMMENT).append("Specification ").append(ATTRIBUTE).append(attributeName).append(CR);
-        tlaBuffer.append(specDefinition[1]).append(CR).append(SEP).append(CR);
-
-    }
-
-    /**
-     * Documentation by SZ: Add constants declarations. 
-     * 
-     * On 17 March 2012, LL split the original addConstants method
-     * into the current one plus the addConstantsBis method.  As explained in Bugzilla Bug 280,
-     * this was to allow the user definitions added on the Advanced Model page to appear between
-     * the CONSTANT declarations for model values and the definitions of the expressions that 
-     * instantiate CONSTANT parameters.  (This allows symbols defined in those user definitions to
-     * appear in the expressions instantiated for CONSTANT parameters.)
-     * 
-     * See the use of these two methods in TLCModelLaunchDelegate.buildForLaunch for a description
-     * of what these methods do.
-     * 
-     * @param constants
-     * @param modelValues
-     */
-    public void addConstants(List<Assignment> constants, TypedSet modelValues, String attributeConstants, String attributeMVs)
-    {
-        // add declarations for model values introduced on Advanced Model page.
-        addMVTypedSet(modelValues, "MV CONSTANT declarations ", attributeMVs);
-
-        Assignment constant;
-        Vector<String> symmetrySets = new Vector<String>();
-
-        // first run for all the declarations
-        for (int i = 0; i < constants.size(); i++)
-        {
-            constant = (Assignment) constants.get(i);
-            if (constant.isModelValue())
-            {
-                if (constant.isSetOfModelValues())
-                {
-                    // set model values
-                    TypedSet setOfMVs = TypedSet.parseSet(constant.getRight());
-                    addMVTypedSet(setOfMVs, "MV CONSTANT declarations", attributeConstants);
-                }
-            }
-        }
-
-        // now all the definitions
-        for (int i = 0; i < constants.size(); i++)
-        {
-            constant = (Assignment) constants.get(i);
-            if (constant.isModelValue())
-            {
-                if (constant.isSetOfModelValues())
-                {
-                    // set model values
-                    cfgBuffer.append(COMMENT).append("MV CONSTANT definitions").append(CR);
-                    tlaBuffer.append(COMMENT).append("MV CONSTANT definitions " + constant.getLeft()).append(CR);
-
-                    String id = addArrowAssignment(constant, CONSTANT_SCHEME);
-                    if (constant.isSymmetricalSet())
-                    {
-                        symmetrySets.add(id);
-                    }
-                    tlaBuffer.append(SEP).append(CR).append(CR);
-                } else
-                {
-                    cfgBuffer.append(COMMENT).append("CONSTANT declarations").append(CR);
-                    // model value assignment
-                    // to .cfg : foo = foo
-                    // to _MC.tla : <nothing>, since the constant is already defined in one of the spec modules
-                    cfgBuffer.append("CONSTANT").append(SPACE).append(constant.getLabel()).append(EQ).append(
-                            constant.getRight()).append(CR);
-                }
-            } else
-            {
-//                // simple constant value assignment
-//                cfgBuffer.append(COMMENT).append("CONSTANT definitions").append(CR);
-//
-//                tlaBuffer.append(COMMENT).append("CONSTANT definitions ").append(ATTRIBUTE).append(attributeConstants)
-//                        .append(INDEX).append(i).append(constant.getLeft()).append(CR);
-//                addArrowAssignment(constant, CONSTANT_SCHEME);
-//                tlaBuffer.append(SEP).append(CR).append(CR);
-            }
-        }
-
-        // symmetry
-        if (!symmetrySets.isEmpty())
-        {
-            String label = ModelWriter.getValidIdentifier(SYMMETRY_SCHEME);
-
-            tlaBuffer.append(COMMENT).append("SYMMETRY definition").append(CR);
-            cfgBuffer.append(COMMENT).append("SYMMETRY definition").append(CR);
-
-            tlaBuffer.append(label).append(DEFINES).append(CR);
-            // symmetric model value sets added
-            for (int i = 0; i < symmetrySets.size(); i++)
-            {
-                tlaBuffer.append("Permutations(").append(symmetrySets.get(i)).append(")");
-                if (i != symmetrySets.size() - 1)
-                {
-                    tlaBuffer.append(" \\union ");
-                }
-            }
-
-            tlaBuffer.append(CR).append(SEP).append(CR).append(CR);
-            cfgBuffer.append("SYMMETRY").append(SPACE).append(label).append(CR);
-        }
-
-    }
-
-    public void addConstantsBis(List<Assignment> constants, /* TypedSet modelValues, */ String attributeConstants /* , String attributeMVs */)
-    {
-//        // add declarations for model values introduced on Advanced Model page.
-//        addMVTypedSet(modelValues, "MV CONSTANT declarations ", attributeMVs);
-//
-        Assignment constant;
-//        Vector symmetrySets = new Vector();
-//
-//        // first run for all the declarations
-//        for (int i = 0; i < constants.size(); i++)
-//        {
-//            constant = (Assignment) constants.get(i);
-//            if (constant.isModelValue())
-//            {
-//                if (constant.isSetOfModelValues())
-//                {
-//                    // set model values
-//                    TypedSet setOfMVs = TypedSet.parseSet(constant.getRight());
-//                    addMVTypedSet(setOfMVs, "MV CONSTANT declarations", attributeConstants);
-//                }
-//            }
-//        }
-
-        // now all the definitions
-        for (int i = 0; i < constants.size(); i++)
-        {
-            constant = (Assignment) constants.get(i);
-            if (constant.isModelValue())
-            {
-//                if (constant.isSetOfModelValues())
-//                {
-//                    // set model values
-//                    cfgBuffer.append(COMMENT).append("MV CONSTANT definitions").append(CR);
-//                    tlaBuffer.append(COMMENT).append("MV CONSTANT definitions " + constant.getLeft()).append(CR);
-//
-//                    String id = addArrowAssignment(constant, CONSTANT_SCHEME);
-//                    if (constant.isSymmetricalSet())
-//                    {
-//                        symmetrySets.add(id);
-//                    }
-//                    tlaBuffer.append(SEP).append(CR).append(CR);
-//                } else
-//                {
-//                    cfgBuffer.append(COMMENT).append("CONSTANT declarations").append(CR);
-//                    // model value assignment
-//                    // to .cfg : foo = foo
-//                    // to _MC.tla : <nothing>, since the constant is already defined in one of the spec modules
-//                    cfgBuffer.append("CONSTANT").append(SPACE).append(constant.getLabel()).append(EQ).append(
-//                            constant.getRight()).append(CR);
-//                }
-            } else
-            {
-                // simple constant value assignment
-                cfgBuffer.append(COMMENT).append("CONSTANT definitions").append(CR);
-
-                tlaBuffer.append(COMMENT).append("CONSTANT definitions ").append(ATTRIBUTE).append(attributeConstants)
-                        .append(INDEX).append(i).append(constant.getLeft()).append(CR);
-                addArrowAssignment(constant, CONSTANT_SCHEME);
-                tlaBuffer.append(SEP).append(CR).append(CR);
-            }
-        }
-
-        // symmetry
-//        if (!symmetrySets.isEmpty())
-//        {
-//            String label = ModelWriter.getValidIdentifier(SYMMETRY_SCHEME);
-//
-//            tlaBuffer.append(COMMENT).append("SYMMETRY definition").append(CR);
-//            cfgBuffer.append(COMMENT).append("SYMMETRY definition").append(CR);
-//
-//            tlaBuffer.append(label).append(DEFINES).append(CR);
-//            // symmetric model value sets added
-//            for (int i = 0; i < symmetrySets.size(); i++)
-//            {
-//                tlaBuffer.append("Permutations(").append((String) symmetrySets.get(i)).append(")");
-//                if (i != symmetrySets.size() - 1)
-//                {
-//                    tlaBuffer.append(" \\union ");
-//                }
-//            }
-//
-//            tlaBuffer.append(CR).append(SEP).append(CR).append(CR);
-//            cfgBuffer.append("SYMMETRY").append(SPACE).append(label).append(CR);
-//        }
-
-    }
-
-
-    /**
-     * Add the view definition
-     * @param viewString the string that the user enters into the view field
-     * @param attributeName the attribute name of the view field
-     */
-    public void addView(String viewString, String attributeName)
-    {
-        if (!(viewString.trim().length() == 0))
-        {
-            cfgBuffer.append(COMMENT).append("VIEW definition").append(CR);
-            String id = ModelWriter.getValidIdentifier(VIEW_SCHEME);
-            cfgBuffer.append("VIEW").append(CR).append(id).append(CR);
-            tlaBuffer.append(COMMENT).append("VIEW definition ").append(ATTRIBUTE).append(attributeName).append(CR);
-            tlaBuffer.append(id).append(DEFINES).append(CR).append(viewString).append(CR);
-            tlaBuffer.append(SEP).append(CR).append(CR);
-        }
-    }
-
-    /**
-     * Adds the ASSUME PrintT statement and identifier for the constant expression
-     * evaluation. The MC.tla file will contain:
-     * 
-     * const_expr_1232141234123 ==
-     * expression
-     * -----
-     * ASSUME PrintT(<<"$!@$!@$!@$!@$!", const_expr_1232141234123>>)
-     * 
-     * See the comments in the method for an explanation of defining
-     * an identifier.
-     * 
-     * @param expression
-     * @param attributeName
-     */
-    public void addConstantExpressionEvaluation(String expression, String attributeName)
-    {
-        if (!((expression.trim().length()) == 0))
-        {
-            /*
-             *  Identifier definition
-             *  We define an identifier for more sensible error messages
-             *  For example, if the user enters "1+" into the constant
-             *  expression field and "1+" is placed as the second element
-             *  of the tuple that is the argument for PrintT(), then the parse
-             *  error would be something like "Encountered >>" which would be
-             *  mysterious to the user. With an identifier defined, the message
-             *  says "Encountered ----" which is the separator after each section in
-             *  MC.tla. This error message is equally mysterious, but at least
-             *  it is the same message that would appear were the same error present
-             *  in another section in the model editor. We can potentially replace
-             *  such messages with something more sensible in the future in the 
-             *  appendError() method in TLCErrorView.
-             */
-            String id = ModelWriter.getValidIdentifier(CONSTANTEXPR_SCHEME);
-            tlaBuffer.append(COMMENT).append("Constant expression definition ").append(ATTRIBUTE).append(attributeName)
-                    .append(CR);
-            tlaBuffer.append(id).append(DEFINES).append(CR).append(expression).append(CR);
-            tlaBuffer.append(SEP).append(CR).append(CR);
-
-            // ASSUME PrintT(<<"$!@$!@$!@$!@$!", const_expr_23423232>>) statement
-            // The "$!@$!@$!@$!@$!" allows the toolbox to identify the
-            // value of the constant expression in the TLC output
-            tlaBuffer.append(COMMENT).append("Constant expression ASSUME statement ").append(ATTRIBUTE).append(
-                    attributeName).append(CR);
-            tlaBuffer.append("ASSUME PrintT(").append(BEGIN_TUPLE).append(CONSTANT_EXPRESSION_EVAL_IDENTIFIER).append(
-                    COMMA).append(id).append(END_TUPLE).append(")").append(CR);
-            tlaBuffer.append(SEP).append(CR).append(CR);
-        }
-    }
-
-    /**
-     * Assigns a right side to a label using an id generated from given schema
-     * @param constant, constant containing the values
-     * @param schema schema to generate the Id
-     * @return generated id
-     */
-    public String addArrowAssignment(Assignment constant, String schema)
-    {
-        // constant instantiation
-        // to .cfg : foo <- <id>
-        // to _MC.tla : <id>(a, b, c)==
-        // <expression>
-        String id = ModelWriter.getValidIdentifier(schema);
-        tlaBuffer.append(constant.getParametrizedLabel(id)).append(DEFINES).append(CR).append(constant.getRight())
-                .append(CR);
-        cfgBuffer.append("CONSTANT").append(CR);
-        cfgBuffer.append(constant.getLabel()).append(ARROW).append(id).append(CR);
-        return id;
-    }
-
-    /**
-     * Creates a serial version of an MV set in both files
-     * @param mvSet typed set containing the model values
-     * @param comment a comment to put before the declarations, null and empty strings are OK
-     */
-    public void addMVTypedSet(TypedSet mvSet, String comment, String attributeName)
-    {
-        if (mvSet.getValueCount() != 0)
-        {
-            // create a declaration line
-            // CONSTANTS
-            // a, b, c
-            if (comment != null && !(comment.length() == 0))
-            {
-                tlaBuffer.append(COMMENT).append(comment).append(ATTRIBUTE).append(attributeName).append(CR);
-            }
-            tlaBuffer.append("CONSTANTS").append(CR).append(mvSet.toStringWithoutBraces());
-            tlaBuffer.append(CR).append(SEP).append(CR).append(CR);
-
-            // create MV assignments
-            // a = a
-            // b = b
-            // c = c
-            if (comment != null && !(comment.length() == 0))
-            {
-                cfgBuffer.append(COMMENT).append(comment).append(CR);
-            }
-            cfgBuffer.append("CONSTANTS").append(CR);
-            String mv;
-            for (int i = 0; i < mvSet.getValueCount(); i++)
-            {
-                mv = mvSet.getValue(i);
-                cfgBuffer.append(mv).append(EQ).append(mv).append(CR);
-            }
-        }
-    }
-    public void addFormulaList(String element, String keyword, String attributeName) {
-    	final List<String[]> elements = new ArrayList<>(1);
-    	elements.add(new String[] {element, EMPTY_STRING});
-    	addFormulaList(elements, keyword, attributeName);
-    }
-    
-    /**
-     * Puts (String[])element[0] to CFG file and element[1] to TLA_MC file, if element[2] present, uses it as index.
-     * 
-     * @param elements a list of String[] elements
-     * @param keyword the keyword to be used in the CFG file
-     * @param attributeName the name of the attribute in the model file
-     */
-    public void addFormulaList(List<String[]> elements, String keyword, String attributeName)
-    {
-        if (elements.isEmpty())
-        {
-            return;
-        }
-        cfgBuffer.append(COMMENT).append(keyword + " definition").append(CR);
-        cfgBuffer.append(keyword).append(CR);
-
-        for (int i = 0; i < elements.size(); i++)
-        {
-            String[] element = elements.get(i);
-            cfgBuffer.append(element[0]).append(CR);
-            // when a definition in the root module is overridden as a model value
-            // there is nothing to add to the MC.tla file so, we do not do the following
-            if (!element[1].equals(EMPTY_STRING))
-            {
-                tlaBuffer.append(COMMENT).append(keyword + " definition ").append(ATTRIBUTE).append(attributeName)
-                        .append(INDEX).append(element.length > 2 ? element[2] : i).append(CR);
-                tlaBuffer.append(element[1]).append(CR).append(SEP).append(CR);
-            }
-        }
-    }
-
-    /**
-     * New definitions are added to the _MC.tla file only
-     * @param elements
-     */
-    public void addNewDefinitions(String definitions, String attributeName)
-    {
-        if (definitions.trim().length() == 0)
-        {
-            return;
-        }
-        tlaBuffer.append(COMMENT).append("New definitions ").append(ATTRIBUTE).append(attributeName).append(CR);
-        tlaBuffer.append(definitions).append(CR).append(SEP).append(CR);
-    }
-
-    /**
-     * Create the content for a single source element
-     * @return a list with at most one String[] element
-     * @throws CoreException 
-     */
-    public static List<String[]> createSourceContent(String propertyName, String labelingScheme, ILaunchConfiguration config)
-            throws CoreException
-    {
-        Vector<String[]> result = new Vector<String[]>();
-        String value = config.getAttribute(propertyName, EMPTY_STRING);
-        if (value.trim().length() == 0)
-        {
-            return result;
-        }
-        String identifier = getValidIdentifier(labelingScheme);
-        StringBuffer buffer = new StringBuffer();
-
-        // the identifier
-        buffer.append(identifier).append(DEFINES_CR);
-        buffer.append(value);
-
-        result.add(new String[] { identifier, buffer.toString() });
-        return result;
-    }
-
-    public static List<String[]> createFalseInit(String var)
-    {
-        List<String[]> list = new Vector<String[]>();
-        String identifier = getValidIdentifier(INIT_SCHEME);
-        list.add(new String[] { identifier, identifier + DEFINES_CR + "FALSE/\\" + var + EQ + "0" });
-        return list;
-    }
-
-    public static List<String[]> createFalseNext(String var)
-    {
-        List<String[]> list = new Vector<String[]>();
-        String identifier = getValidIdentifier(NEXT_SCHEME);
-        list.add(new String[] { identifier, identifier + DEFINES_CR + "FALSE/\\" + var + PRIME + EQ + var });
-        return list;
+	public void writeFiles(final IFile tlaFile, final IFile cfgFile, final IProgressMonitor monitor) throws CoreException {
+		final ContentWriter cw = (inputStream, forTLAFile) -> {
+			final IFile file = forTLAFile ? tlaFile : cfgFile;
+			
+			if (file.exists()) {
+				try {
+					file.setContents(inputStream, IResource.FORCE, monitor);
+				} catch (final CoreException ce) {
+					throw new IOException("Exception writing file " + ce.getMessage(), ce);
+				}
+			} else {
+				throw new IOException("Expected file " + file.getName() + " has been removed externally.");
+			}
+		};
+		
+		try {
+			super.writeFiles(cw);
+		} catch (final IOException e) {
+			throw new CoreException(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.ERROR,
+									"Exception encountered attempting to write modules for the model checking.", e));
+		}
     }
-
-    /**
-     * Converts formula list to a string representation
-     * @param serializedFormulaList, list of strings representing formulas (with enablement flag)
-     * @param labelingScheme
-     * @return
-     */
-    public static List<String[]> createFormulaListContent(List<String> serializedFormulaList, String labelingScheme)
-    {
-        List<Formula> formulaList = ModelHelper.deserializeFormulaList(serializedFormulaList);
-        return createFormulaListContentFormula(formulaList, labelingScheme);
-    }
-    
-    public static List<String[]> createFormulaListContentFormula(List<Formula> serializedFormulaList, String labelingScheme)
-    {
-    	return createListContent(serializedFormulaList, labelingScheme);
-    }
-
-    /**
-     * Create a list of overrides. If the override is not in the spec's root module, then
-     * the config file will have     A <- [M] id . This means that A is defined in module M,
-     * and its definition is being overriden in the spec root module which is dependent upon M.
-     * The following is an example from Leslie Lamport that explains what occured before changing
-     * the code and what occurs now.
-     * Consider the root module
-
-    ----------------- MODULE TestA --------------------
-    M(a,b) == INSTANCE TestB WITH CB <- a, CD <- b
-    ==================================================
-
-    which imports the module
-
-    ----------------- MODULE TestB --------------------
-    CONSTANTS CB, CD
-
-    Foo(x) == <<x, CB, CD>>
-    ==================================================
-
-    If you go to definition overrides, you'll find the option of
-    overriding M!Foo.  Selecting it, the toolbox asks you to define an operator
-    M!Foo of 3 arguments.  If you do it and run TLC, you get the error
-
-    The configuration file substitutes for Foo with
-    def_ov_12533499062845000 of different number of arguments.
-
-    Here's what's going on.  The INSTANCE statement imports the operator
-    M!Foo into module TestA.  As you may recall, you use that operator
-    in an expression by writing something like
-
-    M(42, "a")!F(-13)
-
-    but in the semantic tree, it looks just as if M!F were any other
-    operator with three arguments.  When TLC sees the override instruction
-
-    Foo <- [TestB]def_ov_12533495599614000
-
-    in the .cfg file, it tries to substitute an operator def_ov_...  with
-    3 arguments for the operator Foo of module TestB that has only a
-    single argument.  Hence, the error.
-
-    ------
-
-    Here's the fix.  Instead of giving the user the option of overriding
-    M!Foo, in the menu, he should simply see Foo and, if he clicks once
-    it, he should see that it's in module TestB. If he chooses to override
-    Foo, he should be asked to define an operator of one argument.
-    
-     * @param overrides
-     * @param string
-     * @return
-     * 
-     * Was throwing null-pointer exception when called with spec unparsed.
-     * Hacked a fix to handle this case.  LL 20 Sep 2009
-     */
-    public static List<String[]> createOverridesContent(List<Assignment> overrides, String labelingScheme)
-    {
-        Vector<String[]> resultContent = new Vector<String[]>(overrides.size());
-        String[] content;
-        String id;
-        Assignment formula;
-
-        // getting the opdefnodes is necessary for retrieving the correct label
-        // to appear in the cfg file as explained in the documentation for this method
-        SpecObj specObj = ToolboxHandle.getCurrentSpec().getValidRootModule();
-        if (specObj == null)
-        {
-            return resultContent;
-        }
-        OpDefNode[] opDefNodes = specObj.getExternalModuleTable().getRootModule().getOpDefs();
-        Hashtable<String, OpDefNode> nodeTable = new Hashtable<String, OpDefNode>(opDefNodes.length);
-
-        for (int j = 0; j < opDefNodes.length; j++)
-        {
-            String key = opDefNodes[j].getName().toString();
-            nodeTable.put(key, opDefNodes[j]);
-        }
-
-        for (int i = 0; i < overrides.size(); i++)
-        {
-            id = getValidIdentifier(labelingScheme);
-            // formulas
-            // to .cfg : <id>
-            // to _MC.tla : <id> == <expression>
-            formula = overrides.get(i);
-
-            OpDefNode defNode = nodeTable.get(formula.getLabel());
-
-            if (defNode == null)
-            {
-                // should raise an error
-                content = null;
-            } else
-            {
-                OpDefNode source = defNode.getSource();
-                if (source == defNode)
-                {
-                    // user is overriding a definition in the root module
-                    if (formula.isModelValue() && !formula.isSetOfModelValues())
-                    {
-                        // model value
-                        content = new String[] { formula.getLabel() + EQ + formula.getLabel(), EMPTY_STRING };
-                    } else
-                    {
-                        // not a model value
-                        content = new String[] { formula.getLabel() + ARROW + id,
-                                formula.getParametrizedLabel(id) + DEFINES_CR + formula.getRight() };
-                    }
-                } else if (source.getSource() == source)
-                {
-                    // user is overriding a definition that is not in the root module
-                    if (formula.isModelValue() && !formula.isSetOfModelValues())
-                    {
-                        // model value
-                        content = new String[] {
-                                source.getName().toString() + ARROW + "["
-                                        + source.getOriginallyDefinedInModuleNode().getName().toString() + "]" + id
-                                        + " " + id + EQ + source.getName().toString(), "CONSTANT " + id };
-                    } else
-                    {
-                        // not a model value
-                        content = new String[] {
-                                source.getName().toString() + ARROW + "["
-                                        + source.getOriginallyDefinedInModuleNode().getName().toString() + "]" + id,
-                                formula.getParametrizedLabel(id) + DEFINES_CR + formula.getRight() };
-                    }
-                } else
-                {
-                    // should raise an error window
-                    content = null;
-                }
-            }
-
-            resultContent.add(content);
-        }
-        return resultContent;
-    }
-
-    /**
-     * Converts formula list to a string representation
-     * @param formulaList list of assignments
-     * @param labelingScheme 
-     * @return
-     */
-    public static List<String[]> createListContent(List<Formula> formulaList, String labelingScheme)
-    {
-        Vector<String[]> resultContent = new Vector<String[]>(formulaList.size());
-        String[] content;
-        String label;
-        for (int i = 0; i < formulaList.size(); i++)
-        {
-            label = getValidIdentifier(labelingScheme);
-            // formulas
-            // to .cfg : <id>
-            // to _MC.tla : <id> == <expression>
-            content = new String[] { label, label + DEFINES_CR + formulaList.get(i).getFormula(), String.valueOf(i) };
-            resultContent.add(content);
-        }
-        return resultContent;
-    }
-
-    /**
-     * A pattern to match IDs generated by the {@link ModelWriter#getValidIdentifier(String)} method
-     */
-    public static final Pattern ID_MATCHER = Pattern.compile("(" + SPEC_SCHEME + "|" + INIT_SCHEME + "|" + NEXT_SCHEME
-            + "|" + CONSTANT_SCHEME + "|" + SYMMETRY_SCHEME + "|" + DEFOV_SCHEME + "|" + CONSTRAINT_SCHEME + "|"
-            + ACTIONCONSTRAINT_SCHEME + "|" + INVARIANT_SCHEME + "|" + PROP_SCHEME + ")_[0-9]{17,}");
-
-    /**
-     * Find the IDs in the given text and return the array of 
-     * regions pointing to those or an empty array, if no IDs were found.
-     * An ID is scheme_timestamp, created by {@link ModelWriter#getValidIdentifier(String)} e.G. next_125195338522638000
-     * @param text text containing IDs (error text)
-     * @return array of regions or empty array
-     */
-    public static IRegion[] findIds(String text)
-    {
-        if (text == null || text.length() == 0)
-        {
-            return new IRegion[0];
-        }
-
-        Matcher matcher = ModelWriter.ID_MATCHER.matcher(text);
-        Vector<Region> regions = new Vector<Region>();
-        while (matcher.find())
-        {
-            regions.add(new Region(matcher.start(), matcher.end() - matcher.start()));
-        }
-        return regions.toArray(new IRegion[regions.size()]);
-    }
-
-    /**
-     * Retrieves new valid (not used) identifier from given schema
-     * @param schema a naming schema, one of the {@link ModelWriter} SCHEMA constants
-     * @return a valid identifier
-     */
-	public static String getValidIdentifier(String schema) {
-		return String.format("%s_%s%s", schema, System.currentTimeMillis(), 1000 * COUNTER.incrementAndGet());
-	}
 }
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TLCSpec.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TLCSpec.java
index c31dfd75bfc97370a7f930e869d2772fbd615e95..c2b20504d7c452da32575f5c542324cd04b58123 100644
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TLCSpec.java
+++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TLCSpec.java
@@ -27,8 +27,11 @@
 package org.lamport.tla.toolbox.tool.tlc.model;
 
 import java.util.Collection;
+import java.util.Enumeration;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.regex.Pattern;
 
 import org.eclipse.core.runtime.CoreException;
@@ -37,10 +40,13 @@ import org.eclipse.debug.core.DebugPlugin;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.ILaunchConfigurationType;
 import org.eclipse.debug.core.ILaunchManager;
+import org.lamport.tla.toolbox.spec.Module;
 import org.lamport.tla.toolbox.spec.Spec;
 import org.lamport.tla.toolbox.tool.tlc.launch.TLCModelLaunchDelegate;
 
+import tla2sany.modanalyzer.ParseUnit;
 import tla2sany.modanalyzer.SpecObj;
+import util.TLAConstants;
 
 /**
  * {@link TLCSpec} is the glue between {@link Spec} and {@link Model}. Why do we
@@ -146,7 +152,7 @@ public class TLCSpec extends Spec {
 		
 	private String getModelNameSuggestion(String proposition) {
 		Model model = getModel(proposition);
-		if (model != null || getProject().getFile(proposition + ".tla").exists()) {
+		if (model != null || getProject().getFile(proposition + TLAConstants.Files.TLA_EXTENSION).exists()) {
 			String oldNumber = proposition.substring(proposition.lastIndexOf("_") + 1);
 			int number = Integer.parseInt(oldNumber) + 1;
 			proposition = proposition.substring(0, proposition.lastIndexOf("_") + 1);
@@ -177,4 +183,14 @@ public class TLCSpec extends Spec {
 		}
 		return modelName + "_Copy";
 	}
+	
+	public Set<Module> getModulesSANY() {
+		final Set<Module> s = new HashSet<>();
+        Enumeration<String> enumerate = spec.getRootModule().parseUnitContext.keys();
+        while (enumerate.hasMoreElements()) {
+            ParseUnit parseUnit = (ParseUnit) spec.getRootModule().parseUnitContext.get(enumerate.nextElement());
+            s.add(new Module(parseUnit));
+        }
+        return s;
+	}
 }
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TraceExpressionModelWriter.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TraceExpressionModelWriter.java
index 2b8a78055c2930f8f19427f7aff4a80456f03709..e43cb373edf2268146a668b954f47b2bd59c1e0a 100644
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TraceExpressionModelWriter.java
+++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TraceExpressionModelWriter.java
@@ -25,941 +25,57 @@
  ******************************************************************************/
 package org.lamport.tla.toolbox.tool.tlc.model;
 
-import java.util.Iterator;
-import java.util.List;
-import java.util.Vector;
-
-import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants;
-import org.lamport.tla.toolbox.tool.tlc.launch.TraceExpressionInformationHolder;
-import org.lamport.tla.toolbox.tool.tlc.traceexplorer.SimpleTLCState;
-import org.lamport.tla.toolbox.tool.tlc.traceexplorer.SimpleTLCVariable;
+import java.io.IOException;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.PlatformUI;
 import org.lamport.tla.toolbox.util.ResourceHelper;
 
-public class TraceExpressionModelWriter extends ModelWriter {
-
-	public static final String POSITION = "_TEPosition";
-	public static final String TRACE = "_TETrace";
-	
-	/**
-	 * This only changes the tla file. This method generates and adds a variable declaration
-	 * for each expression in the list. It also creates an identifier for each
-	 * expression and defines the identifier to be that expression.
-	 * It returns an array of {@link TraceExpressionInformationHolder} where each element
-	 * contains the expression, the identifier, and the variable name.
-	 * 
-	 * If the expressions are x' + y and x > 3, The tla file will contain something like
-	 * 
-	 *\* comment line
-	 * VARIABLES __trace_var_21034978347834, __trace_var_90234782309
-	 * 
-	 * \* comment line
-	 * trace_def_3214234234234 ==
-	 * x' + y
-	 * ----
-	 * 
-	 * \* comment line
-	 * trace_def_2342342342342 ==
-	 * x > 3
-	 * ----
-	 * 
-	 * @param expressions a list of formulas, each one an expression the user wants to have evaluated
-	 * at each state of the trace
-	 * @return array of {@link TraceExpressionInformationHolder} where each element
-	 * contains the expression, the identifier, and the variable name
-	 */
-	public TraceExpressionInformationHolder[] createAndAddVariablesAndDefinitions(List<Formula> expressions, String attributeName) {
-	
-	    TraceExpressionInformationHolder[] expressionData = new TraceExpressionInformationHolder[expressions.size()];
-	    Iterator<Formula> it = expressions.iterator();
-	    int position = 0;
-	    while (it.hasNext())
-	    {
-	        final Formula formula = it.next();
-			final String expression = formula.getFormula();
-	
-	        if (expression != null && expression.length() > 0)
-	        {
-	        	final String identifier = getValidIdentifier(TRACE_EXPR_DEF_SCHEME);
-	        	if (formula.isNamed()) {
-	        		final String varname = formula.getLeftHandSide();
-	        		String rightHandSide = formula.getRightHandSide();
-					expressionData[position] = new TraceExpressionInformationHolder(rightHandSide, identifier, varname);
-	        	} else  {
-	        		final String varname = getValidIdentifier(TRACE_EXPR_VAR_SCHEME);
-	        		expressionData[position] = new TraceExpressionInformationHolder(expression, identifier, varname);
-	        	}
-	        }
-	
-	        position++;
-	    }
-	
-	    addVariablesAndDefinitions(expressionData, attributeName, true);
-	
-	    return expressionData;
-	}
-	
-	public void addPrimer(final String moduleFilename, final String extendedModuleName) {
-		// A TE spec has to extend Integers because of the _TEPosition operator.
-		tlaBuffer.append(ResourceHelper.getExtendingModuleContent(moduleFilename,
-				new String[] { extendedModuleName, "TLC", "Integers" }));
-	}
-
-	public void addTraceFunction(final List<SimpleTLCState> input) {
-		// Filter stuttering or back2state instances from trace.
-		final List<SimpleTLCState> trace = input.stream()
-				.filter(state -> !state.isBackToState() && !state.isStuttering())
-				.collect(java.util.stream.Collectors.toList());
-		
-		if (trace.isEmpty()) {
-			return;
-	    }
-		
-		final StringBuffer traceFunctionDef = new StringBuffer();
-//		traceFunctionDef.append("---- MODULE __TEInner ----");
-//		traceFunctionDef.append(CR).append(CR);
-
-		// Trace
-		traceFunctionDef.append(COMMENT).append("TRACE EXPLORER identifier definition ").append(ATTRIBUTE)
-				.append("_TETrace").append(CR);
-		traceFunctionDef.append("_TETrace").append(DEFINES_CR);
-		traceFunctionDef.append(BEGIN_TUPLE).append(CR);
-		for (int j = 0; j < trace.size(); j++) {
-			final SimpleTLCState state = trace.get(j);
-
-			traceFunctionDef.append(L_PAREN).append(state.asFunction()).append(R_PAREN);
-
-			if (j < trace.size() - 1) {
-				traceFunctionDef.append(COMMA).append(CR);
-			}
-		}
-		traceFunctionDef.append(CR).append(END_TUPLE);
-		traceFunctionDef.append(CR);
-		traceFunctionDef.append(SEP).append(CR).append(CR);
-
-        // Position
-		traceFunctionDef.append(COMMENT).append("TRACE EXPLORER Position identifier definition ").append(ATTRIBUTE)
-				.append(POSITION).append(CR);
-		traceFunctionDef.append(POSITION).append(DEFINES_CR);
-		traceFunctionDef.append(
-				String.format("IF TLCGet(\"level\") >= %s THEN %s ELSE TLCGet(\"level\") + 1", trace.size(), trace.size()));
-		traceFunctionDef.append(CR);
-		traceFunctionDef.append(SEP).append(CR).append(CR);
-//		
-//		// INSTANCE
-//		traceFunctionDef.append("====").append(CR);
-//     	traceFunctionDef.append("LOCAL TE == INSTANCE __TEInner").append(CR).append(CR);
-
-        // append the expression definitions
-        tlaBuffer.append(traceFunctionDef.toString());
-	}
-
-	/**
-	 * This only changes the tla file. This method adds a variable declaration
-	 * for each element of traceExpressionData and, if the flag addDefinitions is true,
-	 * defines the identifier of each element to be the expression for that element.
-	 * 
-	 * If the expressions are x' + y and x > 3, The tla file will contain something like
-	 * 
-	 *\* comment line
-	 * VARIABLES __trace_var_21034978347834, __trace_var_90234782309
-	 * 
-	 * \* comment line
-	 * trace_def_3214234234234 ==
-	 * x' + y
-	 * ----
-	 * 
-	 * \* comment line
-	 * trace_def_2342342342342 ==
-	 * x > 3
-	 * ----
-	 * 
-	 * @param traceExpressionData information about the trace expressions
-	 * @param attributeName
-	 * @param addDefinitions whether or not to define each identifier as the expression
-	 */
-	public void addVariablesAndDefinitions(TraceExpressionInformationHolder[] traceExpressionData, String attributeName, boolean addDefinitions) {
-	    if (traceExpressionData.length == 0)
-	    {
-	        return;
-	    }
-	
-	    StringBuffer variableDecls = new StringBuffer();
-	    StringBuffer definitions = new StringBuffer();
-	
-	    for (int i = 0; i < traceExpressionData.length; i++)
-	    {
-	        TraceExpressionInformationHolder expressionInfo = traceExpressionData[i];
-	
-	        variableDecls.append(expressionInfo.getVariableName());
-	        // we add a comma after every variable except for the last
-	        if (i != traceExpressionData.length - 1)
-	        {
-	            variableDecls.append(COMMA);
-	        }
-	
-	        if (addDefinitions)
-	        {
-	            // define the identifier corresponding to this expression - looks like:
-	            // \* comment line
-	            // trace_def_213123123123 ==
-	            // expression
-	            // ----
-	            definitions.append(COMMENT).append("TRACE EXPLORER identifier definition ").append(ATTRIBUTE).append(
-	                    attributeName).append(INDEX).append(i).append(CR);
-	            definitions.append(expressionInfo.getIdentifier()).append(DEFINES_CR).append(
-	                    expressionInfo.getExpression()).append(CR);
-	            definitions.append(SEP).append(CR).append(CR);
-	        }
-	    }
-	
-	    // variable declaration
-	    tlaBuffer.append(COMMENT).append("TRACE EXPLORER variable declaration ").append(ATTRIBUTE)
-	            .append(attributeName).append(CR);
-	    tlaBuffer.append("VARIABLES ").append(variableDecls.toString()).append(CR);
-	
-	    tlaBuffer.append(SEP).append(CR).append(CR);
-	
-	    if (addDefinitions)
-	    {
-	        // append the expression definitions
-	        tlaBuffer.append(definitions.toString());
-	    }
-	}
-
-	/**
-	 * This will generate two identifiers equal to the initial and next state
-	 * predicate for the trace. If expressionData is not null, it should contain information
-	 * about trace explorer expressions. This information is used to appropriately put
-	 * the variables representing trace explorer expressions in the trace. In the following example, trace
-	 * explorer expressions are used, but if expressionData is null, those variables will not appear in the
-	 * init and next definitions, but everything else will be the same.
-	 * 
-	 * Note: In the following example, the expressions expr1,...,expr6, texpr1, texpr2 can take up multiple
-	 * lines.
-	 * 
-	 * Consider the following trace:
-	 * 
-	 * <Initial predicate> <State num 1>
-	 * var1=expr1
-	 * var2=expr2
-	 * 
-	 * <Action...> <State num 2>
-	 * var1=expr3
-	 * var2=expr4
-	 * 
-	 * <Action...> <State num 3>
-	 * var1=expr5
-	 * var2=expr6
-	 * 
-	 * The user has defined two expressions in the trace explorer:
-	 * 
-	 * texpr1 (level 2 represented by var3)
-	 * texpr2 (level 1 represented by var4)
-	 * 
-	 * This method defines the following identifiers:
-	 * 
-	 * init_4123123123 ==
-	 * var1=(
-	 * expr1
-	 * )/\
-	 * var2=(
-	 * expr2
-	 * )/\
-	 * var3=(
-	 * "--"
-	 * )/\
-	 * var4=(
-	 * texpr2
-	 * )
-	 * 
-	 * next_12312312312 ==
-	 * (var1=(
-	 * expr1
-	 * )/\
-	 * var2=(
-	 * expr2
-	 * )/\
-	 * var1'=(
-	 * expr3
-	 * )/\
-	 * var2'=(
-	 * expr4
-	 * )/\
-	 * var3'=(
-	 * texpr1
-	 * )/\
-	 * var4'=(
-	 * texpr2
-	 * )')
-	 * \/
-	 * (var1=(
-	 * expr3
-	 * )/\
-	 * var2=(
-	 * expr4
-	 * )/\
-	 * var1'=(
-	 * expr5
-	 * )/\
-	 * var2'=(
-	 * expr6
-	 * )/\
-	 * var3'=(
-	 * texpr1
-	 * )/\
-	 * var4'=(
-	 * texpr2
-	 * )')
-	 * 
-	 * If the last state is back to state i, then this method treats
-	 * the trace as if it has the state labeled "Back to state i" removed and
-	 * replaced with a copy of state i.
-	 * 
-	 * If the last state is stuttering, then this method treats the trace as if it
-	 * has the state labeled "Stuttering" removed and replaced with a copy
-	 * of the state before the state labeled "Stuttering".
-	 * 
-	 * @param trace
-	 * @param expressionData data on trace explorer expressions, can be null
-	 * @return String[], first element is the identifier for the initial state predicate,
-	 * second element is the identifier for the next-state action
-	 */
-	public String[] addInitNext(List<SimpleTLCState> trace, TraceExpressionInformationHolder[] expressionData) {
-	    String initId = getValidIdentifier(INIT_SCHEME);
-	    String nextId = getValidIdentifier(NEXT_SCHEME);
-	
-	    addInitNext(trace, expressionData, initId, nextId);
-	
-	    return new String[] { initId, nextId };
-	}
-
-	/**
-	 * This will set initId equal to the initial state predicate and nextId equal to the next state
-	 * action for the trace. If expressionData is not null, it should contain information
-	 * about trace explorer expressions. This information is used to appropriately put
-	 * the variables representing trace explorer expressions in the trace. In the following example, trace
-	 * explorer expressions are used, but if expressionData is null, those variables will not appear in the
-	 * init and next definitions, but everything else will be the same.
-	 * 
-	 * Note: In the following example, the expressions expr1,...,expr6, texpr1, texpr2 can take up multiple
-	 * lines.
-	 * 
-	 * Consider the following trace:
-	 * 
-	 * <Initial predicate> <State num 1>
-	 * var1=expr1
-	 * var2=expr2
-	 * 
-	 * <Action...> <State num 2>
-	 * var1=expr3
-	 * var2=expr4
-	 * 
-	 * <Action...> <State num 3>
-	 * var1=expr5
-	 * var2=expr6
-	 * 
-	 * The user has defined two expressions in the trace explorer:
-	 * 
-	 * texpr1 (level 2 represented by var3)
-	 * texpr2 (level 1 represented by var4)
-	 * 
-	 * This method defines the following identifiers:
-	 * 
-	 * init_4123123123 ==
-	 * var1=(
-	 * expr1
-	 * )/\
-	 * var2=(
-	 * expr2
-	 * )/\
-	 * var3=(
-	 * "--"
-	 * )/\
-	 * var4=(
-	 * texpr2
-	 * )
-	 * 
-	 * next_12312312312 ==
-	 * (var1=(
-	 * expr1
-	 * )/\
-	 * var2=(
-	 * expr2
-	 * )/\
-	 * var1'=(
-	 * expr3
-	 * )/\
-	 * var2'=(
-	 * expr4
-	 * )/\
-	 * var3'=(
-	 * texpr1
-	 * )/\
-	 * var4'=(
-	 * texpr2
-	 * )')
-	 * \/
-	 * (var1=(
-	 * expr3
-	 * )/\
-	 * var2=(
-	 * expr4
-	 * )/\
-	 * var1'=(
-	 * expr5
-	 * )/\
-	 * var2'=(
-	 * expr6
-	 * )/\
-	 * var3'=(
-	 * texpr1
-	 * )/\
-	 * var4'=(
-	 * texpr2
-	 * )')
-	 * 
-	 * If the last state is back to state i, then this method treats
-	 * the trace as if it has the state labeled "Back to state i" removed and
-	 * replaced with a copy of state i.
-	 * 
-	 * If the last state is stuttering, then this method treats the trace as if it
-	 * has the state labeled "Stuttering" removed and replaced with a copy
-	 * of the state before the state labeled "Stuttering".
-	 * 
-	 * @param trace
-	 * @param expressionData data on trace explorer expressions, can be null
-	 * @param initId the identifier to be used for the initial state predicate, cannot be null
-	 * @param nextId the identifier to be used for the next-state action, cannot be null
-	 */
-	public void addInitNext(List<SimpleTLCState> trace, TraceExpressionInformationHolder[] expressionData, String initId, String nextId) {
-	
-	    if (trace.size() > 0)
-	    {
-	        Iterator<SimpleTLCState> it = trace.iterator();
-	        SimpleTLCState currentState = it.next();
-	
-	        /*******************************************************
-	         * Add the init definition.                            *
-	         *******************************************************/
-	        cfgBuffer.append(COMMENT).append("INIT definition").append(CR);
-	        cfgBuffer.append("INIT").append(CR);
-	        cfgBuffer.append(initId).append(CR);
-	
-	        tlaBuffer.append(COMMENT).append("TRACE INIT definition").append(
-	                IModelConfigurationConstants.TRACE_EXPLORE_INIT).append(CR);
-	        tlaBuffer.append(initId).append(DEFINES_CR);
-	        SimpleTLCVariable[] vars = currentState.getVars();
-	
-	        // variables from spec
-	        for (int i = 0; i < vars.length; i++)
-	        {
-	            SimpleTLCVariable var = vars[i];
-	            /*
-	             * var=(
-	             * expr
-	             * )
-	             */
-	            tlaBuffer.append(var.getVarName()).append(EQ).append(L_PAREN).append(CR).append(var.getValueAsString())
-	                    .append(CR).append(R_PAREN);
-	            /*
-	             * Add /\ after right parenthesis except for the last variable
-	             * 
-	             * var=(
-	             * expr
-	             * )/\
-	             */
-	            if (i != vars.length - 1)
-	            {
-	                tlaBuffer.append(TLA_AND).append(CR);
-	            }
-	        }
-	
-	        // variables representing trace explorer expressions
-	        if (expressionData != null)
-	        {
-	            for (int i = 0; i < expressionData.length; i++)
-	            {
-	                TraceExpressionInformationHolder expressionInfo = expressionData[i];
-	                tlaBuffer.append(TLA_AND).append(CR).append(expressionInfo.getVariableName()).append(EQ).append(
-	                        L_PAREN).append(CR);
-	
-	                if (expressionInfo.getLevel() == 2)
-	                {
-	                    // add "--" if the expression is temporal level
-	                    tlaBuffer.append(TRACE_NA);
-	                } else
-	                {
-	                    // add the actual expression if it is not temporal level
-	                    tlaBuffer.append(expressionInfo.getExpression());
-	                }
-	
-	                tlaBuffer.append(CR).append(R_PAREN);
-	            }
-	        }
-	
-	        tlaBuffer.append(CR).append(SEP).append(CR).append(CR);
-	
-	        /**********************************************************
-	         *  Now add the next state actions definition             *
-	         **********************************************************/
-	        cfgBuffer.append(COMMENT).append("NEXT definition").append(CR);
-	        cfgBuffer.append("NEXT").append(CR);
-	        cfgBuffer.append(nextId).append(CR);
-	
-	        tlaBuffer.append(COMMENT).append("TRACE NEXT definition").append(
-	                IModelConfigurationConstants.TRACE_EXPLORE_NEXT).append(CR);
-	        tlaBuffer.append(nextId).append(DEFINES_CR);
-	
-	        SimpleTLCState nextState = null;
-	        boolean isSingleState;
-	        if (it.hasNext())
-	        {
-	            nextState = (SimpleTLCState) it.next();
-	            isSingleState = false;
-	        } else
-	        {
-	            nextState = currentState;
-	            isSingleState = true;
-	        }
-	
-	        while (nextState != null)
-	        {
-	            /*
-	             * Handle Back to state and stuttering.
-	             * 
-	             * nextState is assigned to the state which the "Back to state"
-	             * or "Stuttering" state represents. If nextState is "Back to state i",
-	             * then it is assigned to state i. If nextState is "Stuttering", then
-	             * it is assigned to the current state.
-	             */
-	            if (nextState.isBackToState())
-	            {
-	                nextState = (SimpleTLCState) trace.get(nextState.getStateNumber() - 1);
-	            } else if (nextState.isStuttering())
-	            {
-	                nextState = currentState;
-	            }
-	
-	            /*
-	             * Write the action:
-	             * 
-	             * (var1=(
-	             * expr1
-	             * )/\
-	             * var2=(
-	             * expr2
-	             * )/\
-	             * var1'=(
-	             * expr3
-	             * )/\
-	             * var2'=(
-	             * expr4
-	             * ))
-	             */
-	            tlaBuffer.append(L_PAREN);
-	
-	            SimpleTLCVariable[] currentStateVars = currentState.getVars();
-	            SimpleTLCVariable[] nextStateVars = nextState.getVars();
-	
-	            /*
-	             * Iterate through current state variables. This adds:
-	             * 
-	             * var1=(
-	             * expr1
-	             * )/\
-	             * var2=(
-	             * expr2
-	             * )/\
-	             * 
-	             */
-	            for (int i = 0; i < currentStateVars.length; i++)
-	            {
-	                SimpleTLCVariable currentStateVar = currentStateVars[i];
-	                tlaBuffer.append(currentStateVar.getVarName()).append(EQ).append(L_PAREN).append(CR).append(
-	                        currentStateVar.getValueAsString()).append(CR).append(R_PAREN).append(TLA_AND).append(CR);
-	            }
-	
-	            /*
-	             * If the trace is a single state, make the next state
-	             * action never enabled. The model will deadlock in the initial state.
-	             * This adds:
-	             * 
-	             * FALSE
-	             * /\
-	             */
-	            if (isSingleState)
-	            {
-	                tlaBuffer.append("FALSE").append(CR).append(TLA_AND).append(CR);
-	            }
-	
-	            /*
-	             * Iterate through next state variables. This adds:
-	             * 
-	             * var1'=(
-	             * expr3
-	             * )/\
-	             * var2'=(
-	             * expr4
-	             * )
-	             */
-	            for (int i = 0; i < currentStateVars.length; i++)
-	            {
-	                SimpleTLCVariable nextStateVar = nextStateVars[i];
-	                tlaBuffer.append(nextStateVar.getVarName()).append(PRIME).append(EQ).append(L_PAREN).append(CR)
-	                        .append(nextStateVar.getValueAsString()).append(CR).append(R_PAREN);
-	                // add /\ for each variable except the last one
-	                if (i != currentStateVars.length - 1)
-	                {
-	                    tlaBuffer.append(TLA_AND).append(CR);
-	                }
-	            }
-	
-	            /*
-	             * Iterate through the trace explorer expressions if there are any. This adds:
-	             * 
-	             *  /\
-	             * var3'=(
-	             * texpr1
-	             * )/\
-	             * var4'=(
-	             * texpr2
-	             * )'
-	             * 
-	             */
-	            if (expressionData != null)
-	            {
-	                for (int i = 0; i < expressionData.length; i++)
-	                {
-	                    TraceExpressionInformationHolder expressionInfo = expressionData[i];
-	                    tlaBuffer.append(TLA_AND).append(CR).append(expressionInfo.getVariableName()).append(PRIME)
-	                            .append(EQ).append(L_PAREN).append(CR).append(expressionInfo.getExpression())
-	                            .append(CR).append(R_PAREN);
-	
-	                    if (expressionInfo.getLevel() < 2)
-	                    {
-	                        tlaBuffer.append(PRIME);
-	                    }
-	                }
-	            }
-	
-	            tlaBuffer.append(R_PAREN);
-	
-	            if (it.hasNext())
-	            {
-	                tlaBuffer.append(CR).append(TLA_OR).append(CR);
-	            }
-	
-	            currentState = nextState;
-	
-	            if (it.hasNext())
-	            {
-	                nextState = (SimpleTLCState) it.next();
-	            } else
-	            {
-	                nextState = null;
-	            }
-	        }
-	
-	        tlaBuffer.append(CR).append(SEP).append(CR).append(CR);
-	
-	    }
-	
-	}
-
-	/**
-	 * Adds the invariant ~(P) where P is the formula describing finalState. The format
-	 * in the tla file is as follows:
-	 * 
-	 * inv_12312321321 ==
-	 * ~(
-	 * P
-	 * )
-	 * ----
-	 * 
-	 * @param finalState
-	 */
-	public void addInvariant(SimpleTLCState finalState) {
-	    String id = getValidIdentifier(INVARIANT_SCHEME);
-	    cfgBuffer.append(COMMENT).append("INVARIANT definition").append(CR);
-	    cfgBuffer.append("INVARIANT").append(CR);
-	    cfgBuffer.append(id).append(CR);
-	
-	    tlaBuffer.append(COMMENT).append("INVARIANT definition").append(CR);
-	    tlaBuffer.append(id).append(DEFINES_CR);
-	    tlaBuffer.append(TLA_NOT).append(L_PAREN).append(CR).append(getStateConjunction(finalState)).append(CR).append(
-	            R_PAREN).append(CR);
-	
-	    tlaBuffer.append(SEP).append(CR).append(CR);
-	}
-
-	/**
-	 * Adds the temporal property ~<>[](P) where P is the formula describing finalState.
-	 * The format in the tla file is as follows:
-	 * 
-	 * prop_23112321 ==
-	 * ~<>[](
-	 * P
-	 * )
-	 * ----
-	 * 
-	 * @param finalState
-	 */
-	public void addStutteringProperty(SimpleTLCState finalState) {
-	    String id = getValidIdentifier(PROP_SCHEME);
-	    cfgBuffer.append(COMMENT).append("PROPERTY definition").append(CR);
-	    cfgBuffer.append("PROPERTY").append(CR);
-	    cfgBuffer.append(id).append(CR);
-	
-	    tlaBuffer.append(COMMENT).append("PROPERTY definition").append(CR);
-	    tlaBuffer.append(id).append(DEFINES_CR);
-	    tlaBuffer.append(TLA_NOT).append(TLA_EVENTUALLY_ALWAYS).append(L_PAREN).append(CR).append(
-	            getStateConjunction(finalState)).append(CR).append(R_PAREN).append(CR);
-	
-	    tlaBuffer.append(SEP).append(CR).append(CR);
-	}
-
-	/**
-	 * Adds the temporal property ~([]<>P /\ []<>Q), where P is the formula describing finalState and 
-	 * Q the formula describing backToState. The formating in the tla file is as follows:
-	 * 
-	 * prop_21321312 ==
-	 * ~(([]<>(
-	 * P
-	 * ))/\([]<>(
-	 * Q
-	 * )))
-	 * ----
-	 * 
-	 * @param finalState
-	 * @param backToState
-	 */
-	public void addBackToStateProperty(SimpleTLCState finalState, SimpleTLCState backToState) {
-	    String id = getValidIdentifier(PROP_SCHEME);
-	    cfgBuffer.append(COMMENT).append("PROPERTY definition").append(CR);
-	    cfgBuffer.append("PROPERTY").append(CR);
-	    cfgBuffer.append(id).append(CR);
-	
-	    tlaBuffer.append(COMMENT).append("PROPERTY definition").append(CR);
-	    tlaBuffer.append(id).append(DEFINES_CR);
-	    tlaBuffer.append(TLA_NOT).append(L_PAREN).append(L_PAREN).append(TLA_INF_OFTEN).append(L_PAREN).append(CR)
-	            .append(getStateConjunction(finalState)).append(CR).append(R_PAREN).append(R_PAREN).append(TLA_AND)
-	            .append(L_PAREN).append(TLA_INF_OFTEN).append(L_PAREN).append(CR).append(
-	                    getStateConjunction(backToState)).append(CR).append(R_PAREN).append(R_PAREN).append(R_PAREN)
-	            .append(CR);
-	
-	    tlaBuffer.append(SEP).append(CR).append(CR);
-	}
-
-	/**
-	 * Writes comments that will be used for associating variable names with expressions
-	 * and will give the level of each expression. In particular, for each expression "expr"
-	 * with level x and variable name ___trace_var_3242348934343 this
-	 * will append the following comment to the tla file:
-	 * 
-	 * \* :x:___trace_var_3242348934343:expr"$!@$!@$!@$!@$!"
-	 * 
-	 * @param traceExpressionData
-	 */
-	public void addInfoComments(TraceExpressionInformationHolder[] traceExpressionData) {
-	    for (int i = 0; i < traceExpressionData.length; i++)
-	    {
-	        TraceExpressionInformationHolder expressionData = traceExpressionData[i];
-	        tlaBuffer.append(COMMENT).append(INDEX).append(expressionData.getLevel()).append(INDEX).append(
-	                expressionData.getVariableName()).append(INDEX).append(expressionData.getExpression()).append(
-	                CONSTANT_EXPRESSION_EVAL_IDENTIFIER).append(CR);
-	    }
-	}
+import tlc2.output.SpecTraceExpressionWriter;
 
+public class TraceExpressionModelWriter extends SpecTraceExpressionWriter {
     /**
-     * Returns a string representing the formula describing the state.
-     * If the state has var1=expr1, var2 = expr2, and var3=expr3, then this returns:
-     * 
-     * var1=(
-     * expr1
-     * )/\
-     * var2=(
-     * expr2
-     * )/\
-     * var3=(
-     * expr3
-     * )
-     * 
-     * 
-     * The expressions expr1, expr2, and expr3 can take up multiple lines.
-     * 
-     * This will return null if the state is stuttering or back to state.
-     * 
-     * @param state
-     * @return
+     * {@inheritDoc}
      */
-    private static String getStateConjunction(SimpleTLCState state)
-    {
-        if (state.isBackToState())
-        {
-            return null;
-        } else if (state.isStuttering())
-        {
-            return null;
-        } else
-        {
-            StringBuffer formula = new StringBuffer();
-            SimpleTLCVariable[] vars = state.getVars();
-            for (int i = 0; i < vars.length; i++)
-            {
-                SimpleTLCVariable var = vars[i];
-                formula.append(var.getVarName()).append(EQ).append(L_PAREN).append(CR).append(var.getValueAsString())
-                        .append(CR).append(R_PAREN);
-
-                // append /\ except for the last variable
-                if (i != vars.length - 1)
-                {
-                    formula.append(TLA_AND).append(CR);
-                }
-            }
-
-            return formula.toString();
-        }
+	@Override
+    protected String getTLAModuleClosingTag() {
+        final StringBuilder sb = ResourceHelper.getModuleClosingTag();
+    	
+    	return sb.toString();
     }
-
+	
     /**
-    * This adds the trace explorer variables to initWithoutTraceVars.
-    * The method returns a list with one element, a
-    * String[]. The first element of the array is put in TE.cfg, and the
-    * second element is put in TE.tla. The intention is to use
-    * the return value as the first argument of {@link ModelWriter#addFormulaList(List, String, String)}.
-    * 
-    * This can be best explained with an example.
-    * 
-    * The trace is the following:
-    
-    STATE 1: <Initial predicate>
-    /\ x = 0
-    /\ y = 0
-
-    STATE 2: <Action line 8, col 3 to line 9, col 15 of module Test>
-    /\ x = 1
-    /\ y = 0
-
-    STATE 3: <Action line 8, col 3 to line 9, col 15 of module Test>
-    /\ x = 2
-    /\ y = 1
-
-    STATE 4: <Action line 8, col 3 to line 9, col 15 of module Test>
-    /\ x = 3
-    /\ y = 3
-
-    The user wants to evaluate two expressions:
-
-    x + y
-    x' > y
-
-    The file TE.tla will define two new variables:
-
-    VARIABLES sum, big
-
-    The variables are named "sum" and "big" for the simplicity of this example. In
-    reality they will be something like "trace_2348902347238", unless the user is
-    responsible to assigning labels to the expressions. The file will also define
-    two new identifiers:
-
-    sum_def == x + y
-    big_def == x' >y
-
-    We define the initial predicate and next-state relation as follows:
-
-    TInit ==
-    /\ x = 0 
-    /\ y = 0
-    /\ sum = sum_def
-    /\ big = "--"
-
-    TNext ==
-    \/ /\ x = 0
-    /\ y = 0
-    /\ x' = 1
-    /\ y' = 0
-    /\ sum' = sum_def'
-    /\ big' = big_def
-
-    \/ /\ x = 1
-    /\ y = 0
-    /\ x' = 2
-    /\ y' = 1
-    /\ sum' = sum_def'
-    /\ big' = big_def
-
-    \/ /\ x = 2
-    /\ y = 1
-    /\ x' = 3
-    /\ y' = 3
-    /\ sum' = sum_def'
-    /\ big' = big_def
-
-    The expression defined by big_def has primed variables so the variable big
-    takes the value "--" in the initial state predicate. The expression defined by
-    sum_def does not contain primed variables. This will produce an error trace by
-    defining the invariant:
-
-    ~(x=3/\y=3)
-    
-    * 
-    * @param traceInit
-    * @param nextWithoutTraceVars
-    * @param traceExpressionData
-    * @return
-    */
-    public static List<String[]> createInitContent(String traceInit, TraceExpressionInformationHolder[] traceExpressionData)
-    {
-        String id = getValidIdentifier(INIT_SCHEME);
-        StringBuffer initPredicate = new StringBuffer();
-        initPredicate.append(id).append(DEFINES_CR);
-        initPredicate.append(traceInit);
-        for (int i = 0; i < traceExpressionData.length; i++)
-        {
-            TraceExpressionInformationHolder expressionInfo = traceExpressionData[i];
-            initPredicate.append(TLA_AND).append(expressionInfo.getVariableName()).append(EQ);
-            if (expressionInfo.getLevel() < 2)
-            {
-                initPredicate.append(L_PAREN).append(expressionInfo.getExpression()).append(R_PAREN);
-            } else
-            {
-                initPredicate.append(TRACE_NA);
-            }
-        }
-        Vector<String[]> toReturn = new Vector<String[]>();
-        toReturn.add(new String[] { id, initPredicate.toString() });
-        return toReturn;
-    }
-
-    public static List<String[]> createNextContent(List<String> traceNextActions,
-            TraceExpressionInformationHolder[] traceExpressionData)
-    {
-        String id = getValidIdentifier(NEXT_SCHEME);
-        StringBuffer nextActionDisj = new StringBuffer();
-        nextActionDisj.append(id).append(DEFINES_CR);
-        Iterator<String> it = traceNextActions.iterator();
-        while (it.hasNext())
-        {
-            String actionConj = it.next();
-            nextActionDisj.append(TLA_OR).append(L_PAREN).append(actionConj);
-            for (int i = 0; i < traceExpressionData.length; i++)
-            {
-                TraceExpressionInformationHolder expressionInfo = traceExpressionData[i];
-                nextActionDisj.append(TLA_AND).append(expressionInfo.getVariableName()).append(PRIME).append(EQ);
-                if (expressionInfo.getLevel() < 2)
-                {
-                    nextActionDisj.append(L_PAREN).append(expressionInfo.getExpression()).append(R_PAREN).append(PRIME);
-                } else
-                {
-                    nextActionDisj.append(L_PAREN).append(expressionInfo.getExpression()).append(R_PAREN);
-                }
-            }
-            nextActionDisj.append(R_PAREN).append(CR);
-        }
-
-        Vector<String[]> toReturn = new Vector<String[]>();
-        toReturn.add(new String[] { id, nextActionDisj.toString() });
-        return toReturn;
+     * Write the content to files
+     * @param tlaFile
+     * @param cfgFile
+     * @param monitor
+     * @throws CoreException
+     */
+	public void writeFiles(final IFile tlaFile, final IFile cfgFile, final IProgressMonitor monitor) throws CoreException {
+		final ContentWriter cw = (inputStream, forTLAFile) -> {
+			final IFile file = forTLAFile ? tlaFile : cfgFile;
+			
+			if (file.exists()) {
+				try {
+					file.setContents(inputStream, IResource.FORCE, monitor);
+				} catch (final CoreException ce) {
+					throw new IOException("Exception writing file " + ce.getMessage(), ce);
+				}
+			} else {
+				throw new IOException("Expected file " + file.getName() + " has been removed externally.");
+			}
+		};
+		
+		try {
+			super.writeFiles(cw);
+		} catch (final IOException e) {
+			throw new CoreException(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.ERROR,
+									"Exception encountered attempting to write modules for the model checking.", e));
+		}
     }
-
 }
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/SimpleTLCState.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/SimpleTLCState.java
deleted file mode 100644
index 3b0ec75c18e62838baca31f65a1536058d0925cc..0000000000000000000000000000000000000000
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/SimpleTLCState.java
+++ /dev/null
@@ -1,166 +0,0 @@
-package org.lamport.tla.toolbox.tool.tlc.traceexplorer;
-
-import java.util.Vector;
-
-import org.lamport.tla.toolbox.tool.tlc.launch.TraceExplorerDelegate;
-
-/**
- * A class for representing the elements of a TLC state that
- * are necessary for the launch delegate for the trace explorer.
- * Currently, this launch delegate is {@link TraceExplorerDelegate}.
- * 
- * This class contains an array of {@link SimpleTLCVariable}.
- * 
- * @author Daniel Ricketts
- *
- */
-public class SimpleTLCState
-{
-
-    private SimpleTLCVariable[] vars;
-    private boolean isStuttering;
-    private boolean isBackToState;
-    private int stateNumber;
-
-    private static final String COLON = ":";
-    private static final String CR = "\n";
-    private static final String STUTTERING = " Stuttering"; // See tlc2.output.MP
-    private static final String BACK_TO_STATE = " Back to state"; // See tlc2.output.MP
-    private static final String AND = "/\\";
-    private static final String EQ = " = ";
-
-    /**
-     * Constructor.
-     * 
-     * @param vars variables in this state.
-     * @param isStuttering whether this is a stuttering state or not
-     * @param isBackToState whether this is a back to state or not
-     * @param stateNumber number of the state in the trace
-     */
-    public SimpleTLCState(SimpleTLCVariable[] vars, boolean isStuttering, boolean isBackToState, int stateNumber)
-    {
-        this.vars = vars;
-        this.isStuttering = isStuttering;
-        this.isBackToState = isBackToState;
-        this.stateNumber = stateNumber;
-    }
-
-    public SimpleTLCVariable[] getVars()
-    {
-        return vars;
-    }
-
-    public boolean isStuttering()
-    {
-        return isStuttering;
-    }
-
-    public boolean isBackToState()
-    {
-        return isBackToState;
-    }
-
-    public int getStateNumber()
-    {
-        return stateNumber;
-    }
-
-    public static SimpleTLCState parseSimpleTLCState(String stateInputString)
-    {
-        // state number
-        int index = stateInputString.indexOf(COLON);
-        // multi line
-        int index2 = stateInputString.indexOf(CR, index);
-        if (index2 == -1)
-        {
-            index2 = stateInputString.length();
-        }
-
-        int stateNumber = Integer.parseInt(stateInputString.substring(0, index).trim());
-        String label = stateInputString.substring(index + 1, index2);
-        boolean isStuttering = label.indexOf(STUTTERING) == 0;
-        boolean isBackToState = label.indexOf(BACK_TO_STATE) == 0;
-
-        SimpleTLCVariable[] vars = null;
-
-        if (!isBackToState && !isStuttering)
-        {
-            // string from which the variables can be parsed
-            String variableInputString = stateInputString.substring(index2 + 1);
-            vars = parseVariables(variableInputString);
-        }
-
-        return new SimpleTLCState(vars, isStuttering, isBackToState, stateNumber);
-    }
-
-    private static SimpleTLCVariable[] parseVariables(String variableInputString)
-    {
-        String[] lines = variableInputString.split(CR);
-        Vector vars = new Vector();
-        int index;
-
-        // buffer for accumulating the state variable
-        String[] stateVarString = null;
-
-        // iterate line-wise
-        for (int j = 0; j < lines.length; j++)
-        {
-            // find the index of the first /\ in the line
-            index = lines[j].indexOf(AND);
-            // adding the current line to the previous lines
-            if (index != -1)
-            {
-                // there was something in the buffer for the state variable
-                // found an empty line, which means that this is the end of the current state
-                if (stateVarString != null)
-                {
-                    SimpleTLCVariable var = new SimpleTLCVariable(stateVarString[0], stateVarString[1]);
-                    vars.add(var);
-                }
-
-                stateVarString = lines[j].substring(index + AND.length()).split(EQ);
-            } else
-            {
-                // no index
-
-                if (stateVarString != null)
-                {
-                    // either an empty line
-                    stateVarString[1] += CR;
-                    stateVarString[1] += lines[j];
-                } else
-                {
-                    // the state has one variable only
-                    stateVarString = lines[j].split(EQ);
-                }
-            }
-        }
-
-        // write the last one
-        if (stateVarString != null)
-        {
-            SimpleTLCVariable var = new SimpleTLCVariable(stateVarString[0], stateVarString[1]);
-            vars.add(var);
-        }
-
-        return (SimpleTLCVariable[]) vars.toArray(new SimpleTLCVariable[vars.size()]);
-    }
-
-    public String asFunction() {
-    	final StringBuffer buf = new StringBuffer();
-    	buf.append("[");
-    	for (int i = 0; i < vars.length; i++) {
-    		final SimpleTLCVariable var = vars[i];
-    		
-			buf.append(var.getVarName());
-			buf.append(" |-> ");
-			buf.append(var.getValueAsString());
-    		
-			if (i < vars.length - 1) {
-				buf.append(org.lamport.tla.toolbox.tool.tlc.model.ModelWriter.COMMA);
-			}
-		}
-    	buf.append("]");
-    	return buf.toString();
-    }
-}
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/SimpleTLCVariable.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/SimpleTLCVariable.java
deleted file mode 100644
index 95ae43e9aede1fac364389b0d014e2de3ad97c6c..0000000000000000000000000000000000000000
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/SimpleTLCVariable.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.lamport.tla.toolbox.tool.tlc.traceexplorer;
-
-import org.lamport.tla.toolbox.tool.tlc.launch.TraceExplorerDelegate;
-
-/**
- * A class for representing the elements of a TLC variable
- * that are necessary for the launch delegate for the trace explorer.
- * Currently, this launch delegate is {@link TraceExplorerDelegate}.
- * 
- * This class contains the variable name as a string and a string
- * representation of the variable value.
- * 
- * @author Daniel Ricketts
- *
- */
-public class SimpleTLCVariable
-{
-
-    private String varName;
-    private String valueAsString;
-
-    /**
-     * Constructor.
-     * 
-     * @param varName name of the variable
-     * @param valueAsString TLC string representation of the variable value
-     */
-    public SimpleTLCVariable(String varName, String valueAsString)
-    {
-        this.varName = varName;
-        this.valueAsString = valueAsString;
-    }
-
-    public String getVarName()
-    {
-        return varName;
-    }
-
-    public String getValueAsString()
-    {
-        return valueAsString;
-    }
-
-}
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/TLCErrorTraceRegistry.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/TLCErrorTraceRegistry.java
deleted file mode 100644
index 9a45d575a49c593e9748db33489235028bc767a9..0000000000000000000000000000000000000000
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/traceexplorer/TLCErrorTraceRegistry.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package org.lamport.tla.toolbox.tool.tlc.traceexplorer;
-
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
-
-import org.eclipse.debug.core.ILaunchConfiguration;
-
-/**
- * This class should not longer be used.
- * 
- * This class contains TLC error traces for launch
- * configurations. Up to one trace can be stored for each launch configuration.
- * 
- * This class is a singleton. The access method is {@link TLCErrorTraceRegistry#getErrorTraceRegistry()}.
- * Traces are added by calling {@link TLCErrorTraceRegistry#addTLCErrorTrace(ILaunchConfiguration, List)}. Traces
- * are retrieved by calling {@link TLCErrorTraceRegistry#getTrace(ILaunchConfiguration)}.
- * 
- * Traces are lists of {@link SimpleTLCState}. This class is currently used because the storage
- * of traces occurs in a class in the tlc UI plug-in which we cannot directly access from the
- * tlc plug-in. Thus, traces must be added from the UI plug-in to this class using {@link SimpleTLCState}
- * because that class is in this plug-in.
- * 
- * @author Daniel Ricketts
- *
- *@deprecated
- */
-public class TLCErrorTraceRegistry
-{
-
-    // hashtable containing the traces
-    // key is the name of the config file representing
-    // the model for the trace
-    private Hashtable traces;
-    // singleton instance
-    private static TLCErrorTraceRegistry instance;
-
-    /**
-     * Adds a trace to the registry for the launch configuration. Replaces
-     * the previous trace (if there is one) for this config. The trace should
-     * be a List of arrays of {@link SimpleTLCState}. If it is not, it will not be
-     * added.
-     * 
-     * @param config
-     * @param trace
-     */
-    public void addTLCErrorTrace(ILaunchConfiguration config, List trace)
-    {
-
-        Iterator it = trace.iterator();
-        while (it.hasNext())
-        {
-            if (!(it.next() instanceof SimpleTLCState))
-            {
-                // do not add trace if all elements are not SimpleTLCState
-                return;
-            }
-        }
-        // trace is allowed
-        traces.put(config.getName(), trace);
-    }
-
-    /**
-     * Returns a list of {@link SimpleTLCState} representing the error
-     * trace for the config, or null if none is found.
-     * 
-     * @param config
-     * @return
-     */
-    public List getTrace(ILaunchConfiguration config)
-    {
-        return (List) traces.get(config.getName());
-    }
-
-    /**
-     * Clients should use {@link TLCErrorTraceRegistry#getErrorTraceRegistry()} to access
-     * the singleton instance of this class.
-     */
-    private TLCErrorTraceRegistry()
-    {
-        traces = new Hashtable();
-    }
-
-    /**
-     * Access method for error trace registry.
-     * 
-     * @return
-     */
-    public static TLCErrorTraceRegistry getErrorTraceRegistry()
-    {
-        if (instance == null)
-        {
-            instance = new TLCErrorTraceRegistry();
-        }
-        return instance;
-    }
-}
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/util/ModelHelper.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/util/ModelHelper.java
index 2af617ae063a3db4bbab2cd3da81cac0d930864a..62c8ff038cbe4d88769562f4a84ee051e5149550 100644
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/util/ModelHelper.java
+++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/util/ModelHelper.java
@@ -28,12 +28,14 @@ package org.lamport.tla.toolbox.tool.tlc.util;
 import java.io.ByteArrayInputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Vector;
+import java.util.function.Predicate;
 import java.util.regex.Matcher;
 
 import org.eclipse.core.resources.IFile;
@@ -64,10 +66,7 @@ import org.lamport.tla.toolbox.tool.ToolboxHandle;
 import org.lamport.tla.toolbox.tool.tlc.TLCActivator;
 import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants;
 import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationDefaults;
-import org.lamport.tla.toolbox.tool.tlc.model.Assignment;
-import org.lamport.tla.toolbox.tool.tlc.model.Formula;
 import org.lamport.tla.toolbox.tool.tlc.model.Model;
-import org.lamport.tla.toolbox.tool.tlc.model.ModelWriter;
 import org.lamport.tla.toolbox.util.ResourceHelper;
 
 import tla2sany.modanalyzer.SpecObj;
@@ -76,6 +75,9 @@ import tla2sany.semantic.OpDeclNode;
 import tla2sany.semantic.OpDefNode;
 import tla2sany.semantic.SymbolNode;
 import tla2sany.st.Location;
+import tlc2.model.Assignment;
+import tlc2.output.SpecWriterUtilities;
+import util.TLAConstants;
 
 /**
  * Provides utility methods for model manipulation
@@ -107,22 +109,15 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur
      * Delimiter used to serialize parameter-value pair  
      */
     private static final String PARAM_DELIMITER = ":";
-
-    public static final String FILE_TLA_EXTENSION = ".tla";
     
-    public static final String MC_MODEL_NAME = "MC";
-    public static final String FILE_TLA = MC_MODEL_NAME + FILE_TLA_EXTENSION;
-    public static final String FILE_CFG = MC_MODEL_NAME + ".cfg";
-    public static final String FILE_OUT = MC_MODEL_NAME + ".out";
-
     // trace explorer file names
     public static final String TE_MODEL_NAME = "TE";
-    public static final String TE_FILE_TLA = TE_MODEL_NAME + FILE_TLA_EXTENSION;
-    public static final String TE_FILE_CFG = TE_MODEL_NAME + ".cfg";
-    public static final String TE_FILE_OUT = TE_MODEL_NAME + ".out";
+    public static final String TE_FILE_TLA = TE_MODEL_NAME + TLAConstants.Files.TLA_EXTENSION;
+    public static final String TE_FILE_CFG = TE_MODEL_NAME + TLAConstants.Files.CONFIG_EXTENSION;
+    public static final String TE_FILE_OUT = TE_MODEL_NAME + TLAConstants.Files.OUTPUT_EXTENSION;
     // the file to which TLC's output is written so
     // that the trace explorer can retrieve the trace when it is run
-    public static final String TE_TRACE_SOURCE = "MC_TE.out";
+    public static final String TE_TRACE_SOURCE = "MC_TE" + TLAConstants.Files.OUTPUT_EXTENSION;
 
     /**
      * Convenience method
@@ -253,28 +248,6 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur
         return result;
     }
 
-    /**
-     * De-serialize formula list, to a list of formulas, that are selected (have a leading "1")
-     * 
-     * The first character of the formula is used to determine if the formula is enabled in the model 
-     * editor or not. This allows the user to persist formulas, which are not used in the current model 
-     */
-    public static List<Formula> deserializeFormulaList(List<String> serializedList)
-    {
-        Vector<Formula> result = new Vector<Formula>(serializedList.size());
-        Iterator<String> serializedIterator = serializedList.iterator();
-        while (serializedIterator.hasNext())
-        {
-            String entry = serializedIterator.next();
-            Formula formula = new Formula(entry.substring(1));
-            if ("1".equals(entry.substring(0, 1)))
-            {
-                result.add(formula);
-            }
-        }
-        return result;
-    }
-
     /**
      * Extract the constants from module node
      * @param moduleNode
@@ -573,28 +546,28 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur
                 final int errorLineOffset = lineRegion.getOffset();
 
                 // find the previous comment
-                final IRegion commentRegion = searchAdapter.find(errorLineOffset, ModelWriter.COMMENT, false, false, false,
+                final IRegion commentRegion = searchAdapter.find(errorLineOffset, TLAConstants.COMMENT, false, false, false,
                         false);
 
                 // find the next separator
-                final IRegion separatorRegion = searchAdapter.find(errorLineOffset, ModelWriter.SEP, true, false, false,
+                final IRegion separatorRegion = searchAdapter.find(errorLineOffset, TLAConstants.SEP, true, false, false,
                         false);
                 if (separatorRegion != null && commentRegion != null)
                 {
                     // find the first attribute inside of the
                     // comment
-                    final IRegion attributeRegion = searchAdapter.find(commentRegion.getOffset(), ModelWriter.ATTRIBUTE
+                    final IRegion attributeRegion = searchAdapter.find(commentRegion.getOffset(), TLAConstants.ATTRIBUTE
                             + "[a-z]*[A-Z]*", true, false, false, true);
                     if (attributeRegion != null)
                     {
                         // get the attribute name without the
                         // attribute marker
                         attributeName = document.get(attributeRegion.getOffset(), attributeRegion.getLength())
-                                .substring(ModelWriter.ATTRIBUTE.length());
+                                .substring(TLAConstants.ATTRIBUTE.length());
 
                         // find the index
                         final IRegion indexRegion = searchAdapter.find(attributeRegion.getOffset()
-                                + attributeRegion.getLength(), ModelWriter.INDEX + "[0-9]+", true, false, false, true);
+                                + attributeRegion.getLength(), TLAConstants.COLON + "[0-9]+", true, false, false, true);
                         if (indexRegion != null && indexRegion.getOffset() < separatorRegion.getOffset())
                         {
                             // index value found
@@ -751,7 +724,7 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur
      */
     private static String getMessageWithoutFile(IFile rootModule, String message, String attributeName, int attributeIndex)
     {
-        String module = rootModule.getName().replace(".tla", "");
+        String module = rootModule.getName().replace(TLAConstants.Files.TLA_EXTENSION, "");
 		if (message.indexOf("in module " + module) != -1 || message.indexOf("of module " + module) != -1)
         {
             // first possible expression
@@ -831,23 +804,31 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur
         } else if (attributeName.equals(Model.MODEL_EXPRESSION_EVAL))
         {
             return "Expression";
-        } else if (attributeName.equals(TRACE_EXPLORE_EXPRESSIONS)) {
+        } else if (attributeName.equals(TLAConstants.TraceExplore.TRACE_EXPLORE_EXPRESSIONS)) {
         	return "Error-Trace Exploration expression";
         }
         return attributeName;
     }
 
-    /**
     /**
      * Find the IDs in the given text and return the array of 
      * regions pointing to those or an empty array, if no IDs were found.
-     * An ID is scheme_timestamp, created by {@link ModelWriter#getValidIdentifier(String)} e.G. next_125195338522638000
+     * An ID is scheme_timestamp, created by {@link SpecWriterUtilities#getValidIdentifier(String)} e.G. next_125195338522638000
+     * 
      * @param text text containing IDs (error text)
      * @return array of regions or empty array
      */
-    public static IRegion[] findIds(String text)
-    {
-        return ModelWriter.findIds(text);
+	public static IRegion[] findIds(final String text) {
+		if ((text == null) || (text.length() == 0)) {
+			return new IRegion[0];
+		}
+
+		final Matcher matcher = SpecWriterUtilities.ID_MATCHER.matcher(text);
+		final ArrayList<Region> regions = new ArrayList<>();
+		while (matcher.find()) {
+            regions.add(new Region(matcher.start(), matcher.end() - matcher.start()));
+        }
+        return regions.toArray(new IRegion[regions.size()]);
     }
 
     /**
@@ -999,17 +980,24 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur
     {
         // get the list of dependent modules
         List<String> extendedModules = ToolboxHandle.getExtendedModules(specRootFile.getName());
+        copyModuleFiles(specRootFile, targetFolderPath, monitor, STEP, project, extendedModules, e -> ToolboxHandle.isUserModule(e));
+    }
+  
+    public static void copyModuleFiles(IFile specRootFile, IPath targetFolderPath, IProgressMonitor monitor,
+            int STEP, IProject project, Collection<String> extendedModules, final Predicate<String> p) throws CoreException
+    {
 
         // iterate and copy modules that are needed for the spec
         IFile moduleFile = null;
-        for (int i = 0; i < extendedModules.size(); i++)
-        {
-            String module = extendedModules.get(i);
+        
+        final Iterator<String> iterator = extendedModules.iterator();
+        while (iterator.hasNext()) {
+        	String module = iterator.next();
             // only take care of user modules
-            if (ToolboxHandle.isUserModule(module))
+            if (p.test(module))
             {
                 moduleFile = ResourceHelper.getLinkedFile(project, module, false);
-                if (moduleFile != null)
+                if (moduleFile != null && moduleFile.exists())
                 {
                     moduleFile.copy(targetFolderPath.append(moduleFile.getProjectRelativePath()), IResource.DERIVED
                             | IResource.FORCE, new SubProgressMonitor(monitor, STEP / extendedModules.size()));
@@ -1039,7 +1027,7 @@ public class ModelHelper implements IModelConfigurationConstants, IModelConfigur
         while (it.hasNext())
         {
             String moduleName = it.next();
-            if (moduleName.equals(FILE_TLA))
+            if (moduleName.equals(TLAConstants.Files.MODEL_CHECK_TLA_FILE))
             {
                 return true;
             }
diff --git a/org.lamport.tla.toolbox.uitest/src/org/lamport/tla/toolbox/ui/handler/DeleteSpecHandlerTest.java b/org.lamport.tla.toolbox.uitest/src/org/lamport/tla/toolbox/ui/handler/DeleteSpecHandlerTest.java
index 96ffcf02b86dd30408fc1a80c5dfb1726baeb8ee..9187625e828d95e6452516183d12e35a4b176c40 100644
--- a/org.lamport.tla.toolbox.uitest/src/org/lamport/tla/toolbox/ui/handler/DeleteSpecHandlerTest.java
+++ b/org.lamport.tla.toolbox.uitest/src/org/lamport/tla/toolbox/ui/handler/DeleteSpecHandlerTest.java
@@ -34,6 +34,8 @@ import org.lamport.tla.toolbox.ui.navigator.ToolboxExplorer;
 import org.lamport.tla.toolbox.util.ResourceHelper;
 import org.lamport.tla.toolbox.util.UIHelper;
 
+import util.TLAConstants;
+
 @RunWith(SWTBotJunit4ClassRunner.class)
 public class DeleteSpecHandlerTest {
 
@@ -70,7 +72,7 @@ public class DeleteSpecHandlerTest {
 		assertEquals(0, Activator.getSpecManager().getSpecs().size());
 		
 		// create a valid path
-		File fileA = File.createTempFile("DeleteMultiSpecA", ".tla");
+		File fileA = File.createTempFile("DeleteMultiSpecA", TLAConstants.Files.TLA_EXTENSION);
 		fileA.delete();
 		// Create the spec file
 		ResourcesPlugin.getWorkspace().run(ResourceHelper.createTLAModuleCreationOperation(new Path(fileA.getAbsolutePath())),
@@ -81,7 +83,7 @@ public class DeleteSpecHandlerTest {
 		Activator.getSpecManager().addSpec(spec);
 
 		// create a second valid path
-		File fileB = File.createTempFile("DeleteMultiSpecB", ".tla");
+		File fileB = File.createTempFile("DeleteMultiSpecB", TLAConstants.Files.TLA_EXTENSION);
 		fileB.delete();
 		// Create the spec file
 		ResourcesPlugin.getWorkspace().run(ResourceHelper.createTLAModuleCreationOperation(new Path(fileB.getAbsolutePath())),
diff --git a/org.lamport.tla.toolbox/helpContexts.xml b/org.lamport.tla.toolbox/helpContexts.xml
index fe4cf9b106214ad9a23d32f168c9936f24c63e1e..4a19e1483914e9843fa26cd252ca9fab0b299894 100644
--- a/org.lamport.tla.toolbox/helpContexts.xml
+++ b/org.lamport.tla.toolbox/helpContexts.xml
@@ -48,11 +48,11 @@
      <topic href="../org.lamport.tla.toolbox.doc/html/gettingstarted/gettingstarted.html" label="Getting Started"/>
   </context>
   <context id="ErrorTraceExplorerExpression" title="Error-Trace Explorer Expressions">
-     <description>A named expression is syntactically equivalent to a zero-arity operator such that &quot;id == expr&quot; where &quot;id&quot; is an identifier not declared or defined elsewhere.  Subsequent named expressions may refer to named expressions stated above. In other words, named expressions are composable.
-
-The _TEPosition operator is defined for each state to be equivalent to the value shown as &quot;State (num = N)&quot; in the Error-Trace where N is in Nat.
-
-_TETrace is defined to be the sequence of states such that _TETrace[_TEPosition] is equivalent to the state at position _TEPosition.</description>
+  	<description>An error-trace expression may be given the name &quot;id&quot; by preceding it with &quot;id ==&quot;.  This defines id to equal that expression in subsequent error-trace explorer expressions.
+   
+The operators _TETrace and _TEPosition in an error-trace expression are defined as follows.  When the expression is evaluated, _TETrace equals the sequence of records such that for every spec variable v, the value of _TETrace[N].v equals the value of v in state number N of the trace.  When the expression is evaluated in state number N, the operator _TEPosition equals N.
+  	</description>
+  
      <topic href="../org.lamport.tla.toolbox.doc/html/model/results-page.html" label="Model Checking Results Page"/>
   </context>
  
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/Module.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/Module.java
index cbcaad9ef3ce0c428e86cd84d8e98d25fe98baf0..ae4f5f784f1b0d3fdea21ca3451b08b39e7d3fb7 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/Module.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/Module.java
@@ -27,11 +27,19 @@
 package org.lamport.tla.toolbox.spec;
 
 import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
 
 import org.eclipse.core.resources.IResource;
 
+import tla2sany.modanalyzer.ParseUnit;
 import tla2sany.semantic.ModuleNode;
 import tlc2.module.BuiltInModuleHelper;
+import util.FilenameToStream.TLAFile;
+import util.NamedInputStream;
+import util.TLAConstants;
 
 /**
  * Representation of a module
@@ -44,13 +52,17 @@ public class Module
     private boolean isRoot = false;
 	private IResource resource;
 
-    public Module(String absoluteFilename)
+	private final ParseUnit parseUnit;
+
+    public Module(ParseUnit parseUnit)
     {
-        file = new File(absoluteFilename);
+        this.file = new File(parseUnit.getNis().sourceFile().getAbsolutePath());
+        this.parseUnit = parseUnit;
     }
 
     public Module(IResource resource) {
-    	this(resource.getLocation().toOSString());
+    	this.file = new File(resource.getLocation().toOSString());
+    	this.parseUnit = null;
     	this.resource = resource;
 	}
 
@@ -96,9 +108,10 @@ public class Module
     public String getModuleName()
     {
         String filename = file.getName();
-        if (filename.toLowerCase().indexOf(".tla") != -1)
+        final int tlaSuffixIndex = filename.toLowerCase().indexOf(TLAConstants.Files.TLA_EXTENSION);
+        if (tlaSuffixIndex != -1)
         {
-            filename = filename.substring(0, filename.indexOf(".tla"));
+            filename = filename.substring(0, tlaSuffixIndex);
         }
         return filename;
     }
@@ -124,17 +137,26 @@ public class Module
         this.node = node;
     }
 
+    public boolean isStandardModule() {
+    	if (this.node != null) {
+    		// As standard module such as FiniteSets, ... are considered library modules.
+    		return this.node.isStandardModule();
+    	}
+    	// TODO Fishy method; improve/unify!
+        return (getAbsolutePath().indexOf(BuiltInModuleHelper.STANDARD_MODULES) != -1);
+    }
+    
     /**
-     * Determines if current module is a standard module <br>
-     * TODO Fishy method. improve/unify it
-     * 
-     * @return true iff the absolute path of the module contains BuiltInModuleHelper.STANDARD_MODULES value
-     */
-    public boolean isStandardModule()
+	 * Determines if current module has been loaded from the library path, i.e. it
+	 * is a standard module or part of a module archive such as CommuinityModules.
+	 */
+    public boolean isLibraryModule()
     {
-        return (getAbsolutePath().indexOf(BuiltInModuleHelper.STANDARD_MODULES) != -1);
+    	if (this.parseUnit != null && parseUnit.isLibraryModule()) {
+    		return true;
+    	}
+    	return isStandardModule();
     }
-
     
     public boolean isRoot()
     {
@@ -145,4 +167,20 @@ public class Module
     {
         this.isRoot = isRoot;
     }
+
+	public void copyTo(final Path dst) throws IOException {
+		Files.copy(file.toPath(), dst.resolve(file.getName()), StandardCopyOption.REPLACE_EXISTING);
+
+		// Attempt to copy corresponding TLC module override (.class file) if any for this Module. 
+		if (this.parseUnit != null) {
+			final NamedInputStream nis = this.parseUnit.getNis();
+			if (nis != null && nis.sourceFile() instanceof TLAFile) {
+				final TLAFile tlaFile = (TLAFile) nis.sourceFile();
+				final File moduleOverride = tlaFile.getModuleOverride();
+				if (moduleOverride != null) {
+					Files.copy(moduleOverride.toPath(), dst.resolve(moduleOverride.getName()), StandardCopyOption.REPLACE_EXISTING);
+				}
+			}
+		}
+	}
 }
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/parser/ModuleParserLauncher.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/parser/ModuleParserLauncher.java
index b5a114d9015e44da9d8c6f3f15f5615faf940c80..125f202e343fffe2faa68985c17815c5a133cff6 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/parser/ModuleParserLauncher.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/parser/ModuleParserLauncher.java
@@ -256,20 +256,10 @@ public class ModuleParserLauncher
             String moduleName = enumerate.nextElement();
             ParseUnit parseUnit = (ParseUnit) moduleSpec.parseUnitContext.get(moduleName);
 
-            String absoluteFileName = null;
-            if (parseUnit.getNis() != null && parseUnit.getNis().sourceFile() != null)
-            {
-                absoluteFileName = parseUnit.getNis().sourceFile().getAbsolutePath();
-            }
-            if (absoluteFileName == null)
-            {
-                throw new RuntimeException("Bug: Spec.ParseMainModule:1730");
-            }
-
             // create module holder
-            Module module = new Module(absoluteFileName);
+            Module module = new Module(parseUnit);
 
-            if (!module.isStandardModule() && updateStorage)
+            if (!module.isLibraryModule() && updateStorage)
             {
 
                 IResource moduleResource = ResourceHelper.getResourceByModuleName(moduleName);
@@ -298,7 +288,7 @@ public class ModuleParserLauncher
                 module.setRoot(true);
             }
 
-            if (module.isStandardModule())
+            if (module.isLibraryModule())
             {
                 // standardModules.addElement(module);
             } else
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/contribution/ModuleListContributionItem.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/contribution/ModuleListContributionItem.java
index 87f51fc1df0f171863b25ed664bae93cda806e63..55272de960c984bfa0282651aa061e581971fef7 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/contribution/ModuleListContributionItem.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/contribution/ModuleListContributionItem.java
@@ -42,6 +42,8 @@ import org.lamport.tla.toolbox.ui.handler.OpenModuleHandler;
 import org.lamport.tla.toolbox.util.ResourceHelper;
 import org.lamport.tla.toolbox.util.UIHelper;
 
+import tlc2.output.SpecWriterUtilities;
+
 /**
  * Contribution item for opening the modules
  */
@@ -89,7 +91,7 @@ public class ModuleListContributionItem extends CompoundContributionItem
 
                 parameters = new HashMap<String, String>();
                 // fill the module name for the handler
-                parameters.put(OpenModuleHandler.PARAM_MODULE, ResourceHelper.getModuleNameChecked(
+                parameters.put(OpenModuleHandler.PARAM_MODULE, SpecWriterUtilities.getModuleNameChecked(
                         modules[i].getName(), false));
 
                 // create the contribution item
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/AddModuleHandler.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/AddModuleHandler.java
index 4543b885654dd7529fcd8087de7c0f4d5c3b6656..d19604b20a69bc2a69c8f88501edfeaa74b04395 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/AddModuleHandler.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/AddModuleHandler.java
@@ -24,6 +24,8 @@ import org.lamport.tla.toolbox.spec.Spec;
 import org.lamport.tla.toolbox.util.ResourceHelper;
 import org.lamport.tla.toolbox.util.UIHelper;
 
+import tlc2.output.SpecWriterUtilities;
+
 /**
  * Command handler for adding new modules (opening non-existing modules or modules in the directory of the root module)
  * 
@@ -146,7 +148,7 @@ public class AddModuleHandler extends AbstractHandler implements IHandler
 
                 // create parameters for the handler
                 Map<String, String> parameters = new HashMap<String, String>();
-                parameters.put(OpenModuleHandler.PARAM_MODULE, ResourceHelper.getModuleNameChecked(module.getName(),
+                parameters.put(OpenModuleHandler.PARAM_MODULE, SpecWriterUtilities.getModuleNameChecked(module.getName(),
                         false));
 
                 // runs the command and opens the module in the editor
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/CloseSpecHandler.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/CloseSpecHandler.java
index 6b042d59ea72b59ada933c692a555067ad5b908d..a4846575ba16242f5f2fd59f649861d3bd760a20 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/CloseSpecHandler.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/CloseSpecHandler.java
@@ -27,7 +27,7 @@ public class CloseSpecHandler extends AbstractHandler implements IHandler
     public static final QualifiedName LAST_CLOSED_DATE = 
         new QualifiedName(COMMAND_ID, "lastClosedTime");
 
-    public Object execute(ExecutionEvent event) throws ExecutionException
+    public Object execute(final ExecutionEvent event) throws ExecutionException
     {
         // Set the project's last closed time to the current time.
     	Spec specClosed = null;
@@ -46,8 +46,13 @@ public class CloseSpecHandler extends AbstractHandler implements IHandler
             Activator.getDefault().logDebug(
              "Exception thrown when setting project LAST_CLOSED time.");
         }
+        
         // close all editors
-        UIHelper.getActivePage().closeAllEditors(true);
+        if (!UIHelper.getActivePage().closeAllEditors(true)) {
+        	// There are still open editors because the user canceled out of the process
+        	return Boolean.valueOf(false);
+        }
+        
         // hide errors
         UIHelper.hideView(ProblemView.ID);
         // switch perspective
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/DeleteModuleHandler.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/DeleteModuleHandler.java
index 423ce053cf82575f7d83f59b80a12efabbf6d0ba..637eaa7e7057022c7c9f7cbbd9549856a9a3f45c 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/DeleteModuleHandler.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/DeleteModuleHandler.java
@@ -22,6 +22,8 @@ import org.lamport.tla.toolbox.spec.Spec;
 import org.lamport.tla.toolbox.spec.manager.WorkspaceSpecManager;
 import org.lamport.tla.toolbox.util.ToolboxJob;
 
+import util.TLAConstants;
+
 /**
  * If a module is selected and it is not the main module of the specification, facilitate its deletion.
  */
@@ -75,7 +77,7 @@ public class DeleteModuleHandler extends AbstractHandler {
 		final IWorkbenchWindow iww = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
 		final IWorkbenchPage page = iww.getActivePage();
 		final IEditorReference[] refs = page.getEditorReferences();
-		final String tabName = m.getModuleName() + ".tla";
+		final String tabName = m.getModuleName() + TLAConstants.Files.TLA_EXTENSION;
 		boolean removeModule = true;
 		for (final IEditorReference ier : refs) {
 			if (tabName.equals(ier.getName())) {
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/DeleteSpecHandler.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/DeleteSpecHandler.java
index 70818dcc249dad38a40e22acf7a9ec31127a4c90..2cd8b439f223a143713355a02be129dbd9dbc7b4 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/DeleteSpecHandler.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/DeleteSpecHandler.java
@@ -30,46 +30,47 @@ import org.lamport.tla.toolbox.util.UIHelper;
  * 
  * @author Simon Zambrovski
  */
-public class DeleteSpecHandler extends AbstractHandler implements IHandler
-{
-
+public class DeleteSpecHandler extends AbstractHandler implements IHandler {
     /* (non-Javadoc)
      * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
      */
-    public Object execute(ExecutionEvent event) throws ExecutionException
-    {
+	public Object execute(ExecutionEvent event) throws ExecutionException {
          /*
          * No parameter try to get it from active navigator if any
          */
-        IWorkbenchPage activePage = UIHelper.getActivePage();
-        if (activePage != null)
-        {
-            ISelection selection = activePage.getSelection(ToolboxExplorer.VIEW_ID);
-            if (selection != null && selection instanceof IStructuredSelection
-                    && !((IStructuredSelection) selection).isEmpty())
-            {
-                
-                Iterator<Object> selectionIterator = ((IStructuredSelection) selection).iterator();
-                while (selectionIterator.hasNext()) 
-                {
-                	Object next = selectionIterator.next();
+		final IWorkbenchPage activePage = UIHelper.getActivePage();
+		if (activePage != null) {
+            final ISelection selection = activePage.getSelection(ToolboxExplorer.VIEW_ID);
+			if ((selection != null) && (selection instanceof IStructuredSelection)
+					&& !((IStructuredSelection) selection).isEmpty()) {
+                final Iterator<?> selectionIterator = ((IStructuredSelection) selection).iterator();
+				while (selectionIterator.hasNext()) {
+                	final Object next = selectionIterator.next();
                 	if (!(next instanceof Spec)) {
                 		// The selection can contain models and groups too.
                 		continue;
                 	}
+                	
                     final Spec spec = (Spec) next;
                     // 3 Aug 2011: LL changed the dialog's message to make it clearer what the Delete command does.
-                    boolean answer = MessageDialog.openQuestion(UIHelper.getShellProvider().getShell(), "Delete specification?",
-                            "Do you really want the Toolbox to forget the specification " + spec.getName() + " and delete all its models?");
-                    if (answer)
-                    {
+                    final boolean answer
+                    	= MessageDialog.openQuestion(UIHelper.getShellProvider().getShell(),
+                    								 "Delete specification?",
+                    								 "Do you really want the Toolbox to forget the specification "
+                    										 		+ spec.getName() + " and delete all its models?");
+					if (answer) {
                     	// close the spec handler (in the ui thread)
                     	final WorkspaceSpecManager specManager = Activator.getSpecManager();
                         if (specManager.isSpecLoaded(spec)) {
-                        	new CloseSpecHandler().execute(event);
+                        	final CloseSpecHandler handler = new CloseSpecHandler();
+                        	final Boolean result = (Boolean)handler.execute(event);
+                        	
+                        	if ((result != null) && !result.booleanValue()) {
+                        		// there was a dirty editor and the user cancelled out of the closing
+                        		return null;
+                        	}
                         }
                     	
-    					// use confirmed rename -> rename
     					final Job j = new ToolboxJob("Deleting spec...") {
     						protected IStatus run(final IProgressMonitor monitor) {
     							Activator.getSpecManager().removeSpec(spec, monitor, false);
@@ -81,12 +82,10 @@ public class DeleteSpecHandler extends AbstractHandler implements IHandler
                 }
             }
         }
-
         
         return null;
     }
 
-
 	/* (non-Javadoc)
 	 * @see org.eclipse.core.commands.AbstractHandler#isEnabled()
 	 */
@@ -97,5 +96,4 @@ public class DeleteSpecHandler extends AbstractHandler implements IHandler
 		}
 		return super.isEnabled();
 	}
-   
 }
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/OpenSpecHandler.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/OpenSpecHandler.java
index f610ed934497d3ec68eb7f3f712f07569a0a0279..8b74e8c4db06d1abf5ca8ccfee0545d957352c29 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/OpenSpecHandler.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/OpenSpecHandler.java
@@ -33,9 +33,9 @@ public class OpenSpecHandler extends AbstractHandler implements IHandler
     public static final String PARAM_SPEC = "toolbox.command.spec.open.param";
     public static final String TLC_ERROR_VIEW_ID = "toolbox.tool.tlc.view.TLCErrorView";
 
-    public Object execute(ExecutionEvent event) throws ExecutionException
+    public Object execute(final ExecutionEvent event) throws ExecutionException
     {
-        String specName = event.getParameter(PARAM_SPEC);
+        final String specName = event.getParameter(PARAM_SPEC);
         // if no spec name, exit
         if (specName == null)
         {
@@ -43,9 +43,13 @@ public class OpenSpecHandler extends AbstractHandler implements IHandler
         }
 
         // if another spec is currently loaded, close it
-        if (Activator.getSpecManager().getSpecLoaded() != null)
-        {
-            UIHelper.runCommand(CloseSpecHandler.COMMAND_ID, null);
+		if (Activator.getSpecManager().getSpecLoaded() != null) {
+			final Object result = UIHelper.runCommand(CloseSpecHandler.COMMAND_ID, null);
+			
+			if ((result != null) && (result instanceof Boolean) && !((Boolean)result).booleanValue()) {
+				// The attempt to close an open spec was canceled out of by the user
+				return null;
+			}
         }
 
         final Spec spec = Activator.getSpecManager().getSpecByName(specName);
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/ShowHistoryHandler.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/ShowHistoryHandler.java
index 8b3df977ca5da9eeda07725023e5716bd08ee05d..12abf7f170fae7209d050065229bbe178de774f6 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/ShowHistoryHandler.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/ShowHistoryHandler.java
@@ -43,28 +43,31 @@ import org.lamport.tla.toolbox.spec.Module;
 
 @SuppressWarnings("restriction")
 public class ShowHistoryHandler extends AbstractHandler implements IHandler {
-
-	/* (non-Javadoc)
-	 * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
-	 */
-	public Object execute(final ExecutionEvent event) throws ExecutionException {
+	public static void openHistoryForModule(final Module module) {
 		final IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
 		if (activeWorkbenchWindow == null) {
-			return null;
+			return;
 		}
 		
+		final IHistoryView view
+				= TeamUI.showHistoryFor(activeWorkbenchWindow.getActivePage(), module.getResource(), null);
+		final IHistoryPage page = view.getHistoryPage();
+		if (page instanceof LocalHistoryPage) {
+			((LocalHistoryPage)page).setClickAction(true);
+		}
+	}
+	
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Object execute(final ExecutionEvent event) throws ExecutionException {
 		final ISelection selection = HandlerUtil.getCurrentSelection(event);
 		if (selection instanceof IStructuredSelection) {
 			final IStructuredSelection iss = (IStructuredSelection) selection;
 			final Object input = iss.getFirstElement();
 			if (input instanceof Module) {
-				final IHistoryView view = TeamUI.showHistoryFor(activeWorkbenchWindow.getActivePage(),
-						((Module) input).getResource(), null);
-				final IHistoryPage page = view.getHistoryPage();
-				if (page instanceof LocalHistoryPage) {
-					final LocalHistoryPage historyPage = (LocalHistoryPage) page;
-					historyPage.setClickAction(true);
-				}
+				openHistoryForModule((Module)input);
 			}
 		}
 		return null;
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/preference/EditorPreferencePage.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/preference/EditorPreferencePage.java
index 4dd84014dedda4a1c4e707a1973680465233a4b6..b6b7313c723c39d74bb4f5d81d85ea574854cad5 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/preference/EditorPreferencePage.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/preference/EditorPreferencePage.java
@@ -18,10 +18,10 @@ import org.eclipse.ui.IWorkbenchPreferencePage;
 import org.lamport.tla.toolbox.Activator;
 import org.lamport.tla.toolbox.util.IHelpConstants;
 import org.lamport.tla.toolbox.util.UIHelper;
+import org.lamport.tla.toolbox.util.pref.IPreferenceConstants;
 
 /**
  * @author lamport
- *
  */
 public class EditorPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage
 {
@@ -60,7 +60,6 @@ public class EditorPreferencePage extends FieldEditorPreferencePage implements I
     public EditorPreferencePage(int style)
     {
         super(style);
-        // TODO Auto-generated constructor stub
     }
 
     /**
@@ -70,7 +69,6 @@ public class EditorPreferencePage extends FieldEditorPreferencePage implements I
     public EditorPreferencePage(String title, int style)
     {
         super(title, style);
-        // TODO Auto-generated constructor stub
     }
 
     /**
@@ -81,7 +79,6 @@ public class EditorPreferencePage extends FieldEditorPreferencePage implements I
     public EditorPreferencePage(String title, ImageDescriptor image, int style)
     {
         super(title, image, style);
-        // TODO Auto-generated constructor stub
     }
 
     protected Control createContents(Composite parent)
@@ -94,10 +91,9 @@ public class EditorPreferencePage extends FieldEditorPreferencePage implements I
     /* (non-Javadoc)
      * @see org.eclipse.jface.preference.FieldEditorPreferencePage#createFieldEditors()
      */
-    protected void createFieldEditors()
-    {   IntegerFieldEditor rightMarginEditor = 
-            new IntegerFieldEditor(EDITOR_RIGHT_MARGIN, "&Module editor right margin", 
-                   getFieldEditorParent());
+	protected void createFieldEditors() {
+		final IntegerFieldEditor rightMarginEditor = new IntegerFieldEditor(EDITOR_RIGHT_MARGIN,
+				"&Module editor right margin", getFieldEditorParent());
         addField(rightMarginEditor);
         rightMarginEditor.setValidRange(20, 200);
         
@@ -107,15 +103,16 @@ public class EditorPreferencePage extends FieldEditorPreferencePage implements I
         addField(new BooleanFieldEditor(EDITOR_ADD_MODIFICATION_HISTORY,
                 "&Add a modification history comment to new specs", getFieldEditorParent()));
 
+        
         // Preferences for renumbering.  Added 25 July 2013 by LL
         Label lbl = new Label(getFieldEditorParent(), SWT.NONE);
         GridData gd = new GridData();
         gd.horizontalSpan = 2;
         lbl.setLayoutData(gd);
         
-        lbl = new Label(getFieldEditorParent(), SWT.NONE);
-        lbl.setText("Renumber Proof Command preferences") ;
-        lbl.setLayoutData(gd);
+		lbl = new Label(getFieldEditorParent(), SWT.NONE);
+		lbl.setText("Renumber Proof Command preferences");
+		lbl.setLayoutData(gd);
         
         addField(new RadioGroupFieldEditor(EditorPreferencePage.RENUMBER_KEY, 
         		"Which step names to renumber", 1,
@@ -126,16 +123,28 @@ public class EditorPreferencePage extends FieldEditorPreferencePage implements I
         	      {"Names that are all digits", ALL_DIGITS} },
         		getFieldEditorParent())) ;
         addField(new BooleanFieldEditor(SAVE_MODULE, "&Save module", 
-                   getFieldEditorParent())) ;
+                   getFieldEditorParent()));
+        
+        
+        lbl = new Label(getFieldEditorParent(), SWT.NONE);
+        lbl.setLayoutData(gd);
+        
+        lbl = new Label(getFieldEditorParent(), SWT.NONE);
+        lbl.setText("Folding by default preferences");
+        lbl.setLayoutData(gd);
+        
+        addField(new BooleanFieldEditor(IPreferenceConstants.I_FOLDING_BLOCK_COMMENTS,
+                "Fold &block comments by default", getFieldEditorParent()));
+        
+        addField(new BooleanFieldEditor(IPreferenceConstants.I_FOLDING_PCAL_ALGORITHM,
+                "Fold &PlusCal algorithm blocks by default", getFieldEditorParent()));
+        
+        addField(new BooleanFieldEditor(IPreferenceConstants.I_FOLDING_PCAL_TRANSLATED,
+                "Fold &translated &PlusCal algorithm TLA+ code by default", getFieldEditorParent()));
     }
 
     /* (non-Javadoc)
      * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
      */
-    public void init(IWorkbench workbench)
-    {
-        // TODO Auto-generated method stub
-
-    }
-
+    public void init(final IWorkbench workbench) { }
 }
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/provider/ToolboxLabelProvider.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/provider/ToolboxLabelProvider.java
index a03c11e40d5e00297ac7cb28d7b913313ccb0902..48c9ae132a753fa20299e890426d1624047a934b 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/provider/ToolboxLabelProvider.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/provider/ToolboxLabelProvider.java
@@ -52,6 +52,11 @@ public class ToolboxLabelProvider extends LabelProvider implements ILabelProvide
 			if (root == null) {
 				return null;
 			}
+			if (root.getName().replaceAll(".tla$", "").equals(spec.getName())) {
+				// Don't append name of root module if identical to spec name (which is usually
+				// the default).
+				return spec.getName();
+			}
 			return spec.getName() + " [ " + root.getName() + " ]";
 		} else if (element instanceof Module) {
 			return ((Module) element).getModuleName();
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/wizard/NewSpecWizardPage.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/wizard/NewSpecWizardPage.java
index 857fb1bb5f9cccaf8f24ed7ccc2902ec73716112..68b12ce9d18cd5776fcc30ba7b0aefe0ddf048e9 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/wizard/NewSpecWizardPage.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/wizard/NewSpecWizardPage.java
@@ -28,6 +28,9 @@ import org.lamport.tla.toolbox.util.ResourceHelper;
 import org.lamport.tla.toolbox.util.UIHelper;
 import org.lamport.tla.toolbox.util.ZipUtil;
 
+import tlc2.output.SpecWriterUtilities;
+import util.TLAConstants;
+
 /**
  * A wizard page input of the specification name and the location of the root file
  * 
@@ -263,16 +266,16 @@ public class NewSpecWizardPage extends WizardPage
 					final File destDir = ZipUtil.unzip(zip, new File(zip.getAbsolutePath().replaceFirst(".zip$", "")), true);
 					
 					// recursively trigger dialogChanged with now extracted spec.
-					this.fileText.setText(
-							destDir.getAbsolutePath() + File.separator + zip.getName().replaceFirst(".zip$", ".tla"));
+					this.fileText.setText(destDir.getAbsolutePath() + File.separator
+							+ zip.getName().replaceFirst(".zip$", TLAConstants.Files.TLA_EXTENSION));
 					return;
 				} catch (IOException e) {
 					reportError(String.format("Failed to unzip zip archive %s with error %s", rootfilePath,
 							e.getMessage()));
 				}
-            } else if (!rootfilePath.endsWith(".tla"))
+            } else if (!rootfilePath.endsWith(TLAConstants.Files.TLA_EXTENSION))
             {
-                reportError("Root file name should have a file-system path and extension .tla");
+                reportError("Root file name should have a file-system path and extension " + TLAConstants.Files.TLA_EXTENSION);
                 return;
             } else if (!(new File(rootfilePath).isAbsolute()))
             {
@@ -280,14 +283,14 @@ public class NewSpecWizardPage extends WizardPage
                 return;
                 // make sure module name does not violate valid spec name rules
                 // see Bug #112 in general/bugzilla/index.html
-            } else if(!ResourceHelper.isValidSpecName(ResourceHelper.getModuleNameChecked(rootfilePath, false))) {
+            } else if(!ResourceHelper.isValidSpecName(SpecWriterUtilities.getModuleNameChecked(rootfilePath, false))) {
             	// Give the user a hint what a valid spec name might be. E.g. if "Foo.tla" is given,
             	// a valid spec name is "Foo" (without the ".tla" file extension).
-            	final String moduleNameChecked = ResourceHelper.getModuleNameChecked(rootfilePath, false);
+            	final String moduleNameChecked = SpecWriterUtilities.getModuleNameChecked(rootfilePath, false);
             	final String validIdenfier = ResourceHelper.getIdentifier(moduleNameChecked);
 				if ("".equals(validIdenfier)) {
 					reportError("Module name is not valid. The module name '"
-							+ ResourceHelper.getModuleNameChecked(rootfilePath, false) + "' is not a valid identifier.");
+							+ SpecWriterUtilities.getModuleNameChecked(rootfilePath, false) + "' is not a valid identifier.");
 					reportError(String.format(
 							"Module name is not valid. The module name '%s' is not a valid identifier.",
 							moduleNameChecked));
@@ -369,7 +372,7 @@ public class NewSpecWizardPage extends WizardPage
                 // if we got to this point, the fileText is a valid entry
 
                 // just use the module name as a spec name
-                String moduleName = ResourceHelper.getModuleNameChecked(getRootFilename(), false);
+                String moduleName = SpecWriterUtilities.getModuleNameChecked(getRootFilename(), false);
 
                 Spec existingSpec = Activator.getSpecManager().getSpecByName(moduleName);
                 if (existingSpec != null)
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/HelpButton.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/HelpButton.java
index 84e0bf004efcea24d6760b05b17933a3fe9e38a1..62758e691a0badcb5c7e6b48eff4ccf53f3a224b 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/HelpButton.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/HelpButton.java
@@ -11,28 +11,20 @@ import org.eclipse.swt.SWTError;
 import org.eclipse.swt.browser.Browser;
 import org.eclipse.swt.browser.LocationEvent;
 import org.eclipse.swt.browser.LocationListener;
-import org.eclipse.swt.events.DisposeEvent;
-import org.eclipse.swt.events.DisposeListener;
 import org.eclipse.swt.events.SelectionAdapter;
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.events.ShellEvent;
-import org.eclipse.swt.events.ShellListener;
-import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.layout.FillLayout;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.swt.widgets.ToolBar;
 import org.eclipse.swt.widgets.ToolItem;
 import org.eclipse.ui.ISharedImages;
 import org.eclipse.ui.PlatformUI;
-//import org.lamport.tla.toolbox.editor.basic.handlers.DecomposeProofHandler;
 import org.osgi.framework.Bundle;
 
 /**
@@ -57,22 +49,6 @@ import org.osgi.framework.Bundle;
  * to the help page specified by its String argument.
  */
 public class HelpButton {
-	
-	/**
-	 *  This is used only for testing
-	 */
-    public static String baseURL;
-
-    /**
-     * The following fields contain the Browser that displays the help page,
-     * the Shell that creates the Help Window containing the browser, and the
-     * location and size of that window the last time it was closed.
-     */
-    static Browser browser = null;
-    static Shell helpShell = null;
-    static Point location = null ;
-    static Point size = null ;
-    
     /**
      * 
      * @param parent    Where the button should be added.
@@ -82,30 +58,29 @@ public class HelpButton {
      * @return A Button that has been added to the Composite that, when clicked
      *         raises a browser window on the specified help page URL.
      */
-    public static Button helpButton(Composite parent, String helpFile) {
-        Button button = new Button(parent, SWT.NONE);
-        HelpButtonListener listener = new HelpButtonListener(parent, helpFile);
+    public static Button helpButton(final Composite parent, final String helpFile) {
+    	final Button button = new Button(parent, SWT.NONE);
+    	final HelpButtonListener listener = new HelpButtonListener(parent, helpFile);
         button.addSelectionListener(listener);
-        Image helpImg = PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_LCL_LINKTO_HELP);
-        button.setImage(helpImg);
-        GridData gridData = new GridData();
+        button.setImage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_LCL_LINKTO_HELP));
+        final GridData gridData = new GridData();
         gridData.verticalAlignment = SWT.TOP;
         button.setLayoutData(gridData);
         button.setEnabled(true);
-        baseURL = listener.url;
         return button;
     }
 
-    public static class HelpButtonListener extends SelectionAdapter implements
-            SelectionListener {
-
-        String url;
-        Composite shell;
+    
+	private static class HelpButtonListener extends SelectionAdapter implements SelectionListener {
+        private final String url;
+        
+        private Browser browser = null;
+        private Shell helpShell = null;
+        private Point location = null ;
+        private Point size = null ;
 
-        HelpButtonListener(Composite parent, String helpFile) {
-            super();
-            String file = helpFile;
-            shell = parent;
+        HelpButtonListener(final Composite parent, final String helpFile) {
+            final String file = helpFile;
             /*
              * For a helpFile like "foo.html#section", set fileName to
              * "foo.html" and suffix to "#section".  If there is no
@@ -113,22 +88,23 @@ public class HelpButton {
              */
             String fileName = file;
             String suffix = "" ;
-            int idx = fileName.indexOf("#") ;
+            final int idx = fileName.indexOf("#") ;
             if (idx != -1) {
                 suffix = fileName.substring(idx) ;
                 fileName = fileName.substring(0, idx) ;
             }
-            Bundle bundle = Platform.getBundle("org.lamport.tla.toolbox.doc");
+            final Bundle bundle = Platform.getBundle("org.lamport.tla.toolbox.doc");
             /* 
              * The bundle .tla.toolbox does not explicitly depend on .toolbox.doc.
              * Thus, it's possible that the application is running without documentation
              * which results in the variable bundle being null.
              */
+            String urlString = null;
             if (bundle == null) {
-                url = "http://tla.msr-inria.inria.fr/tlatoolbox/doc/" + file ;
+                urlString = "http://tla.msr-inria.inria.fr/tlatoolbox/doc/" + file ;
                 System.out.println("Could not find local copy of help file.");
             } else {
-            	URL fileURL = bundle.getEntry("html/" + fileName);
+            	final URL fileURL = bundle.getEntry("html/" + fileName);
             	File theFile = null;
             	try {
             		theFile = new File(FileLocator.resolve(fileURL).getFile());
@@ -136,13 +112,15 @@ public class HelpButton {
             		e1.printStackTrace();
             	}
             	if (theFile != null) {
-            		url = theFile.getPath() + suffix;
-            	} ;
-            	if ((theFile == null) || (url == null)) {
-            		url = "http://tla.msr-inria.inria.fr/tlatoolbox/doc/" + file ;
+            		urlString = theFile.getPath() + suffix;
+            	}
+            	if ((theFile == null) || (urlString == null)) {
+            		urlString = "http://tla.msr-inria.inria.fr/tlatoolbox/doc/" + file ;
             		System.out.println("Could not find local copy of help file.");
             	}
             }
+            
+            url = urlString;
         }
         
         /**
@@ -151,7 +129,8 @@ public class HelpButton {
          * a new window at the position and with the size of the window the last
          * time it was closed in the current execution of the Toolbox.
          */
-        public void widgetSelected(SelectionEvent e) {
+        @Override
+        public void widgetSelected(final SelectionEvent e) {
             boolean setSize = false;
 
             /*
@@ -160,28 +139,29 @@ public class HelpButton {
              */
             if (helpShell == null) {
                 setSize = true;
-                Shell topshell = UIHelper.getShellProvider().getShell();
+
                 /*
                  * Raise the window without a minimize button because minimizing
                  * puts it as a small window in a corner of the screen, not on
                  * the task bar.
                  */
-                helpShell = new Shell(topshell, SWT.CLOSE | SWT.TITLE
-                        | SWT.RESIZE);
+				helpShell = new Shell(SWT.CLOSE | SWT.TITLE | SWT.RESIZE);
                 helpShell.setText("Toolbox Help");
-                helpShell.addDisposeListener(new HelpWindowDisposeListener());
-                helpShell.addShellListener(new HelpShellListener());
+                helpShell.addDisposeListener((event) -> {
+                    location = helpShell.getLocation();
+                    size = helpShell.getSize();
+                    helpShell = null;
+                });
                 browser = null;
                 helpShell.setLayout(new FillLayout());
-                Composite comp = new Composite(helpShell, SWT.NONE);
+                final Composite comp = new Composite(helpShell, SWT.NONE);
                 comp.setLayout(new GridLayout(1, false));
 
                 /*
                  * Add the "back" and "forward" buttons.
                  */
-                ToolBar navBar = new ToolBar(comp, SWT.NONE);
-                navBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL
-                        | GridData.HORIZONTAL_ALIGN_END));
+                final ToolBar navBar = new ToolBar(comp, SWT.NONE);
+				navBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.HORIZONTAL_ALIGN_END));
                 final ToolItem back = new ToolItem(navBar, SWT.PUSH);
                 back.setText("<-    Back    ");
                 back.setEnabled(false);
@@ -195,31 +175,26 @@ public class HelpButton {
                 try {
                     browser = new Browser(comp, SWT.NONE);
                 } catch (SWTError e1) {
-                    System.out.println("Could not instantiate Browser: "
-                            + e1.getMessage());
+                    System.out.println("Could not instantiate Browser: " + e1.getMessage());
                     helpShell.dispose();
                     return;
                 }
 
-                GridData data = new GridData(GridData.FILL_BOTH);
+                final GridData data = new GridData(GridData.FILL_BOTH);
                 browser.setLayoutData(data);
 
                 /*
                  * Add the listeners for the "back" and "forward" buttons.
                  */
-                back.addListener(SWT.Selection, new Listener() {
-                    public void handleEvent(Event event) {
-                        browser.back();
-                    }
+                back.addListener(SWT.Selection, (event) -> {
+                    browser.back();
                 });
-                forward.addListener(SWT.Selection, new Listener() {
-                    public void handleEvent(Event event) {
-                        browser.forward();
-                    }
+                forward.addListener(SWT.Selection, (event) -> {
+                    browser.forward();
                 });
                 final LocationListener locationListener = new LocationListener() {
                     public void changed(LocationEvent event) {
-                        Browser browser = (Browser) event.widget;
+                    	final Browser browser = (Browser) event.widget;
                         back.setEnabled(browser.isBackEnabled());
                         forward.setEnabled(browser.isForwardEnabled());
                     }
@@ -240,68 +215,20 @@ public class HelpButton {
              * when the previous window was closed.
              */
             if (setSize) {
-                if (HelpButton.location != null) {
-                    helpShell.setLocation(HelpButton.location);
+                if (location != null) {
+                    helpShell.setLocation(location);
                 }
-                if (HelpButton.size != null) {
-                    helpShell.setSize(HelpButton.size);
+                if (size != null) {
+                    helpShell.setSize(size);
                 }
             }
             helpShell.open();
             helpShell.forceFocus();
         }
 
-        public void widgetDefaultSelected(SelectionEvent e) {
+        @Override
+        public void widgetDefaultSelected(final SelectionEvent e) {
             widgetSelected(e);
         }
     }
-
-    static class HelpShellListener implements ShellListener {
-
-        public void shellActivated(ShellEvent e) {
-            // TODO Auto-generated method stub
-//            System.out.println("shellActivated") ;
-            
-        }
-
-        public void shellClosed(ShellEvent e) {
-            // TODO Auto-generated method stub
-//            System.out.println("shellClosed") ;
-        }
-
-        public void shellDeactivated(ShellEvent e) {
-//            System.out.println("shellDeActivated") ;
-            
-        }
-
-        public void shellDeiconified(ShellEvent e) {
-            // TODO Auto-generated method stub
-//            System.out.println("shellDeiconified") ;
-        }
-
-        public void shellIconified(ShellEvent e) {
-            // TODO Auto-generated method stub
-//            System.out.println("shellIconified") ;
-            
-        }
-        
-    }
-    static class HelpWindowDisposeListener implements DisposeListener {
-//        DecomposeProofHandler commandHandler;
-
-//        WindowDisposeListener(DecomposeProofHandler handler) {
-//            commandHandler = handler;
-
-//        }
-
-        public void widgetDisposed(DisposeEvent e) {
-            HelpButton.location = helpShell.getLocation();
-            HelpButton.size = helpShell.getSize();
-            HelpButton.helpShell = null ;
-            
-            
-            
-        }
-    }
-
 }
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/IHelpConstants.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/IHelpConstants.java
index f850ac0e823b3be525981c254f5dbb32d4924674..1219d996b37431cfe2b34e1d7a6f6f0b5a625152 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/IHelpConstants.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/IHelpConstants.java
@@ -12,6 +12,7 @@ public interface IHelpConstants
     public static final String GENERAL_PREFERENCE_PAGE = "GeneralPreferencePage";
     public static final String TLC_PREFERENCE_PAGE = "TLCPreferencePage";
     public static final String EDITOR_PREFERENCE_PAGE = "EditorPreferencePage";
+    public static final String MODEL_EDITOR_PREFERENCE_PAGE = "ModelEditorPreferencePage";
 
     // removed
     // public static final String MODULE_PROPERTY_PAGE = "ModulePropertyPage";
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/PopupMessage.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/PopupMessage.java
deleted file mode 100644
index f323d683d123c63811f4ef489c39fd18e6fc15df..0000000000000000000000000000000000000000
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/PopupMessage.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * This class was created by LL on 12 April 2011 to try to pop up a simple
- * message.  However, it didn't work because I was apparently calling it before
- * the Toolbox had gotten far enough to be able to display a window.  So, it
- * has never been tested.  However, it might be handy at some point. 
- * 
- * THIS METHOD IS UNNECESSARY.  USE the Eclipse MessageDialog class open method.
- */
-package org.lamport.tla.toolbox.util;
-
-import org.eclipse.jface.dialogs.PopupDialog;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Shell;
-
-/**
- * @author lamport
- *
- */
-public class PopupMessage extends PopupDialog
-{
-
-    /**
-     * @param parent
-     * @param shellStyle
-     * @param takeFocusOnOpen
-     * @param persistSize
-     * @param persistLocation
-     * @param showDialogMenu
-     * @param showPersistActions
-     * @param titleText
-     * @param infoText
-     */
-    public PopupMessage(Shell parent, String titleText, String infoText)
-    {
-        super(parent, 
-              SWT.NO_TRIM, // shellStyle, 
-              true, // takeFocusOnOpen, 
-              false, // persistSize, 
-              true, // persistLocation, 
-              true, // showDialogMenu, 
-              true, // showPersistActions,
-              titleText, 
-              infoText);
-        // TODO Auto-generated constructor stub
-    }
-    /**
-     * This should pop up a window with a title displaying a message.  However,
-     * I don't really know what it does because it's never been tested.
-     * 
-     * @param title
-     * @param message
-     */
-    public static void Display(String title, String message) {
-        Shell parent = UIHelper.getShellProvider().getShell();
-        PopupMessage popup = new PopupMessage(parent, title, message);
-        popup.open();
-        return;
-    }
-}
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/RCPNameToFileIStream.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/RCPNameToFileIStream.java
index c7b70b736966ebde245055f60ddf12f4d424ac09..7e28d9ee4011f23c97704169c920a9a037cd9ae0 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/RCPNameToFileIStream.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/RCPNameToFileIStream.java
@@ -8,8 +8,14 @@ import java.nio.file.FileSystems;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
+import java.util.Arrays;
 import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
 import java.util.Vector;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
 
 import org.eclipse.core.runtime.FileLocator;
 import org.eclipse.core.runtime.Platform;
@@ -18,6 +24,7 @@ import org.osgi.framework.Bundle;
 import tla2sany.semantic.ModuleNode;
 import tlc2.module.BuiltInModuleHelper;
 import util.FilenameToStream;
+import util.TLAConstants;
 import util.ToolIO;
 
 /**
@@ -99,7 +106,7 @@ public class RCPNameToFileIStream implements FilenameToStream
      */
     public File resolve(String name, boolean isModule)
     {
-        if (isModule && name.endsWith(".tla"))
+        if (isModule && name.endsWith(TLAConstants.Files.TLA_EXTENSION))
         {
             // user/Foo.tla => user/Foo
             name = name.substring(0, name.length() - 4);
@@ -109,7 +116,7 @@ public class RCPNameToFileIStream implements FilenameToStream
         if (isModule)
         {
             // user/Foo => user/Foo.tla
-            sourceFileName = name + ".tla"; // could be Foo.tla or user/Foo.tla
+            sourceFileName = name + TLAConstants.Files.TLA_EXTENSION; // could be Foo.tla or user/Foo.tla
         } else {
             // user/Foo.cfg => user/Foo.cfg
             sourceFileName = name;
@@ -137,7 +144,7 @@ public class RCPNameToFileIStream implements FilenameToStream
             // improve this: ToolIO.getUserDir()
             if ((idx == 0) && (ToolIO.getUserDir() != null))
             {
-                sourceFile = new File(ToolIO.getUserDir(), name);
+                sourceFile = new TLAFile(ToolIO.getUserDir(), name, this);
             } else
             {
             	if(FilenameToStream.isArchive(prefix)) {
@@ -146,7 +153,7 @@ public class RCPNameToFileIStream implements FilenameToStream
     					return sourceFile;
     				}
             	} else {
-                    sourceFile = new File(prefix + name);
+                    sourceFile = new TLAFile(prefix + name, true, this);
             	}
             }
             if (sourceFile != null && sourceFile.exists()) {
@@ -166,7 +173,7 @@ public class RCPNameToFileIStream implements FilenameToStream
 	// the resource. The problem is, that the Toolbox and TLC work with File instead
 	// of InputStream which is why we can't extract to memory only.
 	private File getFromArchive(String prefix, String name) {
-		final File outputFile = new File(TMPDIR + File.separator + name);
+		final File outputFile = new TLAFile(TMPDIR + File.separator + name, true, this);
 		outputFile.deleteOnExit(); // Written to TMPDIR which is likely deleted regularly anyway.
 		try (FileSystem fileSystem = FileSystems.newFileSystem(new File(prefix).toPath(), null)) {
 	        Path fileToExtract = fileSystem.getPath(name);
@@ -197,6 +204,11 @@ public class RCPNameToFileIStream implements FilenameToStream
 
 	}
 
+	@Override
+	public boolean isLibraryModule(String moduleName) {
+		return isStandardModule(moduleName);
+	}
+	
 	/**
 	 * August 2014 - TL added a stub for this informative interface method. All
 	 * the usages of this class were written before the addition of this
@@ -213,4 +225,41 @@ public class RCPNameToFileIStream implements FilenameToStream
 		}
 		return buf.toString();
 	}
+    
+	/**
+	 * @return The set of the names of all modules found in the various
+	 * libraryPathEntries (Toolbox & TLC installation, spec directories, library
+	 * directories, and library archives.
+	 * <p>
+	 * This are not the modules extended by the current spec.
+	 */
+    public Set<String> getAllModules() {
+    	final Set<String> s = new HashSet<>();
+    	for (final String path : libraryPathEntries) {
+    		if(FilenameToStream.isArchive(path)) {
+    			s.addAll(listTLAFilesInZip(path));
+    		} else {
+    			// List .tla files in the given directory.
+				s.addAll(Arrays.stream(new File(path).listFiles((d, name) -> name.endsWith(TLAConstants.Files.TLA_EXTENSION)))
+						.map(f -> f.getName()).collect(Collectors.toSet()));
+    		}
+		}
+    	return s;
+    }
+    
+    private Set<String> listTLAFilesInZip(String path) {
+    	final Set<String> s = new HashSet<>();
+		try (final ZipFile zipFile = new ZipFile(path)) {
+			final Enumeration<? extends ZipEntry> e = zipFile.entries();
+			while (e.hasMoreElements()) {
+				ZipEntry entry = e.nextElement();
+				String entryName = entry.getName();
+				if (entryName.endsWith(TLAConstants.Files.TLA_EXTENSION)) {
+					s.add(entryName);
+				}
+			}
+		} catch (IOException ignored) {
+		}
+		return s;
+    }
 }
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/ResourceHelper.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/ResourceHelper.java
index a68ebb90f2586450f0f822aef944df4bb94437d1..e7de0f5eddb98cb93856af6fc0e5c381bb3810f0 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/ResourceHelper.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/ResourceHelper.java
@@ -11,7 +11,6 @@ import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -94,7 +93,10 @@ import tla2sany.semantic.ThmOrAssumpDefNode;
 import tla2sany.semantic.UseOrHideNode;
 import tla2sany.st.Location;
 import tla2sany.st.SyntaxTreeConstants;
+import tlc2.output.SpecWriterUtilities;
 import util.FilenameToStream;
+import util.StringHelper;
+import util.TLAConstants;
 import util.UniqueString;
 
 /**
@@ -113,30 +115,13 @@ public class ResourceHelper {
     /**
      * 
      */
-    private static final String TOOLBOX_DIRECTORY_SUFFIX = ".toolbox";
+    public static final String TOOLBOX_DIRECTORY_SUFFIX = ".toolbox";
 
     /**
      * TLA extension
      */
     public static final String TLA_EXTENSION = "tla";
 
-    /*
-     * Constants used for displaying modification history.
-     * It has the syntax:
-     *   modificationHistory +
-     *   (lastModified + date + modifiedBy +
-     *      username + newline)*
-     *      
-     * Note: The StringHelper.newline string wasn't being found on my 64-bit
-     * Windows 7 machine.  So on 8 Dec 2010 I removed it from here, and added
-     * a "\n" before it when writing a new file.
-     */
-    public static String modificationHistory = /* StringHelper.newline + */ "\\* Modification History";
-
-    public static String lastModified = StringHelper.newline + "\\* Last modified ";
-
-    public static String modifiedBy = " by ";
-
     /**
      * Look up if a project exist and return true if so
      * @param name name of the project
@@ -613,7 +598,7 @@ public class ResourceHelper {
      */
     public static String getModuleName(String moduleFilename)
     {
-        return getModuleNameChecked(moduleFilename, true);
+        return SpecWriterUtilities.getModuleNameChecked(moduleFilename, true);
     }
 
     /**
@@ -631,28 +616,6 @@ public class ResourceHelper {
         return getModuleName(resource.getLocation().toOSString());
     }
 
-    /**
-     * Retrieves the name of the module (filename without extension)
-     * 
-     * @param moduleFilename
-     *            filename of a module
-     * @param checkExistence
-     *            if true, the method returns module name, iff the specified file exists or null, if the specified file
-     *            does not exist, if false - only string manipulations are executed
-     * @return module name
-     */
-    public static String getModuleNameChecked(String moduleFilename, boolean checkExistence)
-    {
-        File f = new File(moduleFilename);
-        IPath path = new Path(f.getName()).removeFileExtension();
-        // String modulename = f.getName().substring(0, f.getName().lastIndexOf("."));
-        if (checkExistence)
-        {
-            return (f.exists()) ? path.toOSString() : null;
-        }
-        return path.toOSString();
-    }
-
     /**
      * Creates a module name from a file name (currently, only adding .tla extension)
      * 
@@ -715,13 +678,13 @@ public class ResourceHelper {
     public static StringBuffer getEmptyModuleContent(String moduleFilename)
     {
         StringBuffer buffer = new StringBuffer();
-        String moduleName = ResourceHelper.getModuleNameChecked(moduleFilename, false);
+        String moduleName = SpecWriterUtilities.getModuleNameChecked(moduleFilename, false);
         int numberOfDashes = Math.max(4, (Activator.getDefault().getPreferenceStore().getInt(
                 EditorPreferencePage.EDITOR_RIGHT_MARGIN)
                 - moduleName.length() - 9) / 2);
         String dashes = StringHelper.copyString("-", numberOfDashes);
         buffer.append(dashes).append(" MODULE ").append(moduleName).append(" ").append(dashes).append(
-                StringHelper.copyString(StringHelper.newline, 3));
+                StringHelper.copyString(StringHelper.PLATFORM_NEWLINE, 3));
         return buffer;
     }
 
@@ -729,46 +692,12 @@ public class ResourceHelper {
      * Returns the content for the end of the module
      * @return
      */
-    public static StringBuffer getModuleClosingTag()
-    {
-        StringBuffer buffer = new StringBuffer();
-        IPreferenceStore preferencesStore = Activator.getDefault().getPreferenceStore();
-        int rightMarginWidth = preferencesStore.getInt(EditorPreferencePage.EDITOR_RIGHT_MARGIN);
-        buffer.append(StringHelper.copyString("=", rightMarginWidth)).append(StringHelper.newline);
-
-        if (preferencesStore.getBoolean(EditorPreferencePage.EDITOR_ADD_MODIFICATION_HISTORY)) {
-            buffer.append(modificationHistory).append(StringHelper.newline)
-                .append("\\* Created ").append(new Date()).append(" by ")
-                .append(System.getProperty("user.name")).append(StringHelper.newline);
-        }
-        return buffer;
-    }
-
-    /**
-     * Returns the content for the end of the module
-     * @return
-     */
-    public static StringBuffer getConfigClosingTag()
-    {
-        StringBuffer buffer = new StringBuffer();
-        buffer.append("\\* Generated on ").append(new Date());
-        return buffer;
-    }
-
-    /**
-     * Creates a simple content for a new TLA+ module
-     *  
-     * @param moduleFileName, name of the file 
-     * @return the stream with content
-     */
-    public static StringBuffer getExtendingModuleContent(String moduleFilename, String... extendedModuleName)
-    {
-		final StringBuffer buffer = new StringBuffer();
-		buffer.append("---- MODULE ").append(ResourceHelper.getModuleNameChecked(moduleFilename, false))
-				.append(" ----\n").append("EXTENDS ");
-		buffer.append(String.join(", ", extendedModuleName));
-		buffer.append("\n\n");
-        return buffer;
+    public static StringBuilder getModuleClosingTag() {
+        final IPreferenceStore ips = Activator.getDefault().getPreferenceStore();
+        final int rightMarginWidth = ips.getInt(EditorPreferencePage.EDITOR_RIGHT_MARGIN);
+        final boolean addModificationHistory = ips.getBoolean(EditorPreferencePage.EDITOR_ADD_MODIFICATION_HISTORY);
+        
+        return SpecWriterUtilities.getModuleClosingTag(rightMarginWidth, addModificationHistory);
     }
 
     /**
@@ -805,29 +734,6 @@ public class ResourceHelper {
         return new NewTLAModuleCreationOperation(rootNamePath);
     }
 
-    /**
-     * Writes contents stored in the string buffer to the file, replacing the content 
-     * @param file
-     * @param buffer
-     * @param monitor
-     * @throws CoreException
-     */
-    public static void replaceContent(IFile file, StringBuffer buffer, IProgressMonitor monitor) throws CoreException
-    {
-        ByteArrayInputStream stream = new ByteArrayInputStream(buffer.toString().getBytes());
-        if (file.exists())
-        {
-            file.setContents(stream, IResource.FORCE, monitor);
-        } else
-        {
-            throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Exected " + file.getName()
-                    + " file has been removed externally"));
-            // this will create a file in a wrong location
-            // instead of /rootfile-dir/file.cfg it will create it under /specdir/file.cfg
-            // file.create(stream, force, monitor);
-        }
-    }
-
     /**
      * Writes contents stored in the string buffer to the file, appending the content
      * @param file
@@ -835,18 +741,15 @@ public class ResourceHelper {
      * @param monitor
      * @throws CoreException
      */
-    public static void addContent(IFile file, StringBuffer buffer, IProgressMonitor monitor) throws CoreException
-    {
-        boolean force = true;
-        ByteArrayInputStream stream = new ByteArrayInputStream(buffer.toString().getBytes());
-        if (file.exists())
-        {
-            file.appendContents(stream, IResource.FORCE, monitor);
-        } else
-        {
-            file.create(stream, force, monitor);
-        }
-    }
+	public static void addContent(final IFile file, final StringBuilder buffer, final IProgressMonitor monitor)
+			throws CoreException {
+		final ByteArrayInputStream stream = new ByteArrayInputStream(buffer.toString().getBytes());
+		if (file.exists()) {
+			file.appendContents(stream, IResource.FORCE, monitor);
+		} else {
+			file.create(stream, true, monitor);
+		}
+	}
 
     /**
      * Retrieves a combined rule for modifying the resources
@@ -1795,7 +1698,7 @@ public class ResourceHelper {
         }
 
         // then we get the name of the root module
-        String rootModuleName = getModuleNameChecked(rootFileName, false);
+        String rootModuleName = SpecWriterUtilities.getModuleNameChecked(rootFileName, false);
         if (rootModuleName == null)
         {
             return null;
@@ -1808,7 +1711,7 @@ public class ResourceHelper {
         {
             return null;
         }
-        List<String> listOfImportedModules = pds.getListOfExtendedModules(rootModuleName + ".tla");
+        List<String> listOfImportedModules = pds.getListOfExtendedModules(rootModuleName + TLAConstants.Files.TLA_EXTENSION);
 
         // Then we put them in an array and sort them.
         String[] value = new String[listOfImportedModules.size() + 1];
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/UIHelper.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/UIHelper.java
index b0066f5fc5e422164726e3ceb7ada4b1a6bb63ea..afa10a7fb87f4d5de5e688ca0ce9a8a1c4f54c8b 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/UIHelper.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/UIHelper.java
@@ -103,6 +103,7 @@ import tla2sany.semantic.SymbolNode;
 import tla2sany.semantic.TheoremNode;
 import tla2sany.semantic.ThmOrAssumpDefNode;
 import tla2sany.st.Location;
+import util.TLAConstants;
 
 /**
  * A Helper for handling the RCP Objects like windows, editors and views
@@ -621,7 +622,8 @@ public class UIHelper {
 		if (references != null) {
 			for (int i = 0; i < references.length; i++) {
 				try {
-					if (references[i].isDirty() && references[i].getEditorInput().getName().endsWith(".tla")) {
+					if (references[i].isDirty()
+							&& references[i].getEditorInput().getName().endsWith(TLAConstants.Files.TLA_EXTENSION)) {
 						dirtyEditors.add(references[i]);
 					}
 				} catch (PartInitException e) {
@@ -691,8 +693,12 @@ public class UIHelper {
 			// to not prompt the user to overwrite a file because
 			// that would not make any sense in an open file dialog.
 			openFileDialog.setOverwrite(false);
+		} else if (Platform.getOS().equals(Platform.OS_LINUX)) {
+			// SWT.SAVE allows to create files on Gtk3.x (without I couldn't create files on
+			// Ubuntu 18.04)?!
+			openFileDialog = new FileDialog(shell, SWT.OPEN | SWT.SAVE);
 		} else {
-			// On other platforms, an open dialog is sufficient as it
+			// On Windows, an open dialog is sufficient as it
 			// supports opening existing as well as creating new files.
 			openFileDialog = new FileDialog(shell, SWT.OPEN);
 		}
@@ -920,7 +926,7 @@ public class UIHelper {
 						try {
 							if (jumpToPCal) {
 								final TLAtoPCalMapping mapping = ToolboxHandle.getCurrentSpec().getTpMapping(
-										location.source() + ".tla");
+										location.source() + TLAConstants.Files.TLA_EXTENSION);
 								if (mapping != null) {
 									final Region pCalRegion = AdapterFactory.jumptToPCal(mapping, location, document);
 									if (pCalRegion != null) {
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/IPreferenceConstants.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/IPreferenceConstants.java
index 24a8227a3ae92d3e08848cfe37197a325775e63e..a46ca7d689a0363a258f72c7889d11faa9fa99cd 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/IPreferenceConstants.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/IPreferenceConstants.java
@@ -1,18 +1,15 @@
 package org.lamport.tla.toolbox.util.pref;
 
 /**
- *
  * @author zambrovski
  */
-public interface IPreferenceConstants
-{
-    public static final String DEFAULT_NOT_SET                = "not set";
-
+public interface IPreferenceConstants {
+    public static final String DEFAULT_NOT_SET              = "not set";
     
     /**
      * Project preference storing the root file
      */
-    public static final String P_PROJECT_ROOT_FILE      = "ProjectRootFile";
+    public static final String P_PROJECT_ROOT_FILE          = "ProjectRootFile";
     /**
      * Popup parser errors
      */
@@ -29,7 +26,7 @@ public interface IPreferenceConstants
      * The minimum amount of storage used by the spec (in kbytes) for that
      * size to be displayed (on the bottom line, next to the parse status).
      */
-    public static final String I_MIN_DISPLAYED_SIZE          = "minDisplayedSize";
+    public static final String I_MIN_DISPLAYED_SIZE         = "minDisplayedSize";
     /**
      * Re-parse root on modify
      */
@@ -53,4 +50,11 @@ public interface IPreferenceConstants
     
     /** Resource persistent property for sticking the pcal call params */
     public static final String PCAL_CAL_PARAMS              = "pCalCallParams";
+    
+    /** Folding of the PlusCal algorithm block */
+    public static final String I_FOLDING_PCAL_ALGORITHM     = "foldingPCalAlg";
+    /** Folding of the translated PlusCal TLA+ block */
+    public static final String I_FOLDING_PCAL_TRANSLATED    = "foldingPCalTranslated";
+    /** Folding of block comments */
+    public static final String I_FOLDING_BLOCK_COMMENTS     = "foldingBlockComments";
 }
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/PreferenceInitializer.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/PreferenceInitializer.java
index d42d21aebe2f25459d8305283a1617a2afb63760..bb0b14d5f17bcef3f5a47bc1d56f29437af2634a 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/PreferenceInitializer.java
+++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/PreferenceInitializer.java
@@ -8,16 +8,12 @@ import org.lamport.tla.toolbox.ui.preference.GeneralPreferencePage;
 /**
  * Class used to initialize default preference values.
  */
-public class PreferenceInitializer extends AbstractPreferenceInitializer
-{
-
+public class PreferenceInitializer extends AbstractPreferenceInitializer {
     /**
      * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences()
      */
-    public void initializeDefaultPreferences()
-    {
-
-        IPreferenceStore store = PreferenceStoreHelper.getInstancePreferenceStore();
+	public void initializeDefaultPreferences() {
+        final IPreferenceStore store = PreferenceStoreHelper.getInstancePreferenceStore();
         store.setDefault(IPreferenceConstants.I_PARSER_POPUP_ERRORS, true); // set to true by LL on 22 Sep 2009
 
         // instance based properties
@@ -42,7 +38,7 @@ public class PreferenceInitializer extends AbstractPreferenceInitializer
 
         store.setDefault(EditorPreferencePage.EDITOR_ADD_MODIFICATION_HISTORY,
                 EditorPreferencePage.EDITOR_ADD_MODIFICATION_HISTORY_DEFAULT);
-              
+
         /*
          * Set default for Renumber Proof command option.
          */
@@ -50,6 +46,8 @@ public class PreferenceInitializer extends AbstractPreferenceInitializer
         		EditorPreferencePage.ALL_NAMES);
         store.setDefault(EditorPreferencePage.SAVE_MODULE, true);
         
+        store.setDefault(IPreferenceConstants.I_FOLDING_BLOCK_COMMENTS, false);
+        store.setDefault(IPreferenceConstants.I_FOLDING_PCAL_ALGORITHM, false);
+        store.setDefault(IPreferenceConstants.I_FOLDING_PCAL_TRANSLATED, false);
     }
-
 }
diff --git a/pom.xml b/pom.xml
index b80cee85fb7025aaf11d94e86ecf209ef10dd892..86a1e7295614f3b1ba0258a8bd16e04c5648fc3c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -92,24 +92,24 @@
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 
 		<!-- https://wiki.eclipse.org/Tycho/Release_Notes/1.4 -->
-		<tycho-version>1.4.0</tycho-version>
+		<tycho-version>1.5.0</tycho-version>
 
 		<!-- no default here -->
 		<tycho.test.vm.argline>-Xmx500m -Xdebug -Xrunjdwp:transport=dt_socket,address=1044,server=y,suspend=n</tycho.test.vm.argline>
 		<tycho.test.vm.useUiThread>false</tycho.test.vm.useUiThread>
 
         <!-- These properties define a dummy certificate store that is used unless the developer passes overwrites to maven -->
-        <!-- see http://stackoverflow.com/a/3620575 for how such an overwrite would look like. -->  
+        <!-- see http://stackoverflow.com/a/3620575 for how such an overwrite would look like. -->
   	    <keystore.path>${project.basedir}/../keystore</keystore.path>
 	    <keystore.alias>msr</keystore.alias>
         <keystore.store.password>secret</keystore.store.password>
         <keystore.key.password>secret</keystore.key.password>
-        <!-- 
-          Set to the values below if the signature should include a timestamp. You want this for a release build 
+        <!--
+          Set to the values below if the signature should include a timestamp. You want this for a release build
           because a timestamp makes sure the signature remains valid after the certificate expired.
           If you activate RFC3161, make sure the machine running the build has sufficient entropy available. Otherwise
           expect to see intermittent hangs when the build attempts to sign a jar. On Linux the haveged and rng-tools
-          can help to collect entropy. 
+          can help to collect entropy.
           <tsa.flag>-tsa</tsa.flag>
           <tsa.server>http://timestamp.comodoca.com</tsa.server>
 		 -->
@@ -119,23 +119,23 @@
 		<!-- Report into the tlaplus organization at SonarQube. -->
 		<!-- Organizations support reporting different branches. -->
 		<sonar.organization>tlaplus</sonar.organization>
-		
-		<!-- Align toolbox.version with the version in 
+
+		<!-- Align toolbox.version with the version in
 			 org.lamport.tla.toolbox.product.product.product
 			 product.version. -->
-		<toolbox.version>1.6.0</toolbox.version>
+		<toolbox.version>1.6.1</toolbox.version>
 
 		<!-- This is used in org.lamport.tla.toolbox.product.uitest but
 			has been placed at the top level should it need be referenced
 			in other POMs. This property is only referenced during the AUT
 			unpacking if it is occurring on mac - the AUT unpacks out of
 			the ZIP ok on Linux and Windows-->
-		<jdk-bundle-plugin-version>11.0.3.1</jdk-bundle-plugin-version>
+		<jdk-bundle-plugin-version>13.0.1.3</jdk-bundle-plugin-version>
 	</properties>
 
 	<build>
 		<plugins>
-			<!-- Fail the build early and with a clear error message if the Java 11 
+			<!-- Fail the build early and with a clear error message if the Java 11
 				dependency isn't satisfied. https://github.com/tlaplus/tlaplus/issues/278 -->
 		    <plugin>
 				<groupId>org.apache.maven.plugins</groupId>
@@ -228,8 +228,8 @@
 				        <keypass>${keystore.key.password}</keypass>
 			           	<verbose>false</verbose>
 			           	<arguments>
-			 			  <!-- Embed a current timestamp in the signed content (file). With this timestamp, 
-							the signature of the content remains valid *after* the signing certificate 
+			 			  <!-- Embed a current timestamp in the signed content (file). With this timestamp,
+							the signature of the content remains valid *after* the signing certificate
 							expired. -->
 			              <argument>${tsa.flag}</argument>
 			              <argument>${tsa.server}</argument>
@@ -253,8 +253,8 @@
 					<!-- recommended: use p2-based target platform resolver -->
 					<resolver>p2</resolver>
 					<ignoreTychoRepositories>true</ignoreTychoRepositories>
-					<!-- Include the pack200 artifacts in the p2 repository. This increases 
-						the size of the p2 repository (jars + pack.gz), but reduces the load on the 
+					<!-- Include the pack200 artifacts in the p2 repository. This increases
+						the size of the p2 repository (jars + pack.gz), but reduces the load on the
 						server hosting the repository as clients download the compressed pack.gz files. -->
 					<includePackedArtifacts>true</includePackedArtifacts>
 					<!-- use existing target platform definition -->
@@ -266,13 +266,13 @@
 					    <classifier>TLAToolbox</classifier>
 					 </artifact>
 					</target>
-					
+
 					<!-- Need to specify mininum Java version. This defines what
 					     java.* packages are available during dependency resolution.
 					     Java 1.4, e.g. does not come with "java.security.sasl", a
 					     package that is indirectly referenced by the toolbox (indirectly via
 					     org.apache.mina.core).
-					     see http://dev.eclipse.org/mhonarc/lists/cbi-dev/msg00166.html --> 
+					     see http://dev.eclipse.org/mhonarc/lists/cbi-dev/msg00166.html -->
 		 			<executionEnvironment>JavaSE-11</executionEnvironment>
 
 					<!-- configure the p2 target environments for multi-platform build -->
@@ -325,4 +325,3 @@
 		</profile>
 	</profiles>
 </project>
-
diff --git a/tlatools/.classpath b/tlatools/.classpath
index 4f732359a13d10f057d453de21402b3568383dde..af7fe93b8e8c46dccdd67e1df4ebf45458fdefc9 100644
--- a/tlatools/.classpath
+++ b/tlatools/.classpath
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
 		<attributes>
 			<attribute name="module" value="true"/>
 		</attributes>
diff --git a/tlatools/.settings/org.eclipse.jdt.core.prefs b/tlatools/.settings/org.eclipse.jdt.core.prefs
index eca77e2d236b4ea62572ace58ec574b5687412c2..b17a04a86a31280939bd38107722182912f58e5d 100644
--- a/tlatools/.settings/org.eclipse.jdt.core.prefs
+++ b/tlatools/.settings/org.eclipse.jdt.core.prefs
@@ -9,7 +9,7 @@ org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
 org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.compliance=11
 org.eclipse.jdt.core.compiler.debug.lineNumber=generate
 org.eclipse.jdt.core.compiler.debug.localVariable=generate
 org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -23,6 +23,7 @@ org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
 org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
 org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
 org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
 org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
@@ -66,6 +67,7 @@ org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=igno
 org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
 org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
 org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
 org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
 org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
 org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
@@ -98,5 +100,5 @@ org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
 org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
 org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
 org.eclipse.jdt.core.compiler.processAnnotations=enabled
-org.eclipse.jdt.core.compiler.release=disabled
-org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
diff --git a/tlatools/META-INF/MANIFEST.MF b/tlatools/META-INF/MANIFEST.MF
index dca81d29abbdfbbb2b9df9550fbb274473074dcd..74de04aeca0d4d8ec85c1c5faec1483f3941b356 100644
--- a/tlatools/META-INF/MANIFEST.MF
+++ b/tlatools/META-INF/MANIFEST.MF
@@ -17,6 +17,7 @@ Export-Package: pcal,
  tla2sany.utilities,
  tla2tex,
  tlc2,
+ tlc2.model,
  tlc2.module,
  tlc2.output,
  tlc2.pprint,
@@ -37,7 +38,8 @@ Export-Package: pcal,
  tlc2.value,
  util
 Bundle-Vendor: Leslie Lamport, Markus Alexander Kuppe
-Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-RequiredExecutionEnvironment: JavaSE-11,
+ JavaSE-1.8
 Eclipse-BundleShape: dir
 Require-Bundle: org.aspectj.runtime;bundle-version="1.6.0";resolution:=optional;x-installation:=greedy,
  org.junit;bundle-version="4.12.0";resolution:=optional;x-installation:=greedy,
diff --git a/tlatools/build.properties b/tlatools/build.properties
index b96419813482e94c4ff0d8e530b7887a0c52db61..06d8afaaaa5f8d1144de1907d762b14f8892112c 100644
--- a/tlatools/build.properties
+++ b/tlatools/build.properties
@@ -3,6 +3,3 @@ source.. = src/,\
 bin.includes = META-INF/,\
                .
 output.. = class/
-jre.compilation.profile = JavaSE-1.8
-javacSource = 1.8
-javacTarget = 1.8
diff --git a/tlatools/customBuild.xml b/tlatools/customBuild.xml
index 4234ab78838b63aac8f5d87f597f250cb5a441d2..406392cb1e91114f828c8977777ef4339c18a099 100644
--- a/tlatools/customBuild.xml
+++ b/tlatools/customBuild.xml
@@ -249,7 +249,7 @@
 			</patternset>
 		</unzip>
 		<touch file="target/classes/META-INF/javamail.default.address.map"/>
-
+		
 
 		<!-- create a JAR file for the users -->
 		<mkdir dir="${dist.dir}" />
@@ -285,6 +285,7 @@
 				<!-- The jar files contains many main classes (SANY, TEX, pcal, ...) --> 
                 <!-- but lets consider TLC the one users primarily use. --> 
 				<attribute name="Main-class" value="tlc2.TLC" />
+				<attribute name="Class-Path" value="CommunityModules.jar" />
 				<!-- Git revision -->
 				<attribute name="X-Git-Branch" value="${git.branch}" />
 				<attribute name="X-Git-Tag" value="${git.tag}" />
@@ -318,6 +319,7 @@
 		<!-- Include auxilliary files when compiling classes. -->
 		<copy todir="${test.class.dir}">
 		   <fileset dir="${test.dir}" includes="**/*.dot"/>
+		   <fileset dir="${test.dir}" includes="**/*.dump"/>
 		</copy>		
 		<!-- copy class.dir to path with whitespace -->
 		<!-- this is required by some tests to make sense -->
@@ -356,14 +358,15 @@
 				<pathelement location="test-model/UserModuleOverrideFromJar.jar" />
 				<pathelement path="${class.dir}" />
 				<pathelement path="${test.class.dir}" />
+				<pathelement path="test-model/" />
 			</classpath>
 			<formatter type="xml" />
-
+
 			<!-- Pass the base path of the tlatools project to unit tests in case they need it to locate TLA+ specs or configs -->
 			<sysproperty key="basedir" value="${basedir}/"/>
 			<sysproperty key="tlc2.tool.fp.FPSet.impl" value="tlc2.tool.fp.OffHeapDiskFPSet"/>
 			<sysproperty key="util.FileUtil.milliseconds" value="true"/>
-			<sysproperty key="tlc2.tool.distributed.TLCWorker.threadCount" value="4"/>
+			<sysproperty key="tlc2.tool.distributed.TLCWorker.threadCount" value="4"/>
 			<!-- The tests below can be tricked into running in a single VM by fiddling with the classloader 
 			     to reload and thus initialize all classes for each tests. -->
 			<batchtest fork="yes" todir="${test.reports}">
@@ -378,6 +381,7 @@
 					<exclude name="tlc2/tool/fp/OffHeapDiskFPSetTest.java"/>
 					<exclude name="tlc2/tool/UserModuleOverrideTest.java" />
 					<exclude name="tlc2/tool/UserModuleOverrideFromJarTest.java" />
+					<exclude name="tlc2/tool/UserModuleOverrideAnnotationTest.java" />
 					
 					<exclude name="**/PCalTest.java" />
 					<exclude name="**/CommonTestCase.java" />
@@ -412,6 +416,11 @@
 					<exclude name="**/SimpleMultiProcTest.java" />
 				</fileset>
 			</batchtest>
+			<batchtest fork="yes" todir="${test.reports}">
+				<fileset dir="${test.dir}">
+					<include name="tlc2/tool/UserModuleOverrideAnnotationTest.java" />
+				</fileset>
+			</batchtest>
 			<batchtest fork="yes" todir="${test.reports}">
 				<fileset dir="${test.dir}">
 					<include name="tlc2/tool/UserModuleOverrideFromJarTest.java" />
@@ -444,12 +453,55 @@
 		<delete dir="${ws.class.dir}" deleteonexit="true"/>
 	</target>
 
+	<!-- Executes a single unit test. -->
+	<target name="test-single" unless="test.skip">
+		<!-- run junit test -->
+		<junit printsummary="yes" haltonfailure="true" showoutput="no" haltonerror="true" forkmode="perTest" fork="yes">
+			<!-- enable all assertions -->
+			<jvmarg value="-ea"/>
+			<jvmarg value="-XX:MaxDirectMemorySize=512k"/>
+			<jvmarg value="-XX:+UseParallelGC"/>
+			<!-- Uncomment to open a debug port in each forked VM to remote attach your Eclipse at port 1044.
+            <jvmarg value="-Xdebug" />
+	        <jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044" />
+			-->
+			<classpath refid="project.classpath" />
+			<classpath>
+				<pathelement location="lib/junit-4.12.jar" />
+				<pathelement location="lib/hamcrest-core-1.3.jar" />
+				<pathelement location="lib/cglib-nodep-3.1.jar" />
+				<pathelement location="lib/objenesis-2.1.jar" />
+				<pathelement location="lib/easymock-3.3.1.jar" />
+				<pathelement location="lib/javax.mail/mailapi-1.6.3.jar" />
+				<pathelement location="test-model/UserModuleOverrideFromJar.jar" />
+				<pathelement path="${class.dir}" />
+				<pathelement path="${test.class.dir}" />
+				<pathelement path="${test.class.dir}" />
+				<pathelement path="test-model/" />
+			</classpath>
+
+			<!-- Pass the base path of the tlatools project to unit tests in case they need it to locate TLA+ specs or configs -->
+			<sysproperty key="basedir" value="${basedir}/"/>
+			<sysproperty key="tlc2.tool.fp.FPSet.impl" value="tlc2.tool.fp.OffHeapDiskFPSet"/>
+			<sysproperty key="util.FileUtil.milliseconds" value="true"/>
+			<sysproperty key="tlc2.tool.distributed.TLCWorker.threadCount" value="4"/>
+
+			<!-- Print all output of the test to the screen. -->
+			<formatter type="plain" usefile="false" />
+			<!-- Run a single test case specified by its class name, by setting the property 'test.testcase'. -->
+			<test name="${test.testcase}" skipNonTests="true"/>
+		</junit>
+
+		<!-- remove copied class.dir -->
+		<delete dir="${ws.class.dir}" deleteonexit="true"/>
+	</target>
+
 	<!-- Executes accompining unit tests on jar file -->
 	<target name="test-dist" unless="test.skip">
 		<!-- run junit tests on tlatools.jar -->
 		<mkdir dir="${test.reports}/onJar" />
 		<jacoco:coverage destfile="target/code-coverage.exec" includes="pcal.*:tla2sany.*:tla2tex.*:tlc2.*:util.*:org.lamport.*" excludes="com.sun.*:javax.*:**/Tests.*:**/*Test*">
-			<junit printsummary="yes" haltonfailure="${test.halt}" haltonerror="${test.halt}" forkmode="perTest" fork="yes">
+			<junit printsummary="yes" haltonfailure="${test.halt}" haltonerror="${test.halt}" forkmode="perTest" fork="yes">
 				<!-- enable all assertions -->
 				<jvmarg value="-ea"/>
 				<jvmarg value="-XX:MaxDirectMemorySize=512k"/>
@@ -463,6 +515,7 @@
 					<pathelement location="lib/easymock-3.3.1.jar" />
 					<pathelement location="${dist.file}" />
 					<pathelement path="${test.class.dir}" />
+					<pathelement path="test-model/" />
 					<pathelement location="test-model/UserModuleOverrideFromJar.jar" />
 				</classpath>
 	
@@ -484,7 +537,8 @@
 						<exclude name="tlc2/tool/fp/OffHeapDiskFPSetTest.java"/>
 						<exclude name="tlc2/tool/UserModuleOverrideTest.java" />
 						<exclude name="tlc2/tool/UserModuleOverrideFromJarTest.java" />
-						
+						<exclude name="tlc2/tool/UserModuleOverrideAnnotationTest.java" />
+												
 						<exclude name="**/PCalTest.java" />
 						<exclude name="**/CommonTestCase.java" />
 						<exclude name="**/ModelCheckerTestCase.java" />
@@ -518,6 +572,11 @@
 						<exclude name="**/SimpleMultiProcTest.java" />
 					</fileset>
 				</batchtest>
+				<batchtest fork="yes" todir="${test.reports}">
+					<fileset dir="${test.dir}">
+						<include name="tlc2/tool/UserModuleOverrideAnnotationTest.java" />
+					</fileset>
+				</batchtest>
 				<batchtest fork="yes" todir="${test.reports}">
 					<fileset dir="${test.dir}">
 						<include name="tlc2/tool/UserModuleOverrideFromJarTest.java" />
@@ -662,7 +721,7 @@
 			</classpath>
 		</javac>
 
-		<!-- Build benchmark jar which includes third-party deps, TLC proper (without tests) and the benchmark files compiled in the previous step. -->
+		<!-- Build benchmark jar which includes third-party deps, TLC proper (including tests bc of tlc2.tool.TLCStates.createDummyState) and the benchmark files compiled in the previous step. -->
 		<delete file="target/benchmarks.jar" />
 		<jar jarfile="target/benchmarks.jar" basedir="target/benchmark/">
 			<manifest>
@@ -670,6 +729,7 @@
 			</manifest>
 <!--			<zipfileset dir="${src.dir}" includes="**/*.java" />-->
 			<fileset dir="${class.dir}" includes="**/*" />
+			<fileset dir="${test.class.dir}" includes="**/*" />
 			<zipfileset src="lib/jmh/jmh-core-1.21.jar" excludes="**/META-INF/services/**" />
 			<zipfileset src="lib/jmh/jopt-simple-4.6.jar" />
 			<zipfileset src="lib/jmh/commons-math3-3.2.jar" />
diff --git a/tlatools/doc/License.txt b/tlatools/doc/License.txt
index b7894bc47219e78b13a9923649f067bbb09d2cde..c8f71de5d088dc159f4b482904901e938538598c 100644
--- a/tlatools/doc/License.txt
+++ b/tlatools/doc/License.txt
@@ -1,109 +1,21 @@
-
-1)  Where the following copyright notice appears:
-
-Copyright (c) 2003 Compaq Corporation.  All rights reserved.  
-
-Portions Copyright (c) 2003 Microsoft Corporation.  All rights reserved.  or
-
-Copyright (c) 2003 Microsoft Corporation. All rights reserved.
-
-that code is licensed as follows:   
-
-This Microsoft Research end user license agreement ("MSR-EULA") is a
-legal agreement between you and Microsoft Corporation
-("Microsoft" or "we") for the software identified above,
-which includes source code, and any associated materials and "online"
-or electronic documentation (together, the "Software").
-
-By installing, copying, or otherwise using the Software, found at
-http://research.microsoft.com/downloads, you agree to be bound by the
-terms of this MSR-EULA. If you do not agree, do not install, copy or
-use the Software. The Software is protected by copyright and other
-intellectual property laws and is licensed, not sold.
-
-Upon your agreement to the terms below, you may do anything you want
-with the Software source code for research, teaching purposes, or
-internal use, free of charge, provided that you agree to the
-following:
-
-(a) To leave in place all copyright notices and licensing information
-that you might find in the Software.
-
-(b) That you will not use the Software in a live operating environment
-where it may be relied upon to perform in the same manner as a
-commercially released product, or with data that has not been
-sufficiently backed up.
-
-(c) That any feedback about the Software provided by you to us is
-voluntarily given, and Microsoft shall be free to use the feedback as
-it sees fit without obligation or restriction of any kind, even if the
-feedback is designated by you as confidential.
-
-(d) To make freely available to others the source code or data of any
-modifications or additions you make to the Software, and any related
-documentation, solely and exclusively under the same terms as this
-License.
-
-(e) That Microsoft is granted back, without limitations, the rights to
-reproduce, install, use, modify, distribute and transfer your
-modifications to the Software source code or data.
-
-(f) NO WARRANTIES WHATSOEVER: That the Software comes "AS IS",
-with all faults and with no warranties, conditions or
-representations. The implied warranties of merchantability and fitness
-for a particular purpose, and any warranty against interference with
-your enjoyment of the Software or against infringement, do not apply
-to the Software.  The entire risk as to satisfactory quality,
-performance, accuracy, and effort concerning the Software is assumed
-by you.  There is no warranty that this Software will fulfill any of
-your particular purposes or needs.
-
-(g) That we have no duty of reasonable care or lack of negligence, and
-we are not obligated to (and will not) provide technical support for
-the Software.
-
-(h) That we will not be liable for any damages, including those known
-as direct, indirect, special, consequential, or incidental damages
-related to the Software, this MSR-EULA, or under any legal theory
-(such as negligence), to the maximum extent that overriding applicable
-law permits.
-
-(i) That if you sue or threaten to sue anyone over patents that you
-think may apply to the Software, or if you breach this MSR-EULA in any
-way, your license to the Software ends automatically.
-
-(j) That this MSR-EULA shall be construed and controlled by the laws
-of the State of Washington, USA, without regard to conflicts of law.
-
-
-2) Where the following copyright notice appears: Copyright (c) 2003
-Compaq Corporation.  All rights reserved.
-
-that code is licensed as follows:
-Compaq Computer Corporation, a Delaware corporation with offices at
-20555 SH 249, Houston, TX, (COMPAQ) and you the CUSTOMER agree as
-follows:
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL COMPAQ BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
-THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of COMPAQ shall not be
-used in advertising or otherwise to promote the sale, use or other
-dealings in this Software without prior written authorization from
-COMPAQ.
+Copyright (c) 2019 Microsoft Research. All rights reserved.
+
+The MIT License (MIT)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/tlatools/doc/TraceExplorer_README.txt b/tlatools/doc/TraceExplorer_README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..41afc32e81f6bd94f7e2b0523f259a449c3d6a46
--- /dev/null
+++ b/tlatools/doc/TraceExplorer_README.txt
@@ -0,0 +1,78 @@
+As of December 2019, the tlatools ship with the TraceExplorer command line application.
+
+The current usage of this is as follows; this usage text can also be seen by invoking the application (tla2.TraceExplorer) with no arguments:
+
+	To generate a SpecTE file pair:
+			java tlc2.TraceExplorer -generateSpecTE \
+				[-source=_directory_containing_prior_run_output_] \
+				[-overwrite] \
+				SpecName
+		o source defaults to CWD if not specified.
+		o if a SpecTE.tla already exists and overwrite is not specified, execution will halt.
+		o if no SpecName is specified, output will be expected to arrive via stdin; -source will be ignored in this case.
+
+	To pretty print the error states of a previous run:
+			java tlc2.TraceExplorer -prettyPrint \
+				[-source=_directory_containing_prior_run_output_] \
+				SpecName
+		o source defaults to CWD if not specified.
+		o if no SpecName is specified, output will be expected to arrive via stdin; -source will be ignored in this case.
+
+
+------------------------------------------------------------------------------------
+
+An example of the pretty print output is:
+
+algebraic:Model_1_SnapShot_1576778796288 loki$ java ... tlc2.TraceExplorer -prettyPrint -source=/Users/loki/arbeit/microsoft/dev/tlaplus/runtime-org.lamport.tla.toolbox.product.product.product/Queens/Queens.toolbox/FourQueens/
+ <Initial predicate>
+	/\  todo = {<<>>}
+	/\  sols = {}
+
+ <PlaceQueen line 50, col 15 to line 62, col 26 of module Queens>
+	/\  todo = {<<1>>, <<2>>, <<3>>}
+	/\  sols = {}
+
+ <PlaceQueen line 50, col 15 to line 62, col 26 of module Queens>
+	/\  todo = {<<2>>, <<3>>, <<1, 3>>}
+	/\  sols = {}
+
+ <PlaceQueen line 50, col 15 to line 62, col 26 of module Queens>
+	/\  todo = {<<3>>, <<1, 3>>}
+	/\  sols = {}
+
+ <PlaceQueen line 50, col 15 to line 62, col 26 of module Queens>
+	/\  todo = {<<1, 3>>, <<3, 1>>}
+	/\  sols = {}
+
+ <PlaceQueen line 50, col 15 to line 62, col 26 of module Queens>
+	/\  todo = {<<3, 1>>}
+	/\  sols = {}
+
+ <PlaceQueen line 50, col 15 to line 62, col 26 of module Queens>
+	/\  todo = {}
+	/\  sols = {}
+
+algebraic:Model_1_SnapShot_1576778796288 loki$ 
+
+------------------------------------------------------------------------------------
+
+An example of a piped run from TLC:
+
+algebraic:FourQueens loki$ /Library/Java/JavaVirtualMachines/adoptopenjdk-13.jdk/Contents/Home/bin/java -XX:MaxDirectMemorySize=5460m -Xmx2732m -Dtlc2.tool.fp.FPSet.impl=tlc2.tool.fp.OffHeapDiskFPSet -XX:+UseParallelGC -Dfile.encoding=UTF-8 -classpath /Users/loki/arbeit/microsoft/dev/tlaplus/git/tlaplus/tlatools:/Users/loki/arbeit/microsoft/dev/tlaplus/git/tlaplus/tlatools/lib/*:/Users/loki/arbeit/microsoft/dev/tlaplus/git/tlaplus/tlatools/lib/javax.mail/*:/Users/loki/arbeit/microsoft/dev/tlaplus/git/tlaplus/tlatools/class tlc2.TLC -fpbits 1 -fp 4 -config MC.cfg -coverage 3 -workers 1 -tool -metadir /Users/loki/arbeit/microsoft/dev/tlaplus/runtime-org.lamport.tla.toolbox.product.product.product/Queens/Queens.toolbox/FourQueens MC | /Library/Java/JavaVirtualMachines/adoptopenjdk-13.jdk/Contents/Home/bin/java -XX:+UseParallelGC -Dfile.encoding=UTF-8 -classpath /Users/loki/arbeit/microsoft/dev/tlaplus/git/tlaplus/tlatools:/Users/loki/arbeit/microsoft/dev/tlaplus/git/tlaplus/tlatools/lib/*:/Users/loki/arbeit/microsoft/dev/tlaplus/git/tlaplus/tlatools/lib/javax.mail/*:/Users/loki/arbeit/microsoft/dev/tlaplus/git/tlaplus/tlatools/class tlc2.TraceExplorer -generateSpecTE
+Parsing file /Users/loki/arbeit/microsoft/dev/tlaplus/runtime-org.lamport.tla.toolbox.product.product.product/Queens/Queens.toolbox/FourQueens/MC.tla
+Parsing file /Users/loki/arbeit/microsoft/dev/tlaplus/runtime-org.lamport.tla.toolbox.product.product.product/Queens/Queens.toolbox/FourQueens/Queens.tla
+Parsing file /Users/loki/arbeit/microsoft/dev/quaeler_repo/tlaplus/tlatools/class/tla2sany/StandardModules/TLC.tla
+Parsing file /Users/loki/arbeit/microsoft/dev/quaeler_repo/tlaplus/tlatools/class/tla2sany/StandardModules/Naturals.tla
+Parsing file /Users/loki/arbeit/microsoft/dev/quaeler_repo/tlaplus/tlatools/class/tla2sany/StandardModules/Sequences.tla
+Parsing file /Users/loki/arbeit/microsoft/dev/quaeler_repo/tlaplus/tlatools/class/tla2sany/StandardModules/FiniteSets.tla
+Semantic processing of module Naturals
+Semantic processing of module Sequences
+Semantic processing of module Queens
+Semantic processing of module FiniteSets
+Semantic processing of module TLC
+Semantic processing of module MC
+Starting... (2019-12-22 12:56:00)
+The file /Users/loki/arbeit/microsoft/dev/tlaplus/runtime-org.lamport.tla.toolbox.product.product.product/Queens/Queens.toolbox/FourQueens/SpecTE.tla has been created.
+The file /Users/loki/arbeit/microsoft/dev/tlaplus/runtime-org.lamport.tla.toolbox.product.product.product/Queens/Queens.toolbox/FourQueens/SpecTE.cfg has been created.
+algebraic:FourQueens loki$ 
+
diff --git a/tlatools/javacc/TLAplusParser.java b/tlatools/javacc/TLAplusParser.java
index eec70becf90a22bf8545358dd1bc857d1d34d025..dde171b77bd0bcc5c7119fd33d24f256342c93ed 100644
--- a/tlatools/javacc/TLAplusParser.java
+++ b/tlatools/javacc/TLAplusParser.java
@@ -8,6 +8,7 @@ import tlc2.output.EC;
 import tla2sany.utilities.Vector;
 import tla2sany.utilities.Stack;
 import util.Assert;
+import util.TLAConstants;
 import util.UniqueString;
 import util.ToolIO;
 
@@ -1645,7 +1646,7 @@ Token t;
   SyntaxTreeNode tn, sn[];
   Token t;
   bpa("Parameter declaration");
-  expecting = "CONSTANT";
+  expecting = TLAConstants.KeyWords.CONSTANT;
     tn = ParamSubDecl();
                          addHeir(tn);
  expecting = "Identifier, operator or _";
diff --git a/tlatools/ossrh.xml b/tlatools/ossrh.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1b39a509acb6ab9a7604b46c44a1b5e2d42943b4
--- /dev/null
+++ b/tlatools/ossrh.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+	xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>org.sonatype.oss</groupId>
+		<artifactId>oss-parent</artifactId>
+		<version>9</version>
+		<relativePath>../do-not-reference-our-parent-pom</relativePath>
+	</parent>
+
+	<!-- The settings below have been duplicated from ../pom.xml because the 
+		Toolbox - among other things - uses a different groupId for historical reasons. -->
+
+	<groupId>org.lamport</groupId>
+	<artifactId>tla2tools</artifactId>
+	<name>TLA+ Tools</name>
+	<version>1.6.1-SNAPSHOT</version>
+	<description>The TLC model checker, the syntax and semantic checker SANY, the PlusCal translator, and the LaTeX pretty printer.</description>
+	<packaging>jar</packaging>
+
+	<organization>
+		<name>Microsoft Research Inria Joint Centre</name>
+		<url>http://msr-inria.inria.fr/</url>
+	</organization>
+
+	<licenses>
+		<license>
+			<name>MIT License</name>
+			<url>http://www.opensource.org/licenses/mit-license.php</url>
+		</license>
+	</licenses>
+
+	<issueManagement>
+		<system>GitHub</system>
+		<url>https://github.com/tlaplus/tlaplus/issues</url>
+	</issueManagement>
+
+	<scm>
+		<connection>scm:git:https://github.com/tlaplus/tlaplus</connection>
+		<developerConnection>scm:git:https://github.com/tlaplus/tlaplus</developerConnection>
+		<tag>HEAD</tag>
+	</scm>
+
+	<distributionManagement>
+		<snapshotRepository>
+			<id>ossrh</id>
+			<url>https://oss.sonatype.org/content/repositories/snapshots</url>
+		</snapshotRepository>
+		<repository>
+			<id>ossrh</id>
+			<url>https://oss.sonatype.org/service/local/staging/deploy/maven2</url>
+		</repository>
+	</distributionManagement>
+
+	<dependencies>
+		<dependency>
+			<groupId>com.sun.mail</groupId>
+			<artifactId>mailapi</artifactId>
+			<version>1.6.3</version>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>4.12</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.easymock</groupId>
+			<artifactId>easymock</artifactId>
+			<version>2.4</version>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-gpg-plugin</artifactId>
+				<version>1.6</version>
+				<executions>
+					<execution>
+						<id>sign-artifacts</id>
+						<phase>verify</phase>
+						<goals>
+							<goal>sign</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+</project>
+
diff --git a/tlatools/ossrh.xml.README b/tlatools/ossrh.xml.README
new file mode 100644
index 0000000000000000000000000000000000000000..9e7f08f253b96c6a38d5ace59571857f77a1fae0
--- /dev/null
+++ b/tlatools/ossrh.xml.README
@@ -0,0 +1,47 @@
+Maven Central is the canonical repository for Java libraries.  To allow
+users to build software on top of tla2tools.jar, we publish tla2tools.jar 
+to Maven Central.  Users have asked us to do this [1].  Moreover, our 
+own Apalache [2] will find this useful [3].
+
+We initially had to claim [4] the org.lamport namespace to be allowed to 
+publish tla2tools.jar into it.  The artifacts are available online [5]
+and so far we have only pushed snapshots.
+
+[1] https://groups.google.com/forum/#!msg/tlaplus/xzmsu6qRMyo/YGgRNFE1CAAJ
+[2] https://github.com/konnov/apalache
+[3] https://github.com/konnov/apalache/issues/48
+[4] https://issues.sonatype.org/browse/OSSRH-50021
+[5] https://oss.sonatype.org/content/repositories/snapshots/org/lamport/
+
+Manually deploy tla2tools.jar
+-----------------------------
+
+1) Strip javax/ directory from tla2tools.jar built with regular customBuild.xml.
+   The version of tla2tools.jar - that we will upload to MC - will declare its
+   dependencies to javax packages instead of bundling them.
+
+zip -d dist/tla2tools.jar \
+  javax/\* \
+  com/\* \
+  META-INF/mailcap \
+  META-INF/javamail*
+   
+2) Upload to Maven Central (credentials have to be set in ~/.m2/settings.xml).
+
+mvn gpg:sign-and-deploy-file \
+ -Durl=https://oss.sonatype.org/content/repositories/snapshots \
+ -DrepositoryId=ossrh \
+ -DpomFile=ossrh.xml \
+ -Dfile=dist/tla2tools.jar
+
+
+Background material:
+* <https://central.sonatype.org/pages/manual-staging-bundle-creation-and-deployment.html>
+  * Credentials are the login details for Maven Central (OSSRH)
+* What is wrong when deploy returns a 400 bad request response: <https://stackoverflow.com/a/18702353/6291195>
+
+Delete existing/old artifacts
+-----------------------------
+
+1) Login to the OSSRH web front-end <https://oss.sonatype.org/index.html>
+2) Follow steps outlined in: <https://issues.sonatype.org/browse/OSSRH-776?focusedCommentId=117817&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-117817>
diff --git a/tlatools/pom.xml b/tlatools/pom.xml
index 2c306879d369b4f6d461a4483750a2c87024aa26..c1506b64c3b0c0c1eb731feecd9e842bec85d77d 100644
--- a/tlatools/pom.xml
+++ b/tlatools/pom.xml
@@ -125,6 +125,46 @@
 	        </configuration>
 	      </plugin>
 
+			<!-- Update the Manifest.mf packaged into the OSGi variant of tla2tools.jar 
+				which is embedded in the Toolbox. The standalone tla2tools.jar (see customBuild.xml) 
+				defines various properties in its manifest among which are the git revision 
+				and the implementation title. These two properties are read by TLCGlobals 
+				to determine TLCs revision. This is turn is reported as part of execution statistics.
+				To correctly report the TLC revision when it is launched from inside the Toolbox, the
+				embedded tla2tools.jar created here has to also include the two properties. -->
+			<plugin>
+				<groupId>org.codehaus.mojo</groupId>
+				<artifactId>buildnumber-maven-plugin</artifactId>
+				<version>1.4</version>
+				<executions>
+					<execution>
+						<phase>validate</phase>
+						<goals>
+							<goal>create</goal>
+						</goals>
+					</execution>
+				</executions>
+				<configuration>
+					<getRevisionOnlyOnce>true</getRevisionOnlyOnce>
+				    <shortRevisionLength>7</shortRevisionLength>
+					<doCheck>false</doCheck>
+					<doUpdate>false</doUpdate>
+				</configuration>
+			</plugin>
+      		<plugin>
+				<groupId>org.eclipse.tycho</groupId>
+				<artifactId>tycho-packaging-plugin</artifactId>
+				<version>${tycho-version}</version>
+				<configuration>
+					<archive>
+						<manifestEntries>
+							<Implementation-Title>TLA+ Tools</Implementation-Title>
+							<X-Git-ShortRevision>${buildNumber}</X-Git-ShortRevision>
+						</manifestEntries>
+					</archive>
+				</configuration>
+			</plugin>
+
 			<!-- Compile aspects -->
             <plugin>
                 <!-- https://github.com/nickwongdev/aspectj-maven-plugin -->
diff --git a/tlatools/src/model/InJarFilenameToStream.java b/tlatools/src/model/InJarFilenameToStream.java
index 39f07a222b12497ee02896bf683a98b692b25bc1..e3ff7afc4e65530e2ed1cea9bc1eab948177ac2f 100644
--- a/tlatools/src/model/InJarFilenameToStream.java
+++ b/tlatools/src/model/InJarFilenameToStream.java
@@ -23,7 +23,7 @@ public class InJarFilenameToStream extends SimpleFilenameToStream implements
 		InputStream is = InJarFilenameToStream.class.getResourceAsStream(prefix + name);
 		if(is != null) {
 			try {
-				File sourceFile = new File(TMPDIR + File.separator + name);
+				File sourceFile = new TLAFile(TMPDIR + File.separator + name, this);
 				sourceFile.deleteOnExit();
 				
 				FileOutputStream fos = new FileOutputStream(sourceFile);
diff --git a/tlatools/src/model/ModelInJar.java b/tlatools/src/model/ModelInJar.java
index 7edca84c2eacdae890e5f56e661874b3c54cc9d3..1d51d4ecbc5708bb68e2dea136140045f2c9056a 100644
--- a/tlatools/src/model/ModelInJar.java
+++ b/tlatools/src/model/ModelInJar.java
@@ -9,21 +9,23 @@ import java.nio.file.StandardCopyOption;
 import java.util.Enumeration;
 import java.util.Properties;
 
+import util.TLAConstants;
+
 public abstract class ModelInJar {
 	public static final String PATH = "/model/";
 	
 	public static boolean hasModel() {
-		return ModelInJar.class.getResource("/model/MC.tla") != null;
+		return ModelInJar.class.getResource(PATH + TLAConstants.Files.MODEL_CHECK_TLA_FILE) != null;
 	}
 	
 	public static boolean hasCfg() {
-		return ModelInJar.class.getResource("/model/MC.cfg") != null;
+		return ModelInJar.class.getResource(PATH + TLAConstants.Files.MODEL_CHECK_CONFIG_FILE) != null;
 	}
 
 	public static File getCfg() {
 		try {
-			final InputStream source = ModelInJar.class.getResourceAsStream("/model/MC.cfg");
-			Path target = Files.createTempFile("MC", ".cfg");
+			final InputStream source = ModelInJar.class.getResourceAsStream(PATH + TLAConstants.Files.MODEL_CHECK_CONFIG_FILE);
+			Path target = Files.createTempFile(TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, TLAConstants.Files.CONFIG_EXTENSION);
 			Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
 			return target.toFile();
 		} catch (IOException notExpectedToHappen) {
@@ -32,8 +34,7 @@ public abstract class ModelInJar {
 	}
 	
 	public static boolean loadProperties() {
-		InputStream in = ModelInJar.class
-				.getResourceAsStream("/model/generated.properties");
+		InputStream in = ModelInJar.class.getResourceAsStream(PATH + "generated.properties");
 		if (in != null) {
 			Properties prop = new Properties();
 			try {
diff --git a/tlatools/src/pcal/ParseAlgorithm.java b/tlatools/src/pcal/ParseAlgorithm.java
index 18849103fa924cf6451c5288d1c44bd5fefcebd1..913b348c61815a1d355ef0154f634ed2fbb94a6d 100644
--- a/tlatools/src/pcal/ParseAlgorithm.java
+++ b/tlatools/src/pcal/ParseAlgorithm.java
@@ -3491,20 +3491,17 @@ public class ParseAlgorithm
                             + tok + "\"") ; } ;
      }
 
-   public static void MustGobbleThis(String str) throws ParseAlgorithmException
-     { 
-       String tok;
-    try
-    {
-        tok = GetAlgToken();
-    } catch (ParseAlgorithmException e)
-    {
-        throw new ParseAlgorithmException(e.getMessage());
-    }
-       if (! tok.equals(str) )
-         { PcalDebug.ReportBug("Expected \"" + str + "\" but found \""
-                                 + tok + "\"") ; } ;
-     }
+	public static void MustGobbleThis(final String str) throws ParseAlgorithmException {
+		final String tok;
+		try {
+			tok = GetAlgToken();
+		} catch (ParseAlgorithmException e) {
+			throw new ParseAlgorithmException(e.getMessage());
+		}
+		if (!tok.equals(str)) {
+			ParsingError("Expected \"" + str + "\" but found \"" + tok + "\"");
+		}
+	}
 
    public static boolean GobbleEqualOrIf() throws ParseAlgorithmException
      /**********************************************************************
diff --git a/tlatools/src/pcal/PcalBuiltInSymbols.java b/tlatools/src/pcal/PcalBuiltInSymbols.java
index 0f27eb7d85dc9cf6bd50e9bd7a7c3bdc6d8e8e5f..b3de7693e788b11d5ead668d9178c91c4ccda2cd 100644
--- a/tlatools/src/pcal/PcalBuiltInSymbols.java
+++ b/tlatools/src/pcal/PcalBuiltInSymbols.java
@@ -37,25 +37,26 @@ import java.util.Hashtable;
 
 import tla2tex.Misc;
 import tla2tex.Symbol;
+import util.TLAConstants;
 
 public final class PcalBuiltInSymbols
   { 
     /***********************************************************************
     * The following three hash tables are built by the Initialize method.  *
     ***********************************************************************/
-    private static Hashtable builtInHashTable = new Hashtable(200);
+    private static Hashtable<String, Symbol> builtInHashTable = new Hashtable<>(200);
       /*********************************************************************
       * Maps built-in symbols (which are strings) to their Symbol          *
       * objects.                                                           *
       *********************************************************************/
 
-    private static Hashtable prefixHashTable  = new Hashtable(700);
+    private static Hashtable<String, String> prefixHashTable  = new Hashtable<>(700);
       /*********************************************************************
       * A table containing the prefixes of all built-in symbols.  (It      *
       * holds only their keys.)                                            *
       *********************************************************************/
 
-    private static Hashtable stringCharTable  = new Hashtable(100);
+    private static Hashtable<String, String> stringCharTable  = new Hashtable<>(100);
       /*********************************************************************
       * A table of all the characters that may appear in a TLA+ string     *
       * token.                                                             *
@@ -79,7 +80,7 @@ public final class PcalBuiltInSymbols
       } ;
 
     public static Symbol GetBuiltInSymbol(String str)
-      { return (Symbol) builtInHashTable.get(str);
+      { return builtInHashTable.get(str);
       } ;
 
     public static boolean IsBuiltInPrefix(String str)
@@ -134,20 +135,20 @@ public final class PcalBuiltInSymbols
         add("AXIOM",      "{\\AXIOM}",       Symbol.KEYWORD, 0);
         add("BOOLEAN",    "{\\BOOLEAN}",     Symbol.KEYWORD, 0);
         add("CASE",       "{\\CASE}",        Symbol.KEYWORD, 0);
-        add("CONSTANT",   "{\\CONSTANT}",    Symbol.KEYWORD, 0);
-        add("CONSTANTS",  "{\\CONSTANTS}",   Symbol.KEYWORD, 0);
+        add(TLAConstants.KeyWords.CONSTANT,   "{\\CONSTANT}",    Symbol.KEYWORD, 0);
+        add(TLAConstants.KeyWords.CONSTANTS,  "{\\CONSTANTS}",   Symbol.KEYWORD, 0);
         add("EXCEPT",     "{\\EXCEPT}",      Symbol.KEYWORD, 0);
-        add("EXTENDS",    "{\\EXTENDS}",     Symbol.KEYWORD, 0);
+        add(TLAConstants.KeyWords.EXTENDS,    "{\\EXTENDS}",     Symbol.KEYWORD, 0);
         add("FALSE",      "{\\FALSE}",       Symbol.KEYWORD, 0);
         add("IF",         "{\\IF}",          Symbol.KEYWORD, 0);
         add("INSTANCE",   "{\\INSTANCE}",    Symbol.KEYWORD, 0);
         add("LOCAL",      "{\\LOCAL}",       Symbol.KEYWORD, 0);
-        add("MODULE",     "{\\MODULE}",      Symbol.KEYWORD, 0);
+        add(TLAConstants.KeyWords.MODULE,     "{\\MODULE}",      Symbol.KEYWORD, 0);
         add("OTHER",      "{\\OTHER}",       Symbol.KEYWORD, 0);
         add("STRING",     "{\\STRING}",      Symbol.KEYWORD, 0);
         add("THEOREM",    "{\\THEOREM}",     Symbol.KEYWORD, 0);
         add("TRUE",       "{\\TRUE}",        Symbol.KEYWORD, 0);
-        add("VARIABLE",   "{\\VARIABLE}",    Symbol.KEYWORD, 0);
+        add(TLAConstants.KeyWords.VARIABLE,   "{\\VARIABLE}",    Symbol.KEYWORD, 0);
         add("VARIABLES",  "{\\VARIABLES}",   Symbol.KEYWORD, 0);
         add("WITH",       "{\\WITH}",        Symbol.KEYWORD, 0);
 
@@ -340,9 +341,9 @@ public final class PcalBuiltInSymbols
       * Initializes prefixHashTable, assuming that builtInHashTable is     *
       * already initialized.                                               *
       *********************************************************************/
-      { Enumeration builtInEnum = builtInHashTable.keys();
+      { Enumeration<String> builtInEnum = builtInHashTable.keys();
         while (builtInEnum.hasMoreElements())
-          { String symbol = (String) builtInEnum.nextElement();
+          { String symbol = builtInEnum.nextElement();
             if (    Misc.IsLetter(symbol.charAt(0))
                  ||    (symbol.length() > 1)
                     && (symbol.charAt(0) == '\\')
diff --git a/tlatools/src/pcal/PcalDebug.java b/tlatools/src/pcal/PcalDebug.java
index 87e4933479a4b26ebd7641d140bd1a84a753d906..896e00bb6eda7148da865cd7a2da256d53467f57 100644
--- a/tlatools/src/pcal/PcalDebug.java
+++ b/tlatools/src/pcal/PcalDebug.java
@@ -105,14 +105,15 @@ public class PcalDebug
     * This method is called to report a bug in the program and abort.    *
     *********************************************************************/
     {
+    	final StringBuilder sb = new StringBuilder("You have discovered a bug in pcal.trans.\n");
+        sb.append("Send the following information and the\ninput file to the current maintainer(s).\n\n -- ");
+        sb.append(msg).append(".");
+    	
         ToolIO.out.println("");
-        ToolIO.out.println("You have discovered a bug in pcal.trans.");
-        ToolIO.out.println("Send the following information and the");
-        ToolIO.out.println("input file to the current maintainer(s).");
+        ToolIO.out.println(sb.toString());
         ToolIO.out.println("");
-        ToolIO.out.println(" -- " + msg + ".");
-        ToolIO.out.println("");
-        throw new Error();
+        
+        throw new Error(sb.toString());
     };
 
     public static void printObjectArray(Object[] array, String name)
diff --git a/tlatools/src/pcal/PcalParams.java b/tlatools/src/pcal/PcalParams.java
index 2fc3b9087359b4e9c973cffefd000a5c3b44c0d6..b83937d9a73257838721061f012af9d527efbfb4 100644
--- a/tlatools/src/pcal/PcalParams.java
+++ b/tlatools/src/pcal/PcalParams.java
@@ -183,17 +183,24 @@ public final class PcalParams
     * algorithm in a .tla input file.  The translation is put immediately  *
     * after any line containing                                            *
     *                                                                      *
-    *    BeginXLation1 [one or more spaces] BeginXlation2                  *
+    *    BeginXLation1 [one space] BeginXlation2 [one space] BeginXlation3 *
     *                                                                      *
     * It is followed by a line containing                                  *
     *                                                                      *
-    *    EndXLation1 [one or more spaces] EndXlation2.                     *
+    *    EndXLation1 [one space] EndXlation2 [one space] EndXlation3       *
     ***********************************************************************/
     public static final String BeginXlation1 = "BEGIN" ;
     public static final String BeginXlation2 = "TRANSLATION" ;
+    public static final String BeginXlation3 = "- the hash of the PCal code:" ;
 
     public static final String EndXlation1 = "END" ;
     public static final String EndXlation2 = "TRANSLATION" ;
+    public static final String EndXlation3 = "- the hash of the generated TLA code (remove "
+												+ "to silence divergence warnings):" ;
+    
+    // Checksum marker keywords - introduced as part of https://github.com/tlaplus/tlaplus/issues/296
+    public static final String PCAL_CHECKSUM_KEYWORD = "PCal-";
+    public static final String TRANSLATED_PCAL_CHECKSUM_KEYWORD = "TLA-";
 
   /*************************************************************************
   * The string identifying the end of the automatically generated part of  *
diff --git a/tlatools/src/pcal/PcalTLAGen.java b/tlatools/src/pcal/PcalTLAGen.java
index 9fa7e5f5b6b7c1c5bfa1e0dec10c08eecf2f36ae..45c84dd6b9000818e2fc1d1677776b0b20a042e2 100644
--- a/tlatools/src/pcal/PcalTLAGen.java
+++ b/tlatools/src/pcal/PcalTLAGen.java
@@ -5,6 +5,7 @@ import java.util.Vector;
 import pcal.AST.VarDecl;
 import pcal.exception.PcalTLAGenException;
 import pcal.exception.TLAExprException;
+import util.TLAConstants;
 
 /****************************************************************************
  * Given an exploded and disambiguated AST, generate the equivalent TLA+.
@@ -2041,7 +2042,7 @@ public class PcalTLAGen
         } else
         {
 //            res.append("VARIABLE ");
-            addOneTokenToTLA("VARIABLE ");
+            addOneTokenToTLA(TLAConstants.KeyWords.VARIABLE + " ");
         }
         ;
         for (int i = 0; i < varVec.size(); i++)
@@ -2386,7 +2387,7 @@ public class PcalTLAGen
                             addLeftParen(proc.id.getOrigin());
                             addExprToTLA(proc.id);
                             addRightParen(proc.id.getOrigin());
-                            addOneTokenToTLA(" |-> " );
+                            addOneTokenToTLA(TLAConstants.RECORD_ARROW);
                             addLeftParen(decl.val.getOrigin());
                             addExprToTLA(AddSubscriptsToExpr(
                                            decl.val,
diff --git a/tlatools/src/pcal/Translator.java b/tlatools/src/pcal/Translator.java
index ea3e62a8d3fea48f6ff7e37d52baba0906265a10..ade7335dd052d84c2e0fbaa306203dd795aa1082 100644
--- a/tlatools/src/pcal/Translator.java
+++ b/tlatools/src/pcal/Translator.java
@@ -26,6 +26,7 @@
  ******************************************************************************/
 package pcal;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.Vector;
 import java.util.regex.Matcher;
@@ -62,23 +63,21 @@ public class Translator
      * @return 
      */
 	public boolean translate() {
-		final Vector<String> in = new Vector<String>();
 		// The input .tla file might have unix or windows line ending. If we fail to
 		// properly split the input (a line per array cell), the pcal translator will
 		// silently fail as well.
 		final String[] lines = input.split("\\r?\\n");
-		for (String line : lines) {
-			in.add(line);
-		}
+		final List<String> in = Arrays.asList(lines);
 		
-		final Vector<String> out = trans.runMe(in);
+		final List<String> out = trans.performTranslation(in);
 		if (out != null) {
-			final StringBuffer buf = new StringBuffer(out.size());
-			for (String line : out) {
+			final StringBuilder buf = new StringBuilder();
+			final String lineSeparator = System.getProperty("line.separator");
+			for (final String line : out) {
 				buf.append(line);
 				// The output .tla file will use the OS's line ending which is in line with the
 				// the translator's legacy behavior.
-				buf.append(System.getProperty("line.separator"));
+				buf.append(lineSeparator);
 			}
 			output = buf.toString();
 		}
diff --git a/tlatools/src/pcal/Validator.java b/tlatools/src/pcal/Validator.java
new file mode 100644
index 0000000000000000000000000000000000000000..b42f0d0b9f0337521f53203dadf4ff9e824181c2
--- /dev/null
+++ b/tlatools/src/pcal/Validator.java
@@ -0,0 +1,290 @@
+package pcal;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import pcal.exception.ParseAlgorithmException;
+import util.TLAConstants;
+
+/**
+ * This class validates the recorded checksums generated from an input specification's PlusCal and translated PlusCal
+ * blocks.
+ */
+public class Validator {
+	public enum ValidationResult {
+		/** No PlusCal algorithm exists in the specification */
+		NO_PLUSCAL_EXISTS,
+		
+		/** No translation exists - BUT THERE IS PLUSCAL IN THE SPECIFICATION! */
+		NO_TRANSLATION_EXISTS,
+		
+		/** PlusCal and a translation block exist, but there are no checksums calculated. */
+		NO_CHECKSUMS_EXIST,
+		
+		/** One or both Checksum in the spec do not match the checksums calculated for what was found in the spec. */
+		DIVERGENCE_EXISTS,
+		
+		/** A Java error was encountered while attempting to validate. */
+		ERROR_ENCOUNTERED,
+		
+		/** Everything checks out. */
+		NO_DIVERGENCE;
+	}
+	
+	
+	static protected boolean PRE_TRIM_VALIDATION_CONTENT = true;
+	
+	static final Pattern PCAL_CHECKSUM_PATTERN = Pattern.compile(PcalParams.PCAL_CHECKSUM_KEYWORD + "[0-9a-f]+$");
+	static final Pattern TRANSLATED_PCAL_CHECKSUM_PATTERN
+									= Pattern.compile(PcalParams.TRANSLATED_PCAL_CHECKSUM_KEYWORD + "[0-9a-f]+$");
+
+	private static final Pattern MODULE_PREFIX_PATTERN = Pattern.compile(TLAConstants.MODULE_OPENING_PREFIX_REGEX);
+	private static final Pattern MODULE_CLOSING_PATTERN = Pattern.compile(TLAConstants.MODULE_CLOSING_REGEX);
+	
+	/*
+	 * This regex is appropriate for only pre-MODULE-lines; the PlusCal specification states that the options line
+	 *  	may exist before the module, after the module, or within the module in a comment line or block. For our
+	 *  	purposes, we only care if it exists before the module and therefore the following regex.
+	 */
+	private static final Pattern PLUSCAL_OPTIONS = Pattern.compile("^[\\s]*PlusCal[\\s]+options",
+																   Pattern.CASE_INSENSITIVE);
+
+	/**
+	 * This method is a convenience wrapped around {@link #validate(List)}.
+	 * 
+	 * @param inputStream an stream to the entire specification to be validated; this stream is not closed.
+	 * @return the result of the validation, as enumerated by the inner enum of this class.
+	 */
+	public static ValidationResult validate(final InputStream inputStream)
+			throws IOException {
+        final String specContents;
+    	final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    	final byte[] buffer = new byte[4096];
+    	final BufferedInputStream bis = (inputStream instanceof BufferedInputStream)
+    											? (BufferedInputStream)inputStream
+    											: new BufferedInputStream(inputStream);
+    	
+        int bytesRead;
+        while ((bytesRead = bis.read(buffer)) != -1) {
+        	baos.write(buffer, 0, bytesRead);
+        }
+        
+    	specContents = new String(baos.toByteArray(), "UTF-8");
+
+		final String[] lines = specContents.split("\\r?\\n");
+		int startLine = -1;
+		if (PRE_TRIM_VALIDATION_CONTENT) {
+			for (int i = 0; i < lines.length; i++) {
+				final Matcher m = MODULE_PREFIX_PATTERN.matcher(lines[i]);
+				if (m.find()) {
+					startLine = i;
+					break;
+				} else {
+					final Matcher m2 = PLUSCAL_OPTIONS.matcher(lines[i]);
+					if (m2.find()) {
+						startLine = i;
+						break;
+					}
+				}
+			}
+		}
+		if (startLine < 1) {
+			return validate(Arrays.asList(lines));
+		} else {
+			final int reducedLength = lines.length - startLine;
+			final String[] reducedLines = new String[reducedLength];
+
+			System.arraycopy(lines, startLine, reducedLines, 0, reducedLength);
+			return validate(Arrays.asList(reducedLines));
+		}
+	}
+	
+	/**
+	 * There is some redundancy between this and {@link trans#performTranslation(List)} - it would be nice to make a
+	 * 	common method, extended by each.
+	 * 
+	 * @param specificationText the entire specification, line by line - for historical reasons.
+	 * @return the result of the validation, as enumerated by the inner enum of this class.
+	 */
+	private static ValidationResult validate(final List<String> specificationText) {
+        final Vector<String> deTabbedSpecification = trans.removeTabs(specificationText);
+		
+        final IntPair searchLoc = new IntPair(0, 0);
+        boolean notDone = true;
+		while (notDone) {
+			try {
+				/*
+				 * As mentioned in #413, this is a performance bottleneck point; unfortunately we need process the
+				 *		options as it affects the production of the AST and we base the checksum on the AST.
+				 * We have addressed a use case in which there is a long run of line prefacing the module specification
+				 * 		in the {@link #validate(InputStream)} method, but that doesn't address a long spec.
+				 * If we wanted to devote more time to this, we should examine the performance difference between
+				 * 		the character-by-character marching done in the ParseAlgorithm code versus using a
+				 * 		regex matcher to split apart lines.
+				 */
+                ParseAlgorithm.FindToken("PlusCal", deTabbedSpecification, searchLoc, "");
+                final String line = ParseAlgorithm.GotoNextNonSpace(deTabbedSpecification, searchLoc);
+                final String restOfLine = line.substring(searchLoc.two);
+				if (restOfLine.startsWith("options")) {
+                    // The first string after "PlusCal" not starting with a
+                    // space character is "options"
+					if (ParseAlgorithm.NextNonIdChar(restOfLine, 0) == 7) {
+                        // The "options" should begin an options line
+                        PcalParams.optionsInFile = true;
+                        ParseAlgorithm.ProcessOptions(deTabbedSpecification, searchLoc);
+                        notDone = false;
+                    }
+                }
+			} catch (ParseAlgorithmException e) {
+                // The token "PlusCal" not found.
+                notDone = false;
+            }
+        }
+        
+        int algLine = 0;
+        int algCol = -1;
+        // Search for "--algorithm" or "--fair".
+        // If found set algLine and algCol right after the last char,
+        // set foundBegin true, and set foundFairBegin true iff it
+        // was "--fair".  Otherwise, set foundBegin false.
+        boolean foundBegin = false;
+        boolean foundFairBegin = false;
+		while ((algLine < deTabbedSpecification.size()) && !foundBegin) {
+			final String line = deTabbedSpecification.elementAt(algLine);
+			final Matcher m = MODULE_CLOSING_PATTERN.matcher(line);
+			if (m.matches()) {
+				break;
+			}
+			
+			algCol = line.indexOf(PcalParams.BeginAlg);
+			if (algCol != -1) {
+				algCol = algCol + PcalParams.BeginAlg.length();
+				foundBegin = true;
+			} else {
+            	algCol = line.indexOf(PcalParams.BeginFairAlg);
+            	if (algCol != -1) {
+            		// Found the "--fair".  The more structurally nice thing to
+            		// do here would be to move past the following "algorithm".
+            		// However, it's easier to pass a parameter to the ParseAlgorithm
+            		// class's GetAlgorithm method that tells it to go past the
+            		// "algorithm" token.
+            		 algCol = algCol + PcalParams.BeginFairAlg.length();
+                     foundBegin = true;
+                     foundFairBegin = true;
+            		
+            	} else {
+            		algLine = algLine + 1;
+            	} 
+            }
+        }
+		if (!foundBegin) {
+			return ValidationResult.NO_PLUSCAL_EXISTS;
+		}
+
+		final int translationLine = trans.findTokenPair(deTabbedSpecification, 0,
+														PcalParams.BeginXlation1, PcalParams.BeginXlation2);
+        final String pcalMD5;
+        final String translatedMD5;
+		if (translationLine == -1) {
+            return ValidationResult.NO_TRANSLATION_EXISTS;
+		} else {
+			final int endTranslationLine = trans.findTokenPair(deTabbedSpecification, translationLine + 1,
+															   PcalParams.EndXlation1, PcalParams.EndXlation2);
+			if (endTranslationLine == -1) {
+                return ValidationResult.NO_TRANSLATION_EXISTS;
+            }
+
+			final String beginLine = deTabbedSpecification.get(translationLine);
+        	Matcher m = Validator.PCAL_CHECKSUM_PATTERN.matcher(beginLine);
+        	if (m.find()) {
+        		pcalMD5 = beginLine.substring(m.start() + PcalParams.PCAL_CHECKSUM_KEYWORD.length());
+        	} else {
+        		return ValidationResult.NO_CHECKSUMS_EXIST;
+        	}
+        	final String endLine = deTabbedSpecification.get(endTranslationLine);
+        	m = Validator.TRANSLATED_PCAL_CHECKSUM_PATTERN.matcher(endLine);
+        	if (m.find()) {
+        		translatedMD5 = endLine.substring(m.start() + PcalParams.TRANSLATED_PCAL_CHECKSUM_KEYWORD.length());
+
+            	final Vector<String> translation = new Vector<>(specificationText.subList((translationLine + 1),
+            																			   endTranslationLine));
+            	final String calculatedMD5 = calculateMD5(translation);
+            	if (!translatedMD5.equals(calculatedMD5)) {
+            		return ValidationResult.DIVERGENCE_EXISTS;
+            	}
+        	} else {
+        		translatedMD5 = null;
+        	}
+        }
+        
+		try {
+			ParseAlgorithm.uncomment(deTabbedSpecification, algLine, algCol);
+		} catch (ParseAlgorithmException e) {
+            PcalDebug.reportError(e);
+            return ValidationResult.ERROR_ENCOUNTERED;
+        }
+
+		// This seems like crazy poor design - we're already passing around algLine and algCol, but if we don't make
+		//	this arbitrary object, throw it into a global public static setting, and also assign values to it there,
+		//	then the ParseAlgorithm won't pick up the values..
+        final TLAtoPCalMapping mapping = new TLAtoPCalMapping() ;
+        mapping.algColumn = algCol;
+        mapping.algLine = algLine;
+        PcalParams.tlaPcalMapping = mapping;
+		
+		final PcalCharReader reader = new PcalCharReader(deTabbedSpecification, algLine, algCol,
+				specificationText.size(), 0);
+		final AST ast;
+		try {
+			ast = ParseAlgorithm.getAlgorithm(reader, foundFairBegin);
+		} catch (ParseAlgorithmException e) {
+			PcalDebug.reportError(e);
+			return ValidationResult.ERROR_ENCOUNTERED;
+		}
+        
+        final String calculatedMD5 = Validator.calculateMD5(ast.toString());
+    	if (!pcalMD5.equals(calculatedMD5)) {
+    		return ValidationResult.DIVERGENCE_EXISTS;
+    	}
+
+		return ValidationResult.NO_DIVERGENCE;
+	}
+    
+    static String calculateMD5(final Vector<String> lines) {
+    	final StringBuilder sb = new StringBuilder();
+    	for (final String str : lines) {
+    		sb.append(str);
+    	}
+    	
+    	return calculateMD5(sb.toString());
+    }
+    
+    static String calculateMD5(final String string) {
+    	try {
+        	final MessageDigest digest = MessageDigest.getInstance("MD5");
+        	final byte[] hash = digest.digest(string.getBytes(StandardCharsets.UTF_8));
+        	final StringBuffer hexString = new StringBuffer();
+			for (int i = 0; i < hash.length; i++) {
+				final String hex = Integer.toHexString(0xff & hash[i]);
+				if (hex.length() == 1) {
+					hexString.append('0');
+				}
+				hexString.append(hex);
+			}
+            return hexString.toString();
+    	} catch (final NoSuchAlgorithmException e) {
+    		PcalDebug.reportError("Unable to calculate MD5: " + e.getMessage());
+    		return null;
+    	}
+    }
+}
diff --git a/tlatools/src/pcal/trans.java b/tlatools/src/pcal/trans.java
index a68c1a835f5fb40b43d31f14aaeff333eeb4f509..57fe07a9ce91a59c4606deb5d9ffe1899f6b17fe 100644
--- a/tlatools/src/pcal/trans.java
+++ b/tlatools/src/pcal/trans.java
@@ -8,7 +8,10 @@ import java.io.FileNotFoundException;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Vector;
+import java.util.regex.Matcher;
 
 import pcal.exception.FileToStringVectorException;
 import pcal.exception.ParseAlgorithmException;
@@ -17,6 +20,7 @@ import pcal.exception.RemoveNameConflictsException;
 import pcal.exception.StringVectorToFileException;
 import pcal.exception.TLCTranslationException;
 import pcal.exception.UnrecoverableException;
+import util.TLAConstants;
 import util.ToolIO;
 
 /***************************************************************************
@@ -277,15 +281,20 @@ import util.ToolIO;
 * allow the parser to catch the error at the "if".                         *
 * </pre>
 ***************************************************************************/
-class trans
-{
+class trans {
     /** Status indicating no errors and successful process */
     static final int STATUS_OK = 1;
     /** Status of no errors, but abort of the translation */
     static final int STATUS_EXIT_WITHOUT_ERROR = 0;
     /** Status of present errors and abort of the translation */
     static final int STATUS_EXIT_WITH_ERRORS = -1;
-
+    
+    private static final String PCAL_TRANSLATION_COMMENT_LINE_PREFIX
+    		= "\\* " + PcalParams.BeginXlation1 + " " + PcalParams.BeginXlation2 + " " + PcalParams.BeginXlation3;
+    private static final String TLA_TRANSLATION_COMMENT_LINE_PREFIX
+    		= "\\* " + PcalParams.EndXlation1 + " " + PcalParams.EndXlation2 + " " + PcalParams.EndXlation3;
+    
+    
     /**
      * Main function called from the command line
      * @param args, command line arguments
@@ -346,10 +355,10 @@ class trans
         * contents, where inputVec[i] is the string containing the contents  *
         * of line i+1 of the input file.                                     *
         *********************************************************************/
-        Vector<String> inputVec = null;
+        List<String> inputVec = null;
         try
         {
-            inputVec = fileToStringVector(PcalParams.TLAInputFile + /* (PcalParams.fromPcalFile ? ".pcal" : */".tla" /*)*/);
+            inputVec = fileToStringVector(PcalParams.TLAInputFile + /* (PcalParams.fromPcalFile ? ".pcal" : */TLAConstants.Files.TLA_EXTENSION /*)*/);
         } catch (FileToStringVectorException e)
         {
             PcalDebug.reportError(e);
@@ -361,7 +370,7 @@ class trans
         * which was not always the case in the aborted version 1.31.         *
         *********************************************************************/
         // Vector outputVec = PcalParams.fromPcalFile ? new Vector() : inputVec;
-        final Vector<String> outputVec = runMe(inputVec);
+        final List<String> outputVec = performTranslation(inputVec);
         if (outputVec == null) {
         	return exitWithStatus(STATUS_EXIT_WITH_ERRORS);
         }
@@ -381,11 +390,11 @@ class trans
                 file.delete();
             }
             ;
-            file = new File(PcalParams.TLAInputFile + ".tla");
+            file = new File(PcalParams.TLAInputFile + TLAConstants.Files.TLA_EXTENSION);
             file.renameTo(new File(PcalParams.TLAInputFile + ".old"));
         } catch (Exception e)
         {
-            PcalDebug.reportError("Could not rename input file " + PcalParams.TLAInputFile + ".tla" + " to "
+            PcalDebug.reportError("Could not rename input file " + PcalParams.TLAInputFile + TLAConstants.Files.TLA_EXTENSION + " to "
                     + PcalParams.TLAInputFile + ".old");
             return exitWithStatus(STATUS_EXIT_WITH_ERRORS);
         }
@@ -423,20 +432,20 @@ class trans
         *********************************************************************/
         try
         {
-            WriteStringVectorToFile(outputVec, PcalParams.TLAInputFile + ".tla");
+            WriteStringVectorToFile(outputVec, PcalParams.TLAInputFile + TLAConstants.Files.TLA_EXTENSION);
         } catch (StringVectorToFileException e)
         {
             PcalDebug.reportError(e);
             return exitWithStatus(STATUS_EXIT_WITH_ERRORS);
         }
 
-        PcalDebug.reportInfo("New file " + PcalParams.TLAInputFile + ".tla" + " written.");
+        PcalDebug.reportInfo("New file " + PcalParams.TLAInputFile + TLAConstants.Files.TLA_EXTENSION + " written.");
 
         /*********************************************************************
         * Write the cfg file, unless the -nocfg option is used.              *
         *********************************************************************/
-        File cfgFile = new File(PcalParams.TLAInputFile + ".cfg");
-        Vector<String> cfg = null;
+        final File cfgFile = new File(PcalParams.TLAInputFile + TLAConstants.Files.CONFIG_EXTENSION);
+        List<String> cfg = null;
         boolean writeCfg = !PcalParams.Nocfg;
         if (writeCfg && cfgFile.exists())
         {
@@ -444,7 +453,7 @@ class trans
             {
                 try
                 {
-                    cfg = fileToStringVector(PcalParams.TLAInputFile + ".cfg");
+                    cfg = fileToStringVector(PcalParams.TLAInputFile + TLAConstants.Files.CONFIG_EXTENSION);
                 } catch (FileToStringVectorException e)
                 {
                     PcalDebug.reportError(e);
@@ -460,10 +469,9 @@ class trans
             }
         } else
         {
-            cfg = new Vector<String>();
-            cfg.addElement(PcalParams.CfgFileDelimiter);
+            cfg = new ArrayList<>();
+            cfg.add(PcalParams.CfgFileDelimiter);
         }
-        ;
 
         /*********************************************************************
         * Delete previously written part of cfg file.                        *
@@ -474,7 +482,7 @@ class trans
             boolean done = false;
             while ((!done) && (cfg.size() > j))
             {
-                if (((String) cfg.elementAt(j)).indexOf(PcalParams.CfgFileDelimiter) == -1)
+                if (((String) cfg.get(j)).indexOf(PcalParams.CfgFileDelimiter) == -1)
                 {
                     j = j + 1;
                 } else
@@ -489,7 +497,7 @@ class trans
                 *************************************************************/
                 while (j > 0)
                 {
-                    cfg.removeElementAt(0);
+                    cfg.remove(0);
                     j = j - 1;
                 }
             } else
@@ -502,7 +510,6 @@ class trans
                 *************************************************************/
                 cfg.add(0, PcalParams.CfgFileDelimiter);
             }
-            ;
 
             /******************************************************************
             * If defaultInitValue is used, add a CONSTANT statement setting   *
@@ -513,7 +520,7 @@ class trans
             {
                 cfg.add(0, "CONSTANT defaultInitValue = defaultInitValue");
             }
-            ;
+            
             /******************************************************************
             * Insert the `PROPERTY Termination' line if requested.            *
             ******************************************************************/
@@ -521,51 +528,48 @@ class trans
             {
                 cfg.add(0, "PROPERTY Termination");
             }
-            ;
 
             /******************************************************************
             * Insert the SPECIFICATION line if there isn't already one.       *
             ******************************************************************/
-            j = 0;
             boolean hasSpec = false;
-            while (j < cfg.size())
-            {
-                String thisLine = (String) cfg.elementAt(j);
-                if ((thisLine.indexOf("SPECIFICATION") != -1)
+            for (final String thisLine : cfg) {
+                if ((thisLine.indexOf(TLAConstants.KeyWords.SPECIFICATION) != -1)
                         && ((thisLine.indexOf("\\*") == -1) || (thisLine.indexOf("\\*") > thisLine
-                                .indexOf("SPECIFICATION"))))
-                {
+                                .indexOf(TLAConstants.KeyWords.SPECIFICATION)))) {
                     hasSpec = true;
+                    break;
                 }
-                ;
-                j = j + 1;
             }
-            ;
+
             if (hasSpec)
             {
                 PcalDebug.reportInfo("File " + PcalParams.TLAInputFile
-                        + ".cfg already contains SPECIFICATION statement," + "\n   so new one not written.");
+                        + ".cfg already contains " + TLAConstants.KeyWords.SPECIFICATION
+                        + " statement," + "\n   so new one not written.");
             } else
             {
-                cfg.add(0, "SPECIFICATION Spec");
+                cfg.add(0, TLAConstants.KeyWords.SPECIFICATION + " Spec");
             }
-            ;
+
             try
             {
-                WriteStringVectorToFile(cfg, PcalParams.TLAInputFile + ".cfg");
+                WriteStringVectorToFile(cfg, PcalParams.TLAInputFile + TLAConstants.Files.CONFIG_EXTENSION);
             } catch (StringVectorToFileException e)
             {
                 PcalDebug.reportError(e);
                 return exitWithStatus(STATUS_EXIT_WITH_ERRORS);
             }
-            PcalDebug.reportInfo("New file " + PcalParams.TLAInputFile + ".cfg" + " written.");
+            PcalDebug.reportInfo("New file " + PcalParams.TLAInputFile + TLAConstants.Files.CONFIG_EXTENSION + " written.");
         }
-        ;
 
         return exitWithStatus(STATUS_EXIT_WITHOUT_ERROR);
     } // END main
 
-    public static Vector<String> runMe(final Vector<String> inputVec) {
+    // This is called from the main-invoked {@link #runMe(String[])}
+    // For some reason this method used to both mutate the argument, and then also returns that argument... ?
+    //		Now we copy the argument, mutate the copy, and return that.
+    public static List<String> performTranslation(final List<String> specificationText) {
         /**
          * Create the new TLAtoPCalMapping object, call it mapping
          * here and set PcalParams.tlaPcalMapping to point to it.
@@ -590,7 +594,7 @@ class trans
         * translator are copied from inputVec, so any tabs the user wants    *
         * are kept.                                                          *
         *********************************************************************/
-        Vector<String> untabInputVec = removeTabs(inputVec);
+        final Vector<String> untabInputVec = removeTabs(specificationText);
 
         /**
          *  Look through the file for PlusCal options.  They are put anywhere
@@ -672,25 +676,25 @@ class trans
         * and end translation lines contain part of the algorithm within   *
         * them.                                                            *
         *******************************************************************/
+    	final ArrayList<String> output = new ArrayList<>(specificationText);
+
         translationLine = findTokenPair(untabInputVec, 0, PcalParams.BeginXlation1, PcalParams.BeginXlation2);
         if (translationLine != -1)
         {
-            
-
-            int endTranslationLine = findTokenPair(untabInputVec, translationLine + 1, PcalParams.EndXlation1,
-                PcalParams.EndXlation2);
+            int endTranslationLine = findTokenPair(untabInputVec, translationLine + 1,
+            									   PcalParams.EndXlation1, PcalParams.EndXlation2);
             if (endTranslationLine == -1)
             {
                 PcalDebug.reportError("No line containing `" + PcalParams.EndXlation1 + " " + PcalParams.EndXlation2);
                 return null;
             }
 
-            endTranslationLine = endTranslationLine - 1;
+            endTranslationLine--;
             while (translationLine < endTranslationLine)
             {
-                inputVec.remove(endTranslationLine);
+            	output.remove(endTranslationLine);
                 untabInputVec.remove(endTranslationLine);
-                endTranslationLine = endTranslationLine - 1;
+                endTranslationLine--;
             }
         }
 
@@ -702,7 +706,7 @@ class trans
         boolean foundFairBegin = false;
         while ((algLine < untabInputVec.size()) && !foundBegin)
         {
-            String line = (String) untabInputVec.elementAt(algLine);
+            String line = untabInputVec.elementAt(algLine);
             algCol = line.indexOf(PcalParams.BeginAlg);
             if (algCol != -1)
             {
@@ -832,15 +836,36 @@ class trans
                 return null ;
             } ;
             
-            inputVec.insertElementAt("\\* BEGIN TRANSLATION", ecLine+1) ;
-            untabInputVec.insertElementAt("\\* BEGIN TRANSLATION", ecLine+1) ;
-            inputVec.insertElementAt("\\* END TRANSLATION", ecLine+2) ;
-            untabInputVec.insertElementAt("\\* END TRANSLATION", ecLine+2) ;
+			output.add((ecLine + 1), (PCAL_TRANSLATION_COMMENT_LINE_PREFIX + " "));
+            untabInputVec.insertElementAt(PCAL_TRANSLATION_COMMENT_LINE_PREFIX, (ecLine + 1));
+            output.add((ecLine + 2), (TLA_TRANSLATION_COMMENT_LINE_PREFIX + " "));
+            untabInputVec.insertElementAt(TLA_TRANSLATION_COMMENT_LINE_PREFIX, (ecLine + 2));
 
             translationLine = ecLine + 1;
 //System.out.println(ecLine + ", " + ecCol);
 //Debug.printVector(inputVec, "foo");
         }
+        else {
+        	// if it has an existing checksum suffix then get rid of it
+        	final String originalBeginLine = output.remove(translationLine);
+        	Matcher m = Validator.PCAL_CHECKSUM_PATTERN.matcher(originalBeginLine);
+        	String outputLine;
+        	if (m.find()) {
+        		outputLine = PCAL_TRANSLATION_COMMENT_LINE_PREFIX + " ";
+        	} else {
+        		outputLine = originalBeginLine + " ";
+        	}
+			output.add(translationLine, outputLine);
+			
+        	final String originalEndLine = output.remove(translationLine + 1);
+        	m = Validator.TRANSLATED_PCAL_CHECKSUM_PATTERN.matcher(originalEndLine);
+        	if (m.find()) {
+        		outputLine = TLA_TRANSLATION_COMMENT_LINE_PREFIX + " ";
+        	} else {
+        		outputLine = originalEndLine + " ";
+        	}
+			output.add((translationLine + 1), outputLine);
+        }
         
         /*
          * Set the mappings start line.
@@ -872,7 +897,7 @@ class trans
         * the previous translation removed), starting right after the        *
         * PcalParams.BeginAlg string.                                        *
         *********************************************************************/
-        PcalCharReader reader = new PcalCharReader(untabInputVec, algLine, algCol, inputVec.size(), 0);
+        PcalCharReader reader = new PcalCharReader(untabInputVec, algLine, algCol, output.size(), 0);
 
         /*********************************************************************
         * Set ast to the AST node representing the entire algorithm.         *
@@ -896,6 +921,8 @@ class trans
             return null ; // added for testing
         }
         PcalDebug.reportInfo("Parsing completed.");
+        
+        final String pcalMD5 = Validator.calculateMD5(ast.toString());
 // tla-pcal debugging
 //System.out.println("Translation Output:");
 //System.out.println(ast.toString());
@@ -968,7 +995,13 @@ class trans
                 return null ; // added for testing
             }
         }
-        ;
+        
+        final String beginLine = output.remove(mapping.tlaStartLine - 1);
+        output.add((mapping.tlaStartLine - 1), (beginLine + PcalParams.PCAL_CHECKSUM_KEYWORD + pcalMD5));
+        
+        final String translationMD5 = Validator.calculateMD5(translation);
+        final String endLine = output.remove(mapping.tlaStartLine);
+		output.add(mapping.tlaStartLine, (endLine + PcalParams.TRANSLATED_PCAL_CHECKSUM_KEYWORD + translationMD5));
 
         /*********************************************************************
         * Add the translation to outputVec.                                  *
@@ -976,12 +1009,12 @@ class trans
         int i = 0;
         while (i < translation.size())
         {
-            inputVec.insertElementAt(translation.elementAt(i), i + translationLine + 1);
+        	output.add((i + translationLine + 1), translation.elementAt(i));
             i = i + 1;
         }
 
         PcalDebug.reportInfo("Translation completed.");
-        return inputVec;
+        return output;
 // tla-pcal Debugging
 //System.exit(0);
 	}
@@ -1069,15 +1102,16 @@ class trans
         {
             try
             {
-                Vector<String> parseFile = PcalResourceFileReader.ResourceFileToStringVector(PcalParams.SpecFile + ".tla");
-
-                WriteStringVectorToFile(parseFile, PcalParams.SpecFile + ".tla");
-                parseFile = PcalResourceFileReader.ResourceFileToStringVector(PcalParams.SpecFile + ".cfg");
-                WriteStringVectorToFile(parseFile, PcalParams.SpecFile + ".cfg");
+				Vector<String> parseFile = PcalResourceFileReader
+						.ResourceFileToStringVector(PcalParams.SpecFile + TLAConstants.Files.TLA_EXTENSION);
 
-                PcalDebug
-                        .reportInfo("Wrote files " + PcalParams.SpecFile + ".tla and " + PcalParams.SpecFile + ".cfg.");
+				WriteStringVectorToFile(parseFile, PcalParams.SpecFile + TLAConstants.Files.TLA_EXTENSION);
+				parseFile = PcalResourceFileReader
+						.ResourceFileToStringVector(PcalParams.SpecFile + TLAConstants.Files.CONFIG_EXTENSION);
+				WriteStringVectorToFile(parseFile, PcalParams.SpecFile + TLAConstants.Files.CONFIG_EXTENSION);
 
+				PcalDebug.reportInfo("Wrote files " + PcalParams.SpecFile + TLAConstants.Files.TLA_EXTENSION + " and "
+						+ PcalParams.SpecFile + TLAConstants.Files.CONFIG_EXTENSION + ".");
             } catch (UnrecoverableException e)
             {
                 throw new TLCTranslationException(e.getMessage());
@@ -1232,14 +1266,14 @@ class trans
 
     /***************** METHODS FOR READING AND WRITING FILES *****************/
 
-    private static void WriteStringVectorToFile(Vector<String> inputVec, String fileName) throws StringVectorToFileException
+    private static void WriteStringVectorToFile(final List<String> inputVec, String fileName) throws StringVectorToFileException
     /***********************************************************************
-    * Writes the Vector of strings inputVec to file named fileName, with   *
+    * Writes the List of strings inputVec to file named fileName, with     *
     * each element of inputVec written on a new line.                      *
     ***********************************************************************/
     {
-        try
-        {
+    	// TODO use Apache Commons for this
+        try (final BufferedWriter fileW = new BufferedWriter(new FileWriter(fileName))) {
             // I have no idea what Java does if you try to write a new version
             // of a read-only file. On Windows, it's happy to write it. Who
             // the hell knows what it does on other operating systems? So, something
@@ -1255,61 +1289,41 @@ class trans
             // if (! file.canWrite()) {
             // file.setWritable(true);
             // }
-            BufferedWriter fileW = new BufferedWriter(new FileWriter(fileName));
-            int lineNum = 0;
-            while (lineNum < inputVec.size())
-            {
-                fileW.write((String) inputVec.elementAt(lineNum));
+        	for (final String line : inputVec) {
+                fileW.write(line);
                 fileW.newLine();
-                lineNum = lineNum + 1;
             }
-            ;
-            fileW.close();
-        } catch (Exception e)
-        {
+        } catch (Exception e) {
             throw new StringVectorToFileException("Could not write file " + fileName);
         }
-        ;
-
     }
 
-    private static Vector<String> fileToStringVector(String fileName) throws FileToStringVectorException
+    private static List<String> fileToStringVector(String fileName) throws FileToStringVectorException
     /***********************************************************************
     * Reads file fileName into a StringVector, a vector in which each      *
     * element is a line of the file.                                       *
     ***********************************************************************/
     {
-        Vector<String> inputVec = new Vector<String>(100);
-        try
-        {
-            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(fileName)));
-            try
-            {
-                String nextLine = bufferedReader.readLine();
-                while (nextLine != null)
-                {
-                    inputVec.addElement(nextLine);
-                    nextLine = bufferedReader.readLine();
-                }
-                ;
-                bufferedReader.close();
-            } catch (IOException e)
-            {
-                /*********************************************************
-                * Error while reading input file.                        *
-                *********************************************************/
-                throw new FileToStringVectorException("Error reading file " + fileName + ".");
+        final List<String> inputVec = new ArrayList<>(100);
+    	// TODO use Apache Commons for this
+        try (final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(fileName)))) {
+            String nextLine = bufferedReader.readLine();
+            while (nextLine != null) {
+                inputVec.add(nextLine);
+                nextLine = bufferedReader.readLine();
             }
-        }
-
-        catch (FileNotFoundException e)
-        {
+        } catch (FileNotFoundException e) {
             /**************************************************************
             * Input file could not be found.                              *
             **************************************************************/
             throw new FileToStringVectorException("Input file " + fileName + " not found.");
+        } catch (IOException e) {
+            /*********************************************************
+            * Error while reading input file.                        *
+            *********************************************************/
+            throw new FileToStringVectorException("Error reading file " + fileName + ".");
         }
-        ;
+        
         return inputVec;
     }
 
@@ -1728,7 +1742,7 @@ class trans
         { 
           PcalParams.TLAInputFile = args[maxArg]; 
         } 
-        else if (args[maxArg].substring(dotIndex).equals(".tla"))
+        else if (args[maxArg].substring(dotIndex).equals(TLAConstants.FILE_TLA_EXTENSION))
         { 
           PcalParams.TLAInputFile = args[maxArg].substring(0, dotIndex); 
         }
@@ -1749,7 +1763,7 @@ class trans
         } else
         {
             // extension present
-            if (file.getName().toLowerCase().endsWith(".tla"))
+            if (file.getName().toLowerCase().endsWith(TLAConstants.Files.TLA_EXTENSION))
             {
                 hasExtension = true;
             }
@@ -1780,7 +1794,7 @@ class trans
             // PcalParams.fromPcalFile = true;
             // } else
             // {
-            file = new File(PcalParams.TLAInputFile + ".tla");
+            file = new File(PcalParams.TLAInputFile + TLAConstants.Files.TLA_EXTENSION);
             if (!file.exists())
             {
                 return CommandLineError("Input file " + PcalParams.TLAInputFile + ".pcal and " + file.getPath()
@@ -1788,7 +1802,7 @@ class trans
             }
             // }
         }
-        // file = new File(PcalParams.TLAInputFile + (PcalParams.fromPcalFile?".pcal":".tla"));
+        // file = new File(PcalParams.TLAInputFile + (PcalParams.fromPcalFile?".pcal":TLAConstants.FILE_TLA_EXTENSION));
         // if (!file.exists())
         // {
         // return CommandLineError("Input file " + file.getPath() + " not found");
@@ -1850,7 +1864,7 @@ class trans
         return STATUS_EXIT_WITH_ERRORS;
     }
 
-    private static int findTokenPair(Vector<String> vec, int lineNum, String tok1, String tok2)
+    static int findTokenPair(Vector<String> vec, int lineNum, String tok1, String tok2)
     /*********************************************************************
     * Returns the number of the first line at or after lineNum in the    *
     * vector of strings vec containing tok1 followed by 1 or more        *
@@ -1884,8 +1898,7 @@ class trans
 
     /**************************  RemoveTabs  *********************************/
 
-    public static Vector<String> removeTabs(Vector<String> vec)
-    {
+    public static Vector<String> removeTabs(List<String> input) {
         /********************************************************************
         * Returns a string vector obtained from the string vector vec by   *
         * replacing any evil tabs with the appropriate number of spaces,   *
@@ -1895,34 +1908,25 @@ class trans
         * Emacs does when told to remove tabs, which makes it good enough  *
         * for me.                                                          *
          ********************************************************************/
-        Vector<String> newVec = new Vector<String>();
-        int i = 0;
-        while (i < vec.size())
-        {
-            String oldline = (String) vec.elementAt(i);
-            String newline = "";
+        final Vector<String> newVec = new Vector<>();
+        for (final String oldLine : input) {
+            String newLine = "";
             int next = 0;
-            while (next < oldline.length())
-            {
-                if (oldline.charAt(next) == '\t')
-                {
-                    int toAdd = 8 - (newline.length() % 8);
-                    while (toAdd > 0)
-                    {
-                        newline = newline + " ";
+            while (next < oldLine.length()) {
+                if (oldLine.charAt(next) == '\t') {
+                    int toAdd = 8 - (newLine.length() % 8);
+                    while (toAdd > 0) {
+                        newLine = newLine + " ";
                         toAdd = toAdd - 1;
                     }
-                } else
-                {
-                    newline = newline + oldline.substring(next, next + 1);
+                } else {
+                    newLine = newLine + oldLine.substring(next, next + 1);
                 }
-                ;
                 next = next + 1;
             }
-            newVec.addElement(newline);
-            i = i + 1;
+            newVec.add(newLine);
         }
-        ;
+
         return newVec;
     }
 
diff --git a/tlatools/src/tla2sany/StandardModules/TLC.tla b/tlatools/src/tla2sany/StandardModules/TLC.tla
index 0f0b40f3d7be94c2676d41ab7f405dbc03e4ed50..0384c039761a1a517955481c153b2f5ea7f301bf 100644
--- a/tlatools/src/tla2sany/StandardModules/TLC.tla
+++ b/tlatools/src/tla2sany/StandardModules/TLC.tla
@@ -48,6 +48,20 @@ JavaTime == CHOOSE n : n \in Nat
 (*                                                                         *)
 (* (The ELSE expression is never evaluated.)                               *)
 (*                                                                         *)
+(* TLCGet accepts some pre-defined string values to query TLC state. The   *)
+(* values are as follows:                                                  *)
+(*                                                                         *)
+(*   - TLCGet("distinct") evaluates to the total number of distinct states *)
+(*     found by TLC so far, globally.                                      *)
+(*   - TLCGet("queue") evaluates to the number of states currently in the  *)
+(*     queue to be checked.                                                *)
+(*   - TLCGet("duration") evaluates to the number of seconds elapsed since *)
+(*     model checking began.                                               *)
+(*   - TLCGet("diameter") evaluates to the length of the longest behavior  *)
+(*     found by TLC so far, globally (equals one in the initial predicate).*)
+(*   - TLCGet("level") is the length of the current behavior (equals zero  *)
+(*     in the evaluation of the initial predicate).                        *)
+(*                                                                         *)
 (* For reasons of efficiency, TLCGet and TLCSet behave somewhat strangely  *)
 (* when TLC is run with multiple worker threads.  Each worker thread       *)
 (* maintains its own individual copy of the list of values on which it     *)
diff --git a/tlatools/src/tla2sany/StandardModules/Toolbox.tla b/tlatools/src/tla2sany/StandardModules/Toolbox.tla
new file mode 100644
index 0000000000000000000000000000000000000000..113eb3b690bda01e066ca6dd906e03acc272b968
--- /dev/null
+++ b/tlatools/src/tla2sany/StandardModules/Toolbox.tla
@@ -0,0 +1,23 @@
+----------------------------- MODULE Toolbox --------------------------------
+(***************************************************************************)
+(*                                                                         *)
+(***************************************************************************)
+LOCAL INSTANCE Naturals   \* a + b
+LOCAL INSTANCE FiniteSets \* Cardinality
+LOCAL INSTANCE TLC        \* TLCGet
+
+-----------------------------------------------------------------------------
+
+(* Trace Exploration *)
+
+_TETrace ==
+    CHOOSE f \in [ (Nat \ {0}) -> STRING ] : TRUE
+
+LOCAL _TETraceLength == Cardinality(DOMAIN _TETrace)
+
+_TEPosition == 
+    IF TLCGet("level") >= _TETraceLength
+       THEN _TETraceLength
+       ELSE TLCGet("level") + 1
+
+=============================================================================
diff --git a/tlatools/src/tla2sany/drivers/FrontEndException.java b/tlatools/src/tla2sany/drivers/FrontEndException.java
index 609ab4413c130db9e1ee0fbc3d9e198f6cb03426..e8804206b23545f562a602697c3e97c05b8cffdf 100644
--- a/tlatools/src/tla2sany/drivers/FrontEndException.java
+++ b/tlatools/src/tla2sany/drivers/FrontEndException.java
@@ -4,16 +4,17 @@ package tla2sany.drivers;
 /**
  * Exception thrown by SANY on errors
  * @author Leslie Lamport
- * @version $Id$
  */
 public class FrontEndException extends Exception {
-
     // SZ Feb 20, 2009: fixed the exception chaining
     // instead of having the cause as a member, the 
     // exception now has it in trace
     // also changed the visibility to public
-    public FrontEndException(Exception cause) 
-    { 
-        super(cause);
+	public FrontEndException(final Exception cause) {
+		super(cause);
+    }
+    
+    public FrontEndException(final String msg) {
+    	super(msg);
     }
 }
diff --git a/tlatools/src/tla2sany/drivers/SANY.java b/tlatools/src/tla2sany/drivers/SANY.java
index d27b042086fa6c832d6809d5c4a5c6ee56b86d19..ac724a869dacc2b4d97fc2093bc32ba83ef7a7b9 100644
--- a/tlatools/src/tla2sany/drivers/SANY.java
+++ b/tlatools/src/tla2sany/drivers/SANY.java
@@ -78,7 +78,7 @@ public class SANY {
     //          should be reported
 
   /**
-   * The TLAFrontEnd.frontEndMain method Processes an entire TLA+ spec
+   * The SANY.frontEndMain method Processes an entire TLA+ spec
    * that starts in the file named in "filename", including all files
    * it refers to directly or indirectly in EXTENDS or INSTANCE
    * constructs.  "fileName" is relative to the current directory.  It
@@ -206,7 +206,7 @@ public class SANY {
       try 
       {
           // Actual parsing method called from inside loadSpec()
-          if (!spec.loadSpec(spec.getFileName(), spec.parseErrors)) 
+          if (!spec.loadSpec(spec.getFileName(), spec.parseErrors, true)) 
           {
               // dead code SZ 02. Aug 2009
               /*
@@ -389,7 +389,7 @@ public class SANY {
   }
 
   /**
-   * Main driver method for maintainers and debuggers of the TLAFrontEnd.
+   * Main driver method for maintainers and debuggers of SANY.
    * 
    * Calls frontEndMain for each file named on the command line and then, 
    * barring errors too severe, calls the Explorer tool with the resulting 
diff --git a/tlatools/src/tla2sany/modanalyzer/ModuleRelationships.java b/tlatools/src/tla2sany/modanalyzer/ModuleRelationships.java
index bc4f81e70caf47f2420b6bf8b2cc9e6bcd1f8381..b96fac62d33823fc170219f1df8f3b2760ae151c 100644
--- a/tlatools/src/tla2sany/modanalyzer/ModuleRelationships.java
+++ b/tlatools/src/tla2sany/modanalyzer/ModuleRelationships.java
@@ -33,7 +33,7 @@ class ModuleRelationships {
   } // end getContext()
 
 
-  Enumeration<String> getKeys() { return modRelHashtable.keys(); }  
+  Enumeration<ModulePointer> getKeys() { return modRelHashtable.keys(); }  
 
 
   // Add the entries from otherMR into THIS; they are assumed not to overlap.
diff --git a/tlatools/src/tla2sany/modanalyzer/ParseUnit.java b/tlatools/src/tla2sany/modanalyzer/ParseUnit.java
index 5c853180875fccf73b96f86f84889f93da38e686..9d8fa747a2979d11cb7eaff3929961068ae418b2 100644
--- a/tlatools/src/tla2sany/modanalyzer/ParseUnit.java
+++ b/tlatools/src/tla2sany/modanalyzer/ParseUnit.java
@@ -33,7 +33,10 @@ import tla2sany.st.ParseTree;
 import tla2sany.st.TreeNode;
 import tla2sany.utilities.Vector;
 import util.FileUtil;
+import util.FilenameToStream.TLAFile;
 import util.NamedInputStream;
+import util.TLAConstants;
+import util.TLAFlightRecorder;
 import util.ToolIO;
 
 /**
@@ -89,6 +92,13 @@ public class ParseUnit {
 	    parseStamp > nis.sourceFile().lastModified());
   }
 
+  public boolean isLibraryModule() {
+	  if (nis == null || !(nis.sourceFile() instanceof TLAFile)) {
+		  return false;
+	  }
+	  return ((TLAFile) nis.sourceFile()).isLibraryModule();
+  }
+
   // Get-methods
   public final String        getName()        { return rootModuleName; } 
 
@@ -250,15 +260,15 @@ public class ParseUnit {
         * argument to which such output gets written.  That argument should    *
         * have been passed down to this method.  (LL: 11 Mar 08)               *
         *                                                                      *
-        * The following statement modified by LL on 13 Mary 08 to produce      *
+        * The following statement modified by LL on 13 Mar 08 to produce       *
         * more useful output for the GUI.                                      *
         ***********************************************************************/
         if (ToolIO.getMode() == ToolIO.SYSTEM)
         {
-			ToolIO.out.println(String.format("Parsing file %s", absoluteResolvedPath));
+			ToolIO.out.println(TLAFlightRecorder.message(String.format("%s %s", TLAConstants.LoggingAtoms.PARSING_FILE, absoluteResolvedPath)));
         } else
         {
-            ToolIO.out.println(String.format("Parsing module %s in file %s", nis.getModuleName(), absoluteResolvedPath));
+            ToolIO.out.println(TLAFlightRecorder.message(String.format("Parsing module %s in file %s", nis.getModuleName(), absoluteResolvedPath)));
         }
 
         boolean parseSuccess; 
diff --git a/tlatools/src/tla2sany/modanalyzer/SpecObj.java b/tlatools/src/tla2sany/modanalyzer/SpecObj.java
index e701e708d1f66558ea38189d17aadc2031ad5a31..544993ce298daeaf2e1cdb0c1b15818feb07532a 100644
--- a/tlatools/src/tla2sany/modanalyzer/SpecObj.java
+++ b/tlatools/src/tla2sany/modanalyzer/SpecObj.java
@@ -2,11 +2,15 @@
 // Portions Copyright (c) 2003 Microsoft Corporation.  All rights reserved.
 package tla2sany.modanalyzer;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Set;
 
+import pcal.Validator;
 import tla2sany.semantic.AbortException;
 import tla2sany.semantic.Errors;
 import tla2sany.semantic.ExternalModuleTable;
@@ -221,10 +225,19 @@ public class SpecObj
         return semanticErrors;
     }
 
+	public Set<String> getModuleNames() {
+		final Set<String> s = new HashSet<>();
+		final Enumeration<ModulePointer> modules = getModules();
+		while (modules.hasMoreElements()) {
+			s.add(modules.nextElement().getName());
+		}
+		return s;
+	}
+
     // Returns enumeration of the modules so far included in the spec.
     // As whoever wrote this documentation didn't think was worth mentioning,
     // it appears that the "modules" being returned are ModulePointer objects.
-    public final Enumeration<String> getModules()
+    public final Enumeration<ModulePointer> getModules()
     {
         return moduleRelationshipsSpec.getKeys();
     }
@@ -880,18 +893,33 @@ public class SpecObj
     }
 
     /**
-     * This method "loads" an entire specification, starting with the
-     * top-level rootExternalModule and followed by all of the external
-     * modules it references via EXTENDS and INSTANCE statements.
+     * This invokes {@code loadSpec(rootExternalModuleName, errors, false);}
      */
-    public boolean loadSpec(String rootExternalModuleName, Errors errors) throws AbortException
-    {
+    public boolean loadSpec(final String rootExternalModuleName, final Errors errors) throws AbortException {
+    	return loadSpec(rootExternalModuleName, errors, false);
+    }
+    
+    /**
+	 * This method "loads" an entire specification, starting with the top-level
+	 * rootExternalModule and followed by all of the external modules it references
+	 * via EXTENDS and INSTANCE statements.
+	 * 
+	 * @param validateParseUnits if true, each parseable unit will be checked for
+	 *                           PlusCal and its accompanied TLA translation block,
+	 *                           followed by a validation of them if they exist
+	 * @see Validator
+	 */
+	public boolean loadSpec(final String rootExternalModuleName, final Errors errors, final boolean validateParseUnits)
+			throws AbortException {
         // If rootExternalModuleName" has *not* already been parsed, then
         // go to the file system and find the file containing it, create a
         // ParseUnit for it, and parse it. Parsing includes determining
         // module relationships. Aborts if not found in file system
         rootParseUnit = findOrCreateParsedUnit(rootExternalModuleName, errors, true /* first call */);
         rootModule = rootParseUnit.getRootModule();
+        if (validateParseUnits) {
+        	validateParseUnit(rootParseUnit);
+        }
 
         // Retrieve and parse all module extentions: As long as there is
         // another unresolved module name...
@@ -930,6 +958,10 @@ public class SpecObj
 
             if (extentionFound)
             {
+                if (validateParseUnits) {
+                	validateParseUnit(nextExtentionOrInstantiationParseUnit);
+                }
+
                 extenderOrInstancerParseUnit.addExtendee(nextExtentionOrInstantiationParseUnit);
                 nextExtentionOrInstantiationParseUnit.addExtendedBy(extenderOrInstancerParseUnit);
             }
@@ -969,6 +1001,40 @@ public class SpecObj
         return true;
         // loadUnresolvedRelatives(moduleRelationshipsSpec, rootModule, errors);
     }
+	
+	private void validateParseUnit(final ParseUnit parseUnit) {
+    	final File f = parseUnit.getNis().sourceFile();
+    	
+    	try (final FileInputStream fis = new FileInputStream(f)) {
+    		final Validator.ValidationResult result = Validator.validate(fis);
+    		
+            switch (result) {
+            	case NO_PLUSCAL_EXISTS:
+            	case NO_DIVERGENCE:
+            	case NO_CHECKSUMS_EXIST:
+            		break;
+            	case ERROR_ENCOUNTERED:
+					ToolIO.err.println("A Java problem was encountered attempting to validate the specification for "
+							+ parseUnit.getName());
+
+        			break;
+            	case NO_TRANSLATION_EXISTS:
+					ToolIO.out.println("PlusCal was found in the specification for " + parseUnit.getName()
+							+ " but no TLA+ translation block for it could be found.");
+
+            		break;
+            	case DIVERGENCE_EXISTS:
+					ToolIO.out.println("!! WARNING: Either the PlusCal or its TLA+ translation has changed in the "
+							+ "specification for " + parseUnit.getName()
+							+ " since the last time translation was performed.");
+            		
+            		break;
+            }
+    	} catch (final IOException e) {
+    		ToolIO.err.println("Encountered an exception while attempt to validate " + f.getAbsolutePath() + " - "
+    				+ e.getMessage());
+    	}
+	}
 
     /**
      * Getter for the name resolver used in the Spec
diff --git a/tlatools/src/tla2sany/parser/TLAplusParser.java b/tlatools/src/tla2sany/parser/TLAplusParser.java
index 2a54587334b1a1575f90468452dccb5d3dbf1d39..e5e0b1c895a901dd4bfc5b58f221e39b5639390c 100644
--- a/tlatools/src/tla2sany/parser/TLAplusParser.java
+++ b/tlatools/src/tla2sany/parser/TLAplusParser.java
@@ -7,6 +7,7 @@ import tla2sany.utilities.Stack;
 import tla2sany.utilities.Vector;
 import tlc2.output.EC;
 import util.Assert;
+import util.TLAConstants;
 import util.ToolIO;
 import util.UniqueString;
 
@@ -1655,7 +1656,7 @@ Token t;
   SyntaxTreeNode tn, sn[];
   Token t;
   bpa("Parameter declaration");
-  expecting = "CONSTANT";
+  expecting = TLAConstants.KeyWords.CONSTANT;
     tn = ParamSubDecl();
                          addHeir(tn);
  expecting = "Identifier, operator or _";
diff --git a/tlatools/src/tla2sany/semantic/Context.java b/tlatools/src/tla2sany/semantic/Context.java
index a178f2ae58db10521d76f82dd2558eca9d5ffaf8..2181c5ce6096a1d550e4b748e33f8ecd87af5df7 100644
--- a/tlatools/src/tla2sany/semantic/Context.java
+++ b/tlatools/src/tla2sany/semantic/Context.java
@@ -241,7 +241,7 @@ public class Context implements ExploreNode {
    * Returns a Vector of those SymbolNodes in this Context that are
    * instances of class "template" (or one of its subclasses)
    */
-  public Vector<SymbolNode> getByClass( Class template ) {
+  public Vector<SymbolNode> getByClass( Class<?> template ) {
     Vector<SymbolNode> result = new Vector<>();
     Enumeration<Pair> list = table.elements();
     while (list.hasMoreElements()) {
@@ -360,72 +360,72 @@ public class Context implements ExploreNode {
    * The original implementation added the elements of Context ct to
    * this context in the inverse order as they appear in ct.  It was
    * changed on 12 Mar 2013 by LL to add them in the same order.
+   * 
+   * Note that the return value is never used in our code base. (2020.03.06)
    */
-  public boolean mergeExtendContext(Context ct) {
-    boolean erc = true;
-
-    // check locality, and multiplicity
-    // the .reversePairList was added to the following statement
-    // by LL on 12 Mar 2013
-    Pair p = ct.lastPair.reversePairList();
-    while (p != null) {
-      // Walk back along the list of pairs added to Context "ct"
-      SymbolNode sn = p.info;
-
-      // Ignore local symbols in Context "ct"
-      if (!sn.isLocal()) {
-	Object sName;
-	if (sn instanceof ModuleNode) {
-	  sName = new SymbolTable.ModuleName(sn.getName());
-	}
-	else {
-	  sName = sn.getName();
-	}
-
-        if (!table.containsKey(sName)) {
-	  // If this context DOES NOT contain this name, add it:
-	  table.put(sName, new Pair(sn));
-        }
-	else {
-	  // If this Context DOES contain this name
-          SymbolNode symbol = ((Pair)table.get(sName)).info;
-          if (symbol != sn) {
-	    // if the two SymbolNodes with the same name are distinct nodes,
-	    // We issue a warning or do nothing if they are instances of the same Java
-        // class--i.e. FormalParamNode, OpDeclNode, OpDefNode, or ModuleNode--doing
-        // nothing if they are both definitions coming from the same module.
-	    // otherwise, it is considered to be an error.
-        // Option of doing nothing if from same module added by LL on 31 Oct 2012 to
-        // fix problem caused by the same module being both EXTENDed and imported with
-        // a LOCAL INSTANCE.  Previously, it always added the warning.
-	    if (symbol.getClass() == sn.getClass()) {
-	        if (! symbol.sameOriginallyDefinedInModule(sn)) {
-              errors.addWarning( sn.getTreeNode().getLocation(),
-                                 "Warning: the " + kindOfNode(symbol) +  " of '" +
-                                 sName.toString() +
-                                 "' conflicts with \nits " + kindOfNode(symbol) + " at " +
-                                 symbol.getTreeNode().getLocation() + ".");
-	        }
-         }
-	    else {
-              errors.addError( sn.getTreeNode().getLocation(),
-                               "The " + kindOfNode(symbol) +  " of '" +
-                               sName.toString() +
-                               "' conflicts with \nits " + kindOfNode(symbol) + " at " +
-                               symbol.getTreeNode().getLocation() + ".");
+	public boolean mergeExtendContext(final Context ct) {
+		if (ct.lastPair == null) {
+			// If the context represents an inner module that defines no EXTENDS, ct.lastPair will be null
+			return true;
+		}
+		
+		boolean erc = true;
+		// check locality, and multiplicity
+		// the .reversePairList was added to the following statement
+		// by LL on 12 Mar 2013
+		Pair p = ct.lastPair.reversePairList();
+		while (p != null) {
+			// Walk back along the list of pairs added to Context "ct"
+			SymbolNode sn = p.info;
+
+			// Ignore local symbols in Context "ct"
+			if (!sn.isLocal()) {
+				Object sName;
+				if (sn instanceof ModuleNode) {
+					sName = new SymbolTable.ModuleName(sn.getName());
+				} else {
+					sName = sn.getName();
+				}
+
+				if (!table.containsKey(sName)) {
+					// If this context DOES NOT contain this name, add it:
+					table.put(sName, new Pair(sn));
+				} else {
+					// If this Context DOES contain this name
+					SymbolNode symbol = ((Pair) table.get(sName)).info;
+					if (symbol != sn) {
+						// if the two SymbolNodes with the same name are distinct nodes,
+						// We issue a warning or do nothing if they are instances of the same Java
+						// class--i.e. FormalParamNode, OpDeclNode, OpDefNode, or ModuleNode--doing
+						// nothing if they are both definitions coming from the same module.
+						// otherwise, it is considered to be an error.
+						// Option of doing nothing if from same module added by LL on 31 Oct 2012 to
+						// fix problem caused by the same module being both EXTENDed and imported with
+						// a LOCAL INSTANCE. Previously, it always added the warning.
+						if (symbol.getClass() == sn.getClass()) {
+							if (!symbol.sameOriginallyDefinedInModule(sn)) {
+								errors.addWarning(sn.getTreeNode().getLocation(),
+										"Warning: the " + kindOfNode(symbol) + " of '" + sName.toString()
+												+ "' conflicts with \nits " + kindOfNode(symbol) + " at "
+												+ symbol.getTreeNode().getLocation() + ".");
+							}
+						} else {
+							errors.addError(sn.getTreeNode().getLocation(),
+									"The " + kindOfNode(symbol) + " of '" + sName.toString() + "' conflicts with \nits "
+											+ kindOfNode(symbol) + " at " + symbol.getTreeNode().getLocation() + ".");
 
 //                               "Incompatible multiple definitions of symbol '" +
 //                               sName.toString() +
 //                               "'; \nthe conflicting declaration is at " +
 //                               symbol.getTreeNode().getLocation()+ ".");
-              erc = false;
-            } //end else
-          } // end if
-        } // end else
-      }
-      p  = p.link;
-    }
-    return erc;
+							erc = false;
+						} // end else
+					} // end if
+				} // end else
+			}
+			p = p.link;
+		}
+		return erc;
   }
 
   private static String kindOfNode(SymbolNode symbol) {
diff --git a/tlatools/src/tla2sany/semantic/LevelNode.java b/tlatools/src/tla2sany/semantic/LevelNode.java
index 4cb59cea7ab55d03b984e65dd29da8936e12e096..189c4139e33df9c44de9f53d5f73814fef0d2977 100644
--- a/tlatools/src/tla2sany/semantic/LevelNode.java
+++ b/tlatools/src/tla2sany/semantic/LevelNode.java
@@ -283,13 +283,13 @@ public int levelChecked   = 0 ;
        "NonLeibnizParams: "    + HashSetToString(this.getNonLeibnizParams()) ;
     }
 
-  public static String HashSetToString(HashSet<SymbolNode> hs) {
+  public static String HashSetToString(HashSet<? extends SymbolNode> hs) {
     /***********************************************************************
     * Converts a HashSet of SymbolNodes to a printable string.             *
     ***********************************************************************/
     String rval = "{" ;
     boolean first = true ;
-    Iterator<SymbolNode> iter = hs.iterator();
+    final Iterator<? extends SymbolNode> iter = hs.iterator();
     while (iter.hasNext()) {
       if (! first) {rval = rval + ", ";} ;
       rval = rval + iter.next().getName() ;
diff --git a/tlatools/src/tla2sany/semantic/ModuleNode.java b/tlatools/src/tla2sany/semantic/ModuleNode.java
index d157b75b3d78a43e6e6e348cc421d7d5f919dd99..739024b73caea39d5f050969d14ae49e37ddd820 100644
--- a/tlatools/src/tla2sany/semantic/ModuleNode.java
+++ b/tlatools/src/tla2sany/semantic/ModuleNode.java
@@ -16,6 +16,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Iterator;
@@ -184,10 +185,12 @@ public class ModuleNode extends SymbolNode {
     * ModuleNode class.                                                    *
     ***********************************************************************/
 
-  private HashSet allExtendees = null ;
+  private HashMap<Boolean, HashSet<ModuleNode>> depthAllExtendeesMap = new HashMap<>();
     /***********************************************************************
     * The set of all modules that are extended by this module--either      *
-    * directly or indirectly.  Returned by getExtendModules                *
+    * directly or indirectly, keyed a Boolean representing whether the     *
+    * extendees are gathered recursively of not.                           *
+    * Returned by getExtendModules                                         *
     ***********************************************************************/
 
   private OpDeclNode[] constantDecls = null;
@@ -197,7 +200,7 @@ public class ModuleNode extends SymbolNode {
     // VARIABLEs declared in this module
 
 
-  private Vector definitions         = new Vector(8);
+  private ArrayList<SemanticNode> definitions = new ArrayList<>();
     // AssumeNodes, internal ModuleNodes, OpDefNodes, and TheoremNodes, in
     // the exact order they were defined in this module
     /***********************************************************************
@@ -218,7 +221,8 @@ public class ModuleNode extends SymbolNode {
     * It also contains ModuleNodes for inner modules, but not for modules  *
     * nested within them.                                                  *
     *                                                                      *
-    * It appears that this field is never used in SANY1.                   *
+    * It appears that this field is never used in SANY1; it is used by the *
+    * MCParser though.                                                     *
     ***********************************************************************/
 
   Vector recursiveDecls = new Vector(8);
@@ -227,7 +231,7 @@ public class ModuleNode extends SymbolNode {
     * RECURSIVE statements, in the order in which they were created.       *
     ***********************************************************************/
 
-  Vector opDefsInRecursiveSection = new Vector(16);
+  Vector<OpDefNode> opDefsInRecursiveSection = new Vector<>(16);
     /***********************************************************************
     * The list of all OpDefNode objects opd in this module, and in any     *
     * inner modules, with opd.recursiveSection >= 0.  (See the comments    *
@@ -346,8 +350,12 @@ public class ModuleNode extends SymbolNode {
     return (getConstantDecls().length == 0 &&
             getVariableDecls().length == 0);
   }
+  
+  public List<SemanticNode> getDefinitions() {
+	  return definitions;
+  }
 
-  public final void createExtendeeArray(Vector extendeeVec) {
+  public final void createExtendeeArray(Vector<ModuleNode> extendeeVec) {
     /***********************************************************************
     * This is called by Generator.processExtendsList to set the            *
     * ModuleNode's extendees field, which never seems to be used.          *
@@ -355,7 +363,7 @@ public class ModuleNode extends SymbolNode {
     extendees = new ModuleNode[extendeeVec.size()];
 
     for ( int i = 0; i < extendees.length; i++ ) {
-      extendees[i] = (ModuleNode)extendeeVec.elementAt(i);
+      extendees[i] = extendeeVec.elementAt(i);
     }
   }
 
@@ -368,7 +376,7 @@ public class ModuleNode extends SymbolNode {
   public final OpDeclNode[] getConstantDecls() {
     if (constantDecls != null) return constantDecls;
 
-    Vector contextVec = ctxt.getConstantDecls();
+    Vector<SemanticNode> contextVec = ctxt.getConstantDecls();
     constantDecls = new OpDeclNode[contextVec.size()];
     for (int i = 0, j = constantDecls.length - 1; i < constantDecls.length; i++) {
       constantDecls[j--] = (OpDeclNode)contextVec.elementAt(i);
@@ -384,7 +392,7 @@ public class ModuleNode extends SymbolNode {
    public final OpDeclNode[] getVariableDecls() {
     if (variableDecls != null) return variableDecls;
 
-    Vector contextVec = ctxt.getVariableDecls();
+    Vector<SemanticNode> contextVec = ctxt.getVariableDecls();
     variableDecls = new OpDeclNode[contextVec.size()];
     for (int i = 0, j = variableDecls.length - 1; i < variableDecls.length; i++) {
       variableDecls[j--] = (OpDeclNode)contextVec.elementAt(i);
@@ -437,14 +445,13 @@ public class ModuleNode extends SymbolNode {
     return thmOrAssDefs;
   }
 
-  /**
-   * Appends to vector of definitions in this module; should only be
-   * called with AssumeNodes, ModuleNodes, OpDefNodes and TheoremNodes
-   * as arguments.
-   */
-  public final void appendDef(SemanticNode s) {
-    definitions.addElement(s);
-  }
+	/**
+	 * Appends to vector of definitions in this module; should only be called with
+	 * AssumeNodes, ModuleNodes, OpDefNodes and TheoremNodes as arguments.
+	 */
+	public final void appendDef(SemanticNode s) {
+		definitions.add(s);
+	}
 
   /**
    * Returns array of the InstanceNode's representing module
@@ -547,6 +554,7 @@ public void setInstantiated(boolean isInstantiated) {
 
 /**
  * @return the isStandard
+ * @see tla2sany.modanalyzer.ParseUnit.isLibraryModule()
  */
 public boolean isStandard() {
 	return isStandard;
@@ -554,6 +562,7 @@ public boolean isStandard() {
 
 /**
  * @param isStandard the isStandard to set
+ * @see tla2sany.modanalyzer.ParseUnit.isLibraryModule()
  */
 public void setStandard(boolean isStandard) {
 	this.isStandard = isStandard;
@@ -610,20 +619,37 @@ final void addAssumption(TreeNode stn, ExprNode ass, SymbolTable st,
   }
 
 
-  public final HashSet getExtendedModuleSet() {
-    /***********************************************************************
-    * Returns a Hashset whose elements are ModuleNode objects representing  *
-    * all modules that are extended by this module--either directly or      *
-    * indirectly.                                                           *
-    ***********************************************************************/
-    if (this.allExtendees == null) {
-      this.allExtendees = new HashSet() ;
-      for (int i = 0; i < this.extendees.length; i++) {
-        this.allExtendees.add(this.extendees[i]) ;
-        this.allExtendees.addAll(this.extendees[i].getExtendedModuleSet()) ;
-       } // for
-      }; //if
-    return this.allExtendees ;
+  public final HashSet<ModuleNode> getExtendedModuleSet() {
+	  return getExtendedModuleSet(true);
+  }
+
+  /**
+   * @param recursively if true, the extendees of extendees of extendees of ...
+   * 						will be included; if false, only the direct extendees
+   * 						of this instance will be returned.
+   * @return
+   */
+  public final HashSet<ModuleNode> getExtendedModuleSet(final boolean recursively) {
+		/***********************************************************************
+		 * Returns a Hashset whose elements are ModuleNode objects representing *
+		 * all modules that are extended by this module--either directly or     *
+		 * indirectly.                                                          *
+		 ***********************************************************************/
+	  final Boolean key = Boolean.valueOf(recursively);
+	  HashSet<ModuleNode> extendeesSet = depthAllExtendeesMap.get(key);
+	  if (extendeesSet == null) {
+		  extendeesSet = new HashSet<>();
+		  for (int i = 0; i < this.extendees.length; i++) {
+			  extendeesSet.add(extendees[i]);
+			  if (recursively) {
+				  extendeesSet.addAll(extendees[i].getExtendedModuleSet(true));
+			  }
+		  }
+		  
+		  depthAllExtendeesMap.put(key, extendeesSet);
+	  }
+	  
+	  return extendeesSet;
   }
 
   public boolean extendsModule(ModuleNode mod) {
@@ -752,8 +778,7 @@ final void addAssumption(TreeNode stn, ExprNode ass, SymbolTable st,
       * opDefsInRecursiveSection vector.                                   *
       *********************************************************************/
       int curNodeIdx = firstInSectIdx ;
-      OpDefNode curNode =
-          (OpDefNode) opDefsInRecursiveSection.elementAt(curNodeIdx);
+      OpDefNode curNode = opDefsInRecursiveSection.elementAt(curNodeIdx);
       int curSection = curNode.recursiveSection ;
       boolean notDone = true ;
       while (notDone) {
@@ -777,8 +802,7 @@ final void addAssumption(TreeNode stn, ExprNode ass, SymbolTable st,
          else {curNode.levelChecked = 0 ;};
         curNodeIdx++ ;
         if (curNodeIdx < opDefsInRecursiveSection.size()) {
-          curNode = (OpDefNode)
-                        opDefsInRecursiveSection.elementAt(curNodeIdx);
+          curNode = opDefsInRecursiveSection.elementAt(curNodeIdx);
           notDone = (curNode.recursiveSection == curSection) ;
          }
         else {notDone = false ;} ;
@@ -796,7 +820,7 @@ final void addAssumption(TreeNode stn, ExprNode ass, SymbolTable st,
       HashSet recursiveLevelParams = new HashSet() ;
       HashSet recursiveAllParams = new HashSet() ;
       for (int i = firstInSectIdx ; i < curNodeIdx ; i++) {
-        curNode = (OpDefNode) opDefsInRecursiveSection.elementAt(i) ;
+        curNode = opDefsInRecursiveSection.elementAt(i) ;
         if (curNode.inRecursive) {curNode.levelChecked = 0 ;} ;
         curNode.levelCheck(1) ;
 
@@ -824,7 +848,7 @@ final void addAssumption(TreeNode stn, ExprNode ass, SymbolTable st,
       * for every operator in the recursive section.                       *
       *********************************************************************/
       for (int i = firstInSectIdx ; i < curNodeIdx ; i++) {
-        curNode = (OpDefNode) opDefsInRecursiveSection.elementAt(i) ;
+        curNode = opDefsInRecursiveSection.elementAt(i) ;
         if (curNode.inRecursive) {curNode.levelChecked = 2;} ;
         curNode.level = Math.max(curNode.level, maxRecursiveLevel) ;
         curNode.levelParams.addAll(recursiveLevelParams) ;
@@ -836,7 +860,7 @@ final void addAssumption(TreeNode stn, ExprNode ass, SymbolTable st,
       * recursive section.                                                 *
       *********************************************************************/
       for (int i = firstInSectIdx ; i < curNodeIdx ; i++) {
-        curNode = (OpDefNode) opDefsInRecursiveSection.elementAt(i) ;
+        curNode = opDefsInRecursiveSection.elementAt(i) ;
         if (curNode.inRecursive) {curNode.levelChecked = 1;} ;
         curNode.levelCheck(2) ;
        }; // for i
diff --git a/tlatools/src/tla2sany/semantic/NumeralNode.java b/tlatools/src/tla2sany/semantic/NumeralNode.java
index 675a09ece57ce0ea5b89a5ebb0b280b6c18028c1..ff1f369a9c26b20ba5326c6636a252ab69001da3 100644
--- a/tlatools/src/tla2sany/semantic/NumeralNode.java
+++ b/tlatools/src/tla2sany/semantic/NumeralNode.java
@@ -67,6 +67,15 @@ public class NumeralNode extends ExprNode {
   public final int val() { return this.value; }
 
   public final BigInteger bigVal() { return this.bigValue; }
+  
+  	/**
+	 * @return true if the numerical value of this instance should be referenced via
+	 *         {@link #val()}, false if it should be referenced via
+	 *         {@link #bigVal()}
+	 */
+  public final boolean useVal() {
+	  return (bigValue == null);
+  }
 
   /**
    * Returns the value as a string--for example, "4095".  This string
diff --git a/tlatools/src/tla2sany/semantic/OpApplNode.java b/tlatools/src/tla2sany/semantic/OpApplNode.java
index 06a745392ff055bed8f53405a916f85f645101c1..474c05c481283ce2bf7207d3d3b962ea830f6b45 100644
--- a/tlatools/src/tla2sany/semantic/OpApplNode.java
+++ b/tlatools/src/tla2sany/semantic/OpApplNode.java
@@ -270,6 +270,15 @@ public class OpApplNode extends ExprNode implements ExploreNode {
    */
   public final void setArgs(ExprOrOpArgNode[] args) { this.operands = args; }
 
+	public final boolean argsContainOpArgNodes() {
+		for (ExprOrOpArgNode o : operands) {
+			if (o instanceof OpArgNode) {
+				return true;
+			}
+		}
+		return false;
+	}
+  
   /*************************************************************************
   * Despite what you might gather from its 79 character name, this does    *
   * not return the number of bounded bound symbols.  It returns a weird    *
diff --git a/tlatools/src/tla2sany/semantic/OpDefNode.java b/tlatools/src/tla2sany/semantic/OpDefNode.java
index 343c3033db2e88ab724bf57177d46e3dd68e7d8e..3b5c9f958fc89d8caada229ac2d81b1107ba8eec 100644
--- a/tlatools/src/tla2sany/semantic/OpDefNode.java
+++ b/tlatools/src/tla2sany/semantic/OpDefNode.java
@@ -46,6 +46,7 @@ import tla2sany.st.TreeNode;
 import tla2sany.utilities.Strings;
 import tla2sany.utilities.Vector;
 import tla2sany.xml.SymbolContext;
+import tlc2.tool.BuiltInOPs;
 import util.UniqueString;
 import util.WrongInvocationException;
 
@@ -1211,6 +1212,10 @@ public class OpDefNode extends OpDefOrDeclNode
   }
 
 
+  public boolean hasOpcode(final int opCode) {
+      return opCode == BuiltInOPs.getOpCode(getName());
+  }
+
   /**
    * The body is the node's only child.
    */
diff --git a/tlatools/src/tla2sany/semantic/SemanticNode.java b/tlatools/src/tla2sany/semantic/SemanticNode.java
index 5419d08cda79b5160a7b1fe07c168550f2c140e1..fc265c0b64c071eab9e836ab7dccc20b95ce787d 100644
--- a/tlatools/src/tla2sany/semantic/SemanticNode.java
+++ b/tlatools/src/tla2sany/semantic/SemanticNode.java
@@ -202,6 +202,10 @@ public abstract class SemanticNode
 	  return Context.isBuiltIn(this);
   }
 
+  /**
+   * @see tla2sany.modanalyzer.ParseUnit.isLibraryModule()
+   * @see StandardModules.isDefinedInStandardModule()
+   */
   public boolean isStandardModule() {
 	  return StandardModules.isDefinedInStandardModule(this);
   }
diff --git a/tlatools/src/tla2sany/semantic/StandardModules.java b/tlatools/src/tla2sany/semantic/StandardModules.java
index 3a07ea36216de71b4992e448b93b31b245cc03b2..7c8634a2685a5294c61850ab2bb9b76ef503def8 100644
--- a/tlatools/src/tla2sany/semantic/StandardModules.java
+++ b/tlatools/src/tla2sany/semantic/StandardModules.java
@@ -29,22 +29,21 @@ import java.util.HashSet;
 import java.util.Set;
 
 public class StandardModules {
-
-	private static final Set<String> standardModules = new HashSet<>();
+	private static final Set<String> STANDARD_MODULES = new HashSet<>();
 	
 	static {
 		// Quick'n'Dirty hack! This breaks if any one of the operators is override by
 		// the model or a complete standard module has been replaced by a user-defined
 		// module with the same name.
-		standardModules.add("FiniteSets");
-		standardModules.add("Sequences");
-		standardModules.add("Bags");
-		standardModules.add("Naturals");
-		standardModules.add("Integers");
-		standardModules.add("Reals");
-		standardModules.add("RealTime");
-		standardModules.add("Randomization");
-		standardModules.add("TLC");
+		STANDARD_MODULES.add("FiniteSets");
+		STANDARD_MODULES.add("Sequences");
+		STANDARD_MODULES.add("Bags");
+		STANDARD_MODULES.add("Naturals");
+		STANDARD_MODULES.add("Integers");
+		STANDARD_MODULES.add("Reals");
+		STANDARD_MODULES.add("RealTime");
+		STANDARD_MODULES.add("Randomization");
+		STANDARD_MODULES.add("TLC");
 	}
 
 	private StandardModules() {
@@ -52,10 +51,17 @@ public class StandardModules {
 	}
 	
 	public static boolean isDefinedInStandardModule(SemanticNode sn) {
-		if (sn != null && sn.getLocation() != null) {
-			final String source = sn.getLocation().source(); // source might be null
-			return standardModules.contains(source);
+		if ((sn != null) && (sn.getLocation() != null)) {
+			return isDefinedInStandardModule(sn.getLocation().source()); // source might be null
 		}
 		return false;
 	}
+	
+	public static boolean isDefinedInStandardModule(final String moduleName) {
+		return STANDARD_MODULES.contains(moduleName);
+	}
+	
+	public static void filterNonStandardModulesFromSet(final Set<String> listOfModules) {
+		listOfModules.retainAll(STANDARD_MODULES);
+	}
 }
diff --git a/tlatools/src/tla2sany/st/Location.java b/tlatools/src/tla2sany/st/Location.java
index ffa60fb24cbe2dbc2924cff660de0c40b2db4f10..a56c755a474eb05cda2bc31fcdf41bffc2ebd419 100644
--- a/tlatools/src/tla2sany/st/Location.java
+++ b/tlatools/src/tla2sany/st/Location.java
@@ -9,6 +9,7 @@ import java.util.regex.Pattern;
 import pcal.PCalLocation;
 import pcal.Region;
 import util.Assert;
+import util.TLAConstants;
 import util.UniqueString;
 
 /**
@@ -22,7 +23,7 @@ import util.UniqueString;
 public final class Location implements Comparable<Location>
 {
     // strings used in toString() and Regex
-    private static final String LINE = "line ";
+    private static final String LINE = TLAConstants.LINE;
     private static final String LINE_CAP = "Line ";
     private static final String TO_LINE = " to line ";
     private static final String COL = ", col ";
@@ -394,6 +395,14 @@ public final class Location implements Comparable<Location>
 		return new pcal.Region(new PCalLocation(bLine - 1, bColumn - 1),
 				new PCalLocation(eLine - 1, eColumn - 1));
 	}
+	
+	/**
+	 * @param line
+	 * @return returns true if line is in [beginLine, endLine]
+	 */
+	public boolean containsLine(final int line) {
+		return ((line >= bLine) && (line <= eLine));
+	}
 
 	@Override
 	public int compareTo(final Location other) {
diff --git a/tlatools/src/tla2tex/BuiltInSymbols.java b/tlatools/src/tla2tex/BuiltInSymbols.java
index 83c3ccfdd4f8b952a91e6e52fd8d9587ed33a244..f378c7042dd5e7220be2b62a074640765db56b15 100644
--- a/tlatools/src/tla2tex/BuiltInSymbols.java
+++ b/tlatools/src/tla2tex/BuiltInSymbols.java
@@ -33,6 +33,8 @@ package tla2tex;
 import java.util.Enumeration;
 import java.util.Hashtable;
 
+import util.TLAConstants;
+
 public final class BuiltInSymbols
   { 
     /***********************************************************************
@@ -224,7 +226,7 @@ public final class BuiltInSymbols
              // Changed to INFIX from KEYWORD by LL on 21 July 2012 to allow 
              // left-aligning with [].  It produces something reasonable when
              // a bunch of [] symbols are right-aligned with CASE as well.
-        add("CONSTANT",   "{\\CONSTANT}",    Symbol.KEYWORD, 0);
+        add(TLAConstants.KeyWords.CONSTANT,   "{\\CONSTANT}",    Symbol.KEYWORD, 0);
         add("CONSTANTS",  "{\\CONSTANTS}",   Symbol.KEYWORD, 0);
         add("EXCEPT",     "{\\EXCEPT}",      Symbol.KEYWORD, 0);
         add("EXTENDS",    "{\\EXTENDS}",     Symbol.KEYWORD, 0);
@@ -237,7 +239,7 @@ public final class BuiltInSymbols
         add("STRING",     "{\\STRING}",      Symbol.KEYWORD, 0);
         add("THEOREM",    "{\\THEOREM}",     Symbol.KEYWORD, 0);
         add("TRUE",       "{\\TRUE}",        Symbol.KEYWORD, 0);
-        add("VARIABLE",   "{\\VARIABLE}",    Symbol.KEYWORD, 0);
+        add(TLAConstants.KeyWords.VARIABLE,   "{\\VARIABLE}",    Symbol.KEYWORD, 0);
         add("VARIABLES",  "{\\VARIABLES}",   Symbol.KEYWORD, 0);
         add("WITH",       "{\\WITH}",        Symbol.KEYWORD, 0);
 // The following added for tla2tex
diff --git a/tlatools/src/tla2tex/TLA.java b/tlatools/src/tla2tex/TLA.java
index 11eeace340a36009a88c7553233c344dddeb62ee..7109379a265aa1b0c0d8d0b1a5566f21ea93f6ce 100644
--- a/tlatools/src/tla2tex/TLA.java
+++ b/tlatools/src/tla2tex/TLA.java
@@ -126,6 +126,7 @@ import java.io.File;
 import java.io.IOException;
 
 import util.FileUtil;
+import util.TLAConstants;
 import util.ToolIO;
 
 public class TLA
@@ -437,7 +438,7 @@ public class TLA
                 Parameters.TLAOutFile = args[nextArg];
                 if (Parameters.TLAOutFile.indexOf(".") == -1)
                 {
-                    Parameters.TLAOutFile = Parameters.TLAOutFile + ".tla";
+                    Parameters.TLAOutFile = Parameters.TLAOutFile + TLAConstants.Files.TLA_EXTENSION;
                 }
                 if (HasPathPrefix(Parameters.TLAOutFile))
                 {
@@ -636,7 +637,7 @@ public class TLA
         ********************************************************************/
         if (args[maxArg].indexOf(".") == -1)
         {
-            Parameters.TLAInputFile = args[maxArg] + ".tla";
+            Parameters.TLAInputFile = args[maxArg] + TLAConstants.Files.TLA_EXTENSION;
         } else
         {
             Parameters.TLAInputFile = args[maxArg];
diff --git a/tlatools/src/tlc2/REPLSpecWriter.java b/tlatools/src/tlc2/REPLSpecWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..74af71313721d8eaca7062befd20b187a1fdffd5
--- /dev/null
+++ b/tlatools/src/tlc2/REPLSpecWriter.java
@@ -0,0 +1,84 @@
+package tlc2;
+
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+
+import tlc2.output.AbstractSpecWriter;
+import tlc2.output.SpecWriterUtilities;
+
+class REPLSpecWriter extends AbstractSpecWriter {
+	private static final String EXPRESSION_OPEN = "\"EXPR_TLATE_BEGIN\"";
+	private static final String EXPRESSION_CLOSE = "\"EXPR_TLATE_END\"";
+	private static final String ASSUME_PREFIX = "ASSUME PrintT(" + EXPRESSION_OPEN + ") /\\ PrintT(\n";
+	private static final String ASSUME_SUFFIX = "\n) /\\ PrintT(" + EXPRESSION_CLOSE + ")\n";
+
+	REPLSpecWriter(final String specName, final List<String> expressions) {
+		super(true);
+		
+		tlaBuffer.append(SpecWriterUtilities.getExtendingModuleContent(specName,
+																	   "Naturals", "Reals", "Sequences", "Bags",
+																	   "FiniteSets", "TLC"));
+		tlaBuffer.append(ASSUME_PREFIX);
+		tlaBuffer.append(String.join("\n", expressions));
+		tlaBuffer.append(ASSUME_SUFFIX);
+	}
+	
+	
+	static class REPLLogConsumerStream extends ByteArrayOutputStream {
+		private boolean inResponse;
+		private boolean haveCollected;
+		private StringBuilder currentLine;
+		
+		private String collectedContent;
+		
+		REPLLogConsumerStream() {
+			inResponse = false;
+			haveCollected = false;
+			currentLine = new StringBuilder();
+		}
+		
+		String getCollectedContent() {
+			return collectedContent;
+		}
+		
+		// Being wrapped in a Buffer invokes this method, we sub-optimally pass it off to our real digestion below
+		@Override
+		public void write(final byte b[], final int off, final int len) {
+			for (int i = off; i < (off + len); i++) {
+				write(b[i]);
+			}
+		}
+
+		@Override
+		public void write(final int b) {
+			if (haveCollected) {
+				return;
+			} else {
+				if (b == '\n') {
+					if (inResponse) {
+						if (EXPRESSION_CLOSE.equals(currentLine.toString())) {
+							haveCollected = true;
+							
+							final String allCollectedContent = toString();
+							final int length = allCollectedContent.length();
+							collectedContent = allCollectedContent.substring(0, (length - (EXPRESSION_CLOSE.length() + 1)));
+						} else {
+							super.write(b);
+						}
+					} else if (EXPRESSION_OPEN.equals(currentLine.toString())) {
+						inResponse = true;
+					}
+					
+					currentLine = new StringBuilder();
+ 				} else {
+					if (inResponse) {
+						super.write(b);
+					}
+ 					
+ 					// casting to char is probably not the best thing - suffices for the majority of the presumed cases
+ 					currentLine.append((char)b);
+ 				}
+			}
+		}
+	}
+}
diff --git a/tlatools/src/tlc2/TLC.java b/tlatools/src/tlc2/TLC.java
index bc31ed61f1251cbd3324e493d2c9484d0168636b..3d180a7ca1c0c954709df872b1db3265b382a25d 100644
--- a/tlatools/src/tlc2/TLC.java
+++ b/tlatools/src/tlc2/TLC.java
@@ -5,10 +5,19 @@
 
 package tlc2;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
 import java.io.BufferedWriter;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.FileWriter;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.io.PrintStream;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Date;
@@ -17,19 +26,27 @@ import java.util.List;
 import java.util.Map;
 import java.util.Random;
 import java.util.TimeZone;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import model.InJarFilenameToStream;
 import model.ModelInJar;
+import tlc2.input.MCOutputPipeConsumer;
+import tlc2.input.MCParser;
+import tlc2.input.MCParserResults;
 import tlc2.output.EC;
 import tlc2.output.MP;
+import tlc2.output.Messages;
+import tlc2.output.TLAMonolithCreator;
+import tlc2.output.TeeOutputStream;
 import tlc2.tool.DFIDModelChecker;
-import tlc2.tool.ITool;
 import tlc2.tool.ModelChecker;
 import tlc2.tool.Simulator;
 import tlc2.tool.fp.FPSet;
 import tlc2.tool.fp.FPSetConfiguration;
 import tlc2.tool.fp.FPSetFactory;
-import tlc2.tool.impl.Tool;
+import tlc2.tool.impl.FastTool;
+import tlc2.tool.impl.ModelConfig;
+import tlc2.tool.impl.SpecProcessor;
 import tlc2.tool.management.ModelCheckerMXWrapper;
 import tlc2.tool.management.TLCStandardMBean;
 import tlc2.util.DotStateWriter;
@@ -46,24 +63,34 @@ import util.FileUtil;
 import util.FilenameToStream;
 import util.MailSender;
 import util.SimpleFilenameToStream;
+import util.TLAConstants;
 import util.TLCRuntime;
 import util.ToolIO;
 import util.UniqueString;
+import util.UsageGenerator;
 
 /**
- * Main TLC starter class
+ * Main TLC starter class.
+ * 
+ * <b>Note:</b> If you are using a new instance of this class in an already existant JVM which has done processing with
+ * 			tlc2 parsers, please see the class javadocs for {@link TLCRunner}
+ * 
  * @author Yuan Yu
  * @author Leslie Lamport
  * @author Simon Zambrovski
  */
-public class TLC
-{
-    
+public class TLC {
     private static boolean MODEL_PART_OF_JAR = false;
+    
+    private enum RunMode {
+    	MODEL_CHECK, SIMULATE;
+    }
+    
 
     // SZ Feb 20, 2009: the class has been 
     // transformed from static to dynamic
-    private boolean isSimulate; 
+
+    private RunMode runMode;
     private boolean cleanup;
     private boolean deadlock;
 
@@ -78,7 +105,7 @@ public class TLC
 	private String metadir;
     /**
 	 * If instantiated with a non-Noop* instance, the trace will be written to the
-	 * user provided file (-dump paramter).
+	 * user provided file (-dump parameter).
 	 * <p>
 	 * Contrary to plain -dump, -dot will also write out transitions from state s to
 	 * s' if s' is already known. Thus, the resulting graph shows all successors of
@@ -104,14 +131,21 @@ public class TLC
     
     private FPSetConfiguration fpSetConfiguration;
     
+    private File temporaryMCOutputLogFile;
+    private FileOutputStream temporaryMCOutputStream;
+    private File specTETLAFile;
+    private MCParserResults mcParserResults;
+    private MCOutputPipeConsumer mcOutputConsumer;
+    private boolean avoidMonolithSpecTECreation;
+    private final AtomicBoolean waitingOnGenerationCompletion;
+    
     /**
      * Initialization
      */
-    public TLC()
-    {
+	public TLC() {
         welcomePrinted = false;
         
-        isSimulate = false; // Default to model checking
+        runMode = RunMode.MODEL_CHECK;
         cleanup = false;
         deadlock = true;
         
@@ -128,71 +162,79 @@ public class TLC
         traceDepth = 100;
 
         fpSetConfiguration = new FPSetConfiguration();
-    }
+        
+        avoidMonolithSpecTECreation = false;
+        waitingOnGenerationCompletion = new AtomicBoolean(false);
+	}
 
     /*
      * This TLA checker (TLC) provides the following functionalities:
-     *  1. Simulation of TLA+ specs: java tlc2.TLC -simulate spec[.tla]
-     *  2. Model checking of TLA+ specs: java tlc2.TLC [-modelcheck] spec[.tla]
+     *  1. Simulation of TLA+ specs:
+     *  				java tlc2.TLC -simulate spec[.tla]
+     *  2. Model checking of TLA+ specs:
+     *  				java tlc2.TLC [-modelcheck] spec[.tla]
      *
-     * The command line also provides the following options:
+     * The command line also provides the following options observed for functionalities 1. & 2.:
      *  o -config file: provide the config file.
-     *    Defaults to spec.cfg if not provided
+     *		Defaults to spec.cfg if not provided
      *  o -deadlock: do not check for deadlock.
-     *    Defaults to checking deadlock if not specified
+     *		Defaults to checking deadlock if not specified
      *  o -depth num: specify the depth of random simulation 
-     *    Defaults to 100 if not specified
+     *		Defaults to 100 if not specified
      *  o -seed num: provide the seed for random simulation
-     *    Defaults to a random seed if not specified
+     *		Defaults to a random seed if not specified
      *  o -aril num: Adjust the seed for random simulation
-     *    Defaults to 0 if not specified
+     *		Defaults to 0 if not specified
      *  o -recover path: recover from the checkpoint at path
-     *    Defaults to scratch run if not specified
-     *  o -bound: The upper limit for sets effectively limiting the number of init states
-     *    (@see Bug #264 in general/bugzilla/index.html)
-     *    Defaults to 1000000 if not specified
+     *		Defaults to scratch run if not specified
      *  o -metadir path: store metadata in the directory at path
-     *    Defaults to specdir/states if not specified
+     *		Defaults to specdir/states if not specified
 	 *  o -userFile file: A full qualified/absolute path to a file to log user
-	 *    output (Print/PrintT/...) to
+	 *					output (Print/PrintT/...) to
      *  o -workers num: the number of TLC worker threads
-     *    Defaults to 1
+     *		Defaults to 1
      *  o -dfid num: use depth-first iterative deepening with initial depth num
      *  o -cleanup: clean up the states directory
      *  o -dump [dot] file: dump all the states into file. If "dot" as sub-parameter
-     *                      is given, the output will be in dot notation.
+     *					is given, the output will be in dot notation.
      *  o -difftrace: when printing trace, show only
-     *                the differences between successive states
-     *    Defaults to printing full state descriptions if not specified
-     *    (Added by Rajeev Joshi)
+     *					the differences between successive states
+     *		Defaults to printing full state descriptions if not specified
+     *					(Added by Rajeev Joshi)
      *  o -terse: do not expand values in Print statement
-     *    Defaults to expand value if not specified
+     *		Defaults to expand value if not specified
      *  o -coverage minutes: collect coverage information on the spec,
-     *                       print out the information every minutes.
-     *    Defaults to no coverage if not specified
+     *					print out the information every minutes.
+     *		Defaults to no coverage if not specified
      *  o -continue: continue running even when invariant is violated
-     *    Defaults to stop at the first violation if not specified
+     *		Defaults to stop at the first violation if not specified
      *  o -lncheck: Check liveness properties at different times
-     *    of model checking.
-     *    Defaults to false increasing the overall model checking time.
+     *					of model checking.
+     *		Defaults to false increasing the overall model checking time.
      *  o -nowarning: disable all the warnings
-     *    Defaults to report warnings if not specified
+     *		Defaults to report warnings if not specified
      *  o -fp num: use the num'th irreducible polynomial from the list
-     *    stored in the class FP64.
+     *					stored in the class FP64.
      *  o -view: apply VIEW (if provided) when printing out states.
      *  o -gzip: control if gzip is applied to value input/output stream.
-     *    Defaults to off if not specified
+     *		Defaults to off if not specified
      *  o -debug: debbuging information (non-production use)
      *  o -tool: tool mode (put output codes on console)
+     *  o -generateSpecTE: will generate SpecTE assets if error-states are
+     *  				encountered during model checking; this will change
+     *  				to tool mode regardless of whether '-tool' was
+     *  				explicitly specified; add on 'nomonolith' to not
+     *  				embed the dependencies in the SpecTE
      *  o -checkpoint num: interval for check pointing (in minutes)
-     *     Defaults to 30
-     *  o -fpmem num: the number of megabytes of memory used to store
-     *                the fingerprints of found states.
-     *  Defaults to 1/4 physical memory.  (Added 6 Apr 2010 by Yuan Yu.)
+     *		Defaults to 30
+     *  o -fpmem num: a value between 0 and 1, exclusive, representing the ratio
+     *  				of total system memory used to store the fingerprints of
+     *  				found states.
+     *  	Defaults to 1/4 physical memory.  (Added 6 Apr 2010 by Yuan Yu.)
      *  o -fpbits num: the number of msb used by MultiFPSet to create nested FPSets.
-     *  Defaults to 1
+     *  	Defaults to 1
      *  o -maxSetSize num: the size of the largest set TLC will enumerate.
-     *                     default: 1000000
+     *		Defaults to 1000000
      *   
      */
     public static void main(String[] args) throws Exception
@@ -215,33 +257,33 @@ public class TLC
             System.exit(1);
         }
 
-        // Setup how spec files will be resolved in the filesystem.
-        if (MODEL_PART_OF_JAR) {
-            // There was not spec file given, it instead exists in the
-            // .jar file being executed. So we need to use a special file
-            // resolver to parse it.
-        	tlc.setResolver(new InJarFilenameToStream(ModelInJar.PATH));
-        } else {
-            // The user passed us a spec file directly. To ensure we can
-            // recover it during semantic parsing, we must include its
-            // parent directory as a library path in the file resolver.
-            //
-            // If the spec file has no parent directory, use the "standard"
-            // library paths provided by SimpleFilenameToStream.
-            final String dir = FileUtil.parseDirname(tlc.getMainFile());
-            if (!dir.isEmpty()) {
-            	tlc.setResolver(new SimpleFilenameToStream(dir));
-            } else {
-            	tlc.setResolver(new SimpleFilenameToStream());
-            }
-        }
-        
+		final MailSender ms = new MailSender();
+		// Setup how spec files will be resolved in the filesystem.
+		if (MODEL_PART_OF_JAR) {
+			// There was not spec file given, it instead exists in the
+			// .jar file being executed. So we need to use a special file
+			// resolver to parse it.
+			tlc.setResolver(new InJarFilenameToStream(ModelInJar.PATH));
+		} else {
+			// The user passed us a spec file directly. To ensure we can
+			// recover it during semantic parsing, we must include its
+			// parent directory as a library path in the file resolver.
+			//
+			// If the spec file has no parent directory, use the "standard"
+			// library paths provided by SimpleFilenameToStream.
+			final String dir = FileUtil.parseDirname(tlc.getMainFile());
+			if (!dir.isEmpty()) {
+				tlc.setResolver(new SimpleFilenameToStream(dir));
+			} else {
+				tlc.setResolver(new SimpleFilenameToStream());
+			}
+		}
+
 		// Setup MailSender *before* calling tlc.process. The MailSender's task it to
 		// write the MC.out file. The MC.out file is e.g. used by CloudTLC to feed
 		// progress back to the Toolbox (see CloudDistributedTLCJob).
-        final MailSender ms = new MailSender();
-        ms.setModelName(tlc.getModelName());
-        ms.setSpecName(tlc.getSpecName());
+		ms.setModelName(tlc.getModelName());
+		ms.setSpecName(tlc.getSpecName());
 
         // Execute TLC.
         final int errorCode = tlc.process();
@@ -291,12 +333,14 @@ public class TLC
      * @throws IOException 
      */
     // SZ Feb 23, 2009: added return status to indicate the error in parsing
+	@SuppressWarnings("deprecation")	// we're emitting a warning to the user, but still accepting fpmem values > 1
 	public boolean handleParameters(String[] args)
     {
 		String dumpFile = null;
 		boolean asDot = false;
 	    boolean colorize = false;
 	    boolean actionLabels = false;
+		boolean snapshot = false;
 		
         // SZ Feb 20, 2009: extracted this method to separate the 
         // parameter handling from the actual processing
@@ -305,7 +349,7 @@ public class TLC
         {
             if (args[index].equals("-simulate"))
             {
-                isSimulate = true;
+            	runMode = RunMode.SIMULATE;
                 index++;
                 
 				// Simulation args can be:
@@ -313,7 +357,7 @@ public class TLC
 				// file=/path/to/file
 				// "file=..." and "num=..." are only relevant for simulation which is why they
 				// are args to "-simulate".
-				if (index + 1 < args.length && (args[index].contains("file=") || args[index].contains("num="))) {
+				if (((index + 1) < args.length) && (args[index].contains("file=") || args[index].contains("num="))) {
 					final String[] simArgs = args[index].split(",");
 					index++; // consume simulate args
 					for (String arg : simArgs) {
@@ -324,10 +368,8 @@ public class TLC
 						}
 					}
 				}
-            } else if (args[index].equals("-modelcheck"))
-            {
-                isSimulate = false;
-                index++;
+			} else if (args[index].equals("-modelcheck")) {
+				index++;
             } else if (args[index].equals("-difftrace"))
             {
                 index++;
@@ -368,7 +410,107 @@ public class TLC
             {
                 index++;
                 TLCGlobals.tool = true;
-            } else if (args[index].equals("-help"))
+            } else if (args[index].equals("-generateSpecTE")) {
+                index++;
+            	
+                TLCGlobals.tool = true;
+                
+                if ((index < args.length) && args[index].equals("nomonolith")) {
+                	index++;
+                	avoidMonolithSpecTECreation = true;
+                }
+				try {
+					temporaryMCOutputLogFile = File.createTempFile("mcout_", ".out");
+					temporaryMCOutputLogFile.deleteOnExit();
+					temporaryMCOutputStream = new FileOutputStream(temporaryMCOutputLogFile);
+					final BufferedOutputStream bos = new BufferedOutputStream(temporaryMCOutputStream);
+					final PipedInputStream pis = new PipedInputStream();
+					final TeeOutputStream tos1 = new TeeOutputStream(bos, new PipedOutputStream(pis));
+					final TeeOutputStream tos2 = new TeeOutputStream(ToolIO.out, tos1);
+					ToolIO.out = new PrintStream(tos2);
+					mcOutputConsumer = new MCOutputPipeConsumer(pis, null);
+					
+					// Note, this runnable's thread will not finish consuming output until just
+					// 	before the app exits and we will use the output consumer in the TLC main
+					//	thread while it is still consuming (but at a point where the model checking
+					//	itself has finished and so the consumer is as populated as we need it to be
+					//	- but prior to the output consumer encountering the EC.TLC_FINISHED message.)
+					final Runnable r = () -> {
+						boolean haveClosedOutputStream = false;
+						try {
+							waitingOnGenerationCompletion.set(true);
+							mcOutputConsumer.consumeOutput(false);
+							
+							bos.flush();
+							temporaryMCOutputStream.close();
+							haveClosedOutputStream = true;
+							
+							if (mcOutputConsumer.getError() != null) {
+								final File tempTLA = File.createTempFile("temp_tlc_tla_", ".tla");
+								tempTLA.deleteOnExit();
+								FileUtil.copyFile(specTETLAFile, tempTLA);
+								
+								final FileOutputStream fos = new FileOutputStream(specTETLAFile);
+								final FileInputStream mcOutFIS = new FileInputStream(temporaryMCOutputLogFile);
+								copyStream(mcOutFIS, fos);
+								
+								final FileInputStream tempTLAFIS = new FileInputStream(tempTLA);
+								copyStream(tempTLAFIS, fos);
+								
+								fos.close();
+								mcOutFIS.close();
+								tempTLAFIS.close();
+								
+								final TLAMonolithCreator monolithCreator;
+								if (avoidMonolithSpecTECreation) {
+									monolithCreator
+										= new TLAMonolithCreator(TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME,
+																 mcOutputConsumer.getSourceDirectory(),
+																 mcParserResults.getAllExtendedModules());
+								} else {
+									final List<File> extendedModules = mcOutputConsumer.getExtendedModuleLocations();
+									monolithCreator
+										= new TLAMonolithCreator(TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME,
+																 mcOutputConsumer.getSourceDirectory(),
+																 extendedModules,
+																 mcParserResults.getAllExtendedModules(),
+																 mcParserResults.getAllInstantiatedModules());
+								}
+								
+								monolithCreator.copy();
+							}
+							
+							waitingOnGenerationCompletion.set(false);
+							synchronized(this) {
+								notifyAll();
+							}
+						} catch (final Exception e) {
+							MP.printMessage(EC.GENERAL,
+											"A model checking error occurred while parsing tool output; the execution "
+													+ "ended before the potential "
+													+ TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME
+													+ " generation stage.");
+						} finally {
+							if (!haveClosedOutputStream) {
+								try {
+									bos.flush();
+									temporaryMCOutputStream.close();
+								} catch (final Exception e) { }
+							}
+						}
+					};
+					(new Thread(r)).start();
+					
+					MP.printMessage(EC.GENERAL,
+									"Will generate a " + TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME
+										+ " file pair if error states are encountered.");
+				} catch (final IOException ioe) {
+					printErrorMsg("Failed to set up piped output consumers; no potential "
+										+ TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME + " will be generated: "
+										+ ioe.getMessage());
+					mcOutputConsumer = null;
+				}
+            } else if (args[index].equals("-help") || args[index].equals("-h"))
             {
                 printUsage();
                 return false;
@@ -390,11 +532,10 @@ public class TLC
                 if (index < args.length)
                 {
                     configFile = args[index];
-                    int len = configFile.length();
-                    if (configFile.startsWith(".cfg", len - 4))
-                    {
-                        configFile = configFile.substring(0, len - 4);
-                    }
+					if (configFile.endsWith(TLAConstants.Files.CONFIG_EXTENSION)) {
+						configFile = configFile.substring(0,
+								(configFile.length() - TLAConstants.Files.CONFIG_EXTENSION.length()));
+					}
                     index++;
                 } else
                 {
@@ -404,13 +545,14 @@ public class TLC
             } else if (args[index].equals("-dump"))
             {
                 index++; // consume "-dump".
-                if (index + 1 < args.length && args[index].startsWith("dot"))
+                if (((index + 1) < args.length) && args[index].startsWith("dot"))
                 {
                 	final String dotArgs = args[index].toLowerCase();
                 	index++; // consume "dot...".
                 	asDot = true;
                 	colorize = dotArgs.contains("colorize");
                 	actionLabels = dotArgs.contains("actionlabels");
+                	snapshot = dotArgs.contains("snapshot");
 					dumpFile = getDumpFile(args[index++], ".dot");
                 }
                 else if (index < args.length)
@@ -759,16 +901,16 @@ public class TLC
                     return false;
                 }
                 mainFile = args[index++];
-                int len = mainFile.length();
-                if (mainFile.endsWith(".tla"))
+                if (mainFile.endsWith(TLAConstants.Files.TLA_EXTENSION))
                 {
-                    mainFile = mainFile.substring(0, len - 4);
+                    mainFile = mainFile.substring(0, (mainFile.length() - TLAConstants.Files.TLA_EXTENSION.length()));
                 }
             }
         }
-        
-        if (mainFile == null)
-        {
+                
+        startTime = System.currentTimeMillis();
+
+		if (mainFile == null) {
 			// command line omitted name of spec file, take this as an
 			// indicator to check the in-jar model/ folder for a spec.
 			// If a spec is found, use it instead.
@@ -777,40 +919,37 @@ public class TLC
 				ModelInJar.loadProperties();
 				TLCGlobals.tool = true; // always run in Tool mode (to parse output by Toolbox later)
 				TLCGlobals.chkptDuration = 0; // never use checkpoints with distributed TLC (highly inefficient)
-				mainFile = "MC";
+				mainFile = TLAConstants.Files.MODEL_CHECK_FILE_BASENAME;
 			} else {
 				printErrorMsg("Error: Missing input TLA+ module.");
 				return false;
 			}
-        }
-        
+		}
+
 		// The functionality to start TLC from an (absolute) path /path/to/spec/file.tla
 		// seems to have eroded over the years which is why this block of code is a
-		// clutch.  It essentially massages the variable values for mainFile, specDir and
-        // the user dir to make the code below - as well as the FilenameToStream resolver -
-        // work. Original issues was https://github.com/tlaplus/tlaplus/issues/24.
-        final File f = new File(mainFile);
-        String specDir = "";
-        if (f.isAbsolute()) {
-        	specDir = f.getParent() + FileUtil.separator;
-        	mainFile = f.getName();
-        	// Not setting user dir causes a ConfigFileException when the resolver
-        	// tries to read the .cfg file later in the game.
-        	ToolIO.setUserDir(specDir);
-        }
-        
-        if (configFile == null)
-        {
-            configFile = mainFile;
-        }
+		// clutch. It essentially massages the variable values for mainFile, specDir and
+		// the user dir to make the code below - as well as the FilenameToStream
+		// resolver -
+		// work. Original issues was https://github.com/tlaplus/tlaplus/issues/24.
+		final File f = new File(mainFile);
+		String specDir = "";
+		if (f.isAbsolute()) {
+			specDir = f.getParent() + FileUtil.separator;
+			mainFile = f.getName();
+			// Not setting user dir causes a ConfigFileException when the resolver
+			// tries to read the .cfg file later in the game.
+			ToolIO.setUserDir(specDir);
+		}
 
-        if (cleanup && fromChkpt == null)
-        {
-            // clean up the states directory only when not recovering
-            FileUtil.deleteDir(TLCGlobals.metaRoot, true);
-        }
-        
-        startTime = System.currentTimeMillis();
+		if (configFile == null) {
+			configFile = mainFile;
+		}
+
+		if (cleanup && (fromChkpt == null)) {
+			// clean up the states directory only when not recovering
+			FileUtil.deleteDir(TLCGlobals.metaRoot, true);
+		}
 
         // Check if mainFile is an absolute or relative file system path. If it is
 		// absolute, the parent gets used as TLC's meta directory (where it stores
@@ -818,40 +957,37 @@ public class TLC
 		// the current directory.
     	metadir = FileUtil.makeMetaDir(new Date(startTime), specDir, fromChkpt);
     	
-        if (dumpFile != null) {
-        	if (dumpFile.startsWith("${metadir}")) {
+		if (dumpFile != null) {
+			if (dumpFile.startsWith("${metadir}")) {
 				// prefix dumpfile with the known value of this.metadir. There
 				// is no way to determine the actual value of this.metadir
 				// before TLC startup and thus it's impossible to make the
 				// dumpfile end up in the metadir if desired.
-        		dumpFile = dumpFile.replace("${metadir}", metadir);
-        	}
-        	try {
-        		if (asDot) {
-        			this.stateWriter = new DotStateWriter(dumpFile, colorize, actionLabels);
-        		} else {
-        			this.stateWriter = new StateWriter(dumpFile);
-        		}
-        	} catch (IOException e) {
+				dumpFile = dumpFile.replace("${metadir}", metadir);
+			}
+			try {
+				if (asDot) {
+					this.stateWriter = new DotStateWriter(dumpFile, colorize, actionLabels, snapshot);
+				} else {
+					this.stateWriter = new StateWriter(dumpFile);
+				}
+			} catch (IOException e) {
 				printErrorMsg(String.format("Error: Given file name %s for dumping states invalid.", dumpFile));
 				return false;
-        	}
-        }
+			}
+		}
         
-        if (TLCGlobals.debug) 
-        {
-		StringBuffer buffer = new StringBuffer("TLC arguments:");
-		for (int i=0; i < args.length; i++)
-		{
-		    buffer.append(args[i]);
-		    if (i < args.length - 1) 
-		    {
-		        buffer.append(" ");
-		    }
+		if (TLCGlobals.debug) {
+			final StringBuilder buffer = new StringBuilder("TLC arguments:");
+			for (int i = 0; i < args.length; i++) {
+				buffer.append(args[i]);
+				if (i < args.length - 1) {
+					buffer.append(" ");
+				}
+			}
+			buffer.append("\n");
+			DebugPrinter.print(buffer.toString());
 		}
-            buffer.append("\n");
-            DebugPrinter.print(buffer.toString());
-        }
         
         // if no errors, print welcome message
         printWelcome();
@@ -895,8 +1031,7 @@ public class TLC
     		final RandomGenerator rng = new RandomGenerator();
             // Start checking:
             final int result;
-            if (isSimulate)
-            {
+			if (RunMode.SIMULATE.equals(runMode)) {
                 // random simulation
                 if (noSeed)
                 {
@@ -912,8 +1047,7 @@ public class TLC
                         traceNum, rng, seed, resolver, TLCGlobals.getNumWorkers());
                 TLCGlobals.simulator = simulator;
                 result = simulator.simulate();
-            } else
-            {
+			} else { // RunMode.MODEL_CHECK
 				if (noSeed) {
                     seed = rng.nextLong();
 				}
@@ -927,12 +1061,12 @@ public class TLC
 				printStartupBanner(isBFS() ? EC.TLC_MODE_MC : EC.TLC_MODE_MC_DFS, getModelCheckingRuntime(fpIndex, fpSetConfiguration));
 				
             	// model checking
-		        final ITool tool = new Tool(mainFile, configFile, resolver);
-
+		        final FastTool tool = new FastTool(mainFile, configFile, resolver);
                 if (isBFS())
                 {
 					TLCGlobals.mainChecker = new ModelChecker(tool, metadir, stateWriter, deadlock, fromChkpt,
-							FPSetFactory.getFPSetInitialized(fpSetConfiguration, metadir, mainFile), startTime);
+							FPSetFactory.getFPSetInitialized(fpSetConfiguration, metadir, new File(mainFile).getName()),
+							startTime);
 					modelCheckerMXWrapper = new ModelCheckerMXWrapper((ModelChecker) TLCGlobals.mainChecker, this);
 					result = TLCGlobals.mainChecker.modelCheck();
                 } else
@@ -940,6 +1074,21 @@ public class TLC
 					TLCGlobals.mainChecker = new DFIDModelChecker(tool, metadir, stateWriter, deadlock, fromChkpt, startTime);
 					result = TLCGlobals.mainChecker.modelCheck();
                 }
+
+                if ((mcOutputConsumer != null) && (mcOutputConsumer.getError() != null)) {
+            		final SpecProcessor sp = tool.getSpecProcessor();
+            		final ModelConfig mc = tool.getModelConfig();
+            		final File sourceDirectory = mcOutputConsumer.getSourceDirectory();
+            		final String originalSpecName = mcOutputConsumer.getSpecName();
+            		
+            		MP.printMessage(EC.GENERAL,
+    								"The model check run produced error-states - we will generate the "
+    										+ TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME + " files now.");
+            		mcParserResults = MCParser.generateResultsFromProcessorAndConfig(sp, mc);
+            		final File[] files = TraceExplorer.writeSpecTEFiles(sourceDirectory, originalSpecName,
+            															mcParserResults, mcOutputConsumer.getError());
+            		specTETLAFile = files[0];
+                }
             }
             return result;
         } catch (Throwable e)
@@ -970,8 +1119,7 @@ public class TLC
         		try {
         			tlc2.module.TLC.OUTPUT.flush();
 					tlc2.module.TLC.OUTPUT.close();
-				} catch (IOException e) {
-				}
+				} catch (IOException e) { }
         	}
 			modelCheckerMXWrapper.unregister();
 			// In tool mode print runtime in milliseconds, in non-tool mode print human
@@ -980,9 +1128,17 @@ public class TLC
 			MP.printMessage(EC.TLC_FINISHED,
 					TLCGlobals.tool ? Long.toString(runtime) + "ms" : convertRuntimeToHumanReadable(runtime));
 			MP.flush();
+			
+	        while (waitingOnGenerationCompletion.get()) {
+	        	synchronized (this) {
+	        		try {
+	        			wait();
+	        		} catch (final InterruptedException ie) { }
+	        	}
+	        }
         }
     }
-
+    
 	private static boolean isBFS() {
 		return TLCGlobals.DFIDMax == -1;
 	}
@@ -1146,8 +1302,11 @@ public class TLC
 		parameters.remove("seed");
 		udc.putAll(parameters);
 		
-		// True if TLC is run from within the Toolbox.
+		// True if TLC is run from within the Toolbox. Derive ide name from .tool too
+		// unless set explicitly.  Eventually, we can probably remove the toolbox
+		// parameter.
 		udc.put("toolbox", Boolean.toString(TLCGlobals.tool));
+		udc.put("ide", System.getProperty(TLC.class.getName() + ".ide", TLCGlobals.tool ? "toolbox" : "cli"));
 		new ExecutionStatisticsCollector().collect(udc);
 	}
 	
@@ -1163,19 +1322,177 @@ public class TLC
 			return "unknown";
 		}
 	}
+	
+	/**
+	 * This is themed on commons-io-2.6's IOUtils.copyLarge(InputStream, OutputStream, byte[]) -
+	 * 	once we move to Java9+, dump this usage in favor of InputStream.transferTo(OutputStream)
+	 * 
+	 * @param is
+	 * @param os
+	 * @return the count of bytes copied
+	 * @throws IOException
+	 */
+	private static long copyStream(final InputStream is, final OutputStream os) throws IOException {
+		final byte[] buffer = new byte[1024 * 4];
+		long byteCount = 0;
+		int n;
+		final BufferedInputStream bis = (is instanceof BufferedInputStream) ? (BufferedInputStream)is
+																			: new BufferedInputStream(is);
+		final BufferedOutputStream bos = (os instanceof BufferedOutputStream) ? (BufferedOutputStream)os
+																			  : new BufferedOutputStream(os);
+		while ((n = bis.read(buffer)) != -1) {
+			bos.write(buffer, 0, n);
+			byteCount += n;
+		}
+		
+		bos.flush();
+		
+		return byteCount;
+	}
     
     /**
      * 
      */
     private void printUsage()
     {
-        printWelcome();
-        MP.printMessage(EC.TLC_USAGE);
+    	final List<List<UsageGenerator.Argument>> commandVariants = new ArrayList<>();
+    	final List<UsageGenerator.Argument> sharedArguments = new ArrayList<>();
+    	
+    	// N.B. alphabetical ordering is not required by the UsageGenerator, but introduced here to more easily
+    	//			find options when reading the code
+    	sharedArguments.add(new UsageGenerator.Argument("-checkpoint", "minutes",
+    													"interval between check point; defaults to 30",
+    													true));
+    	sharedArguments.add(new UsageGenerator.Argument("-cleanup", "clean up the states directory", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-config", "file",
+    													"provide the configuration file; defaults to SPEC.cfg", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-continue",
+    													"continue running even when an invariant is violated; default\n"
+    														+ "behavior is to halt on first violation", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-coverage", "minutes",
+														"interval between the collection of coverage information;\n"
+    														+ "if not specified, no coverage will be collected", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-deadlock",
+														"if specified DO NOT CHECK FOR DEADLOCK; default\n"
+															+ "behavior is to check for deadlock", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-difftrace",
+														"show only the differences between successive states when\n"
+															+ "printing trace information; defaults to printing\n"
+															+ "full state descriptions", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-debug",
+														"print various debugging information - not for production use\n",
+														true));
+    	sharedArguments.add(new UsageGenerator.Argument("-dump", "file",
+    													"dump all states into the specified file; this parameter takes\n"
+    														+ "optional parameters for dot graph generation. Specifying\n"
+    														+ "'dot' allows further options, comma delimited, of zero\n"
+    														+ "or more of 'actionlabels', 'colorize', 'snapshot' to be\n"
+    														+ "specified before the '.dot'-suffixed filename", true,
+    													"dot actionlabels,colorize,snapshot"));
+    	sharedArguments.add(new UsageGenerator.Argument("-fp", "N",
+    													"use the Nth irreducible polynomial from the list stored\n"
+    														+ "in the class FP64", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-fpbits", "num",
+														"the number of MSB used by MultiFPSet to create nested\n"
+    														+ "FPSets; defaults to 1", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-fpmem", "num",
+														"a value in (0.0,1.0) representing the ratio of total\n"
+															+ "physical memory to devote to storing the fingerprints\n"
+															+ "of found states; defaults to 0.25", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-generateSpecTE", null,
+														"if errors are encountered during model checking, generate\n"
+															+ "a SpecTE tla/cfg file pair which encapsulates Init-Next\n"
+															+ "definitions to specify the state conditions of the error\n"
+															+ "state; this enables 'tool' mode. The generated SpecTE\n"
+															+ "will include tool output as well as all non-Standard-\n"
+															+ "Modules dependencies embeded in the module. To prevent\n"
+															+ "the embedding of dependencies, add the parameter\n"
+															+ "'nomonolith' to this declaration", true,
+															"nomonolith"));
+    	sharedArguments.add(new UsageGenerator.Argument("-gzip",
+														"control if gzip is applied to value input/output streams;\n"
+															+ "defaults to 'off'", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-h", "display these help instructions", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-maxSetSize", "num",
+														"the size of the largest set which TLC will enumerate; defaults\n"
+															+ "to 1000000 (10^6)", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-metadir", "path",
+														"specify the directory in which to store metadata; defaults to\n"
+															+ "SPEC-directory/states if not specified", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-nowarning",
+														"disable all warnings; defaults to reporting warnings", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-recover", "id",
+														"recover from the checkpoint with the specified id", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-terse",
+														"do not expand values in Print statements; defaults to\n"
+															+ "expanding values", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-tool",
+														"run in 'tool' mode, surrounding output with message codes;\n"
+															+ "if '-generateSpecTE' is specified, this is enabled\n"
+															+ "automatically", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-userFile", "file",
+														"an absolute path to a file in which to log user output (for\n"
+    														+ "example, that which is produced by Print)", true));
+    	sharedArguments.add(new UsageGenerator.Argument("-workers", "num",
+														"the number of TLC worker threads; defaults to 1", true));
+    	
+    	sharedArguments.add(new UsageGenerator.Argument("SPEC", null));
+    	
+    	
+    	final List<UsageGenerator.Argument> modelCheckVariant = new ArrayList<>(sharedArguments);
+    	modelCheckVariant.add(new UsageGenerator.Argument("-dfid", "num",
+														  "run the model check in depth-first iterative deepening\n"
+    														+ "starting with an initial depth of 'num'", true));
+    	modelCheckVariant.add(new UsageGenerator.Argument("-view",
+														  "apply VIEW (if provided) when printing out states", true));
+    	commandVariants.add(modelCheckVariant);
+    	
+    	
+    	final List<UsageGenerator.Argument> simulateVariant = new ArrayList<>(sharedArguments);
+    	simulateVariant.add(new UsageGenerator.Argument("-depth", "num",
+														"specifies the depth of random simulation; defaults to 100",
+														true));
+    	simulateVariant.add(new UsageGenerator.Argument("-seed", "num",
+														"provide the seed for random simulation; defaults to a\n"
+    														+ "random long pulled from a pseudo-RNG", true));
+    	simulateVariant.add(new UsageGenerator.Argument("-aril", "num",
+														"adjust the seed for random simulation; defaults to 0", true));
+    	simulateVariant.add(new UsageGenerator.Argument("-simulate", null,
+													  	"run in simulation mode; optional parameters may be specified\n"
+	    													+ "comma delimited: 'num=X' where X is the maximum number of\n"
+	    													+ "total traces to generate and/or 'file=Y' where Y is the\n"
+	    													+ "absolute-pathed prefix for trace file modules to be written\n"
+	    													+ "by the simulation workers; for example Y='/a/b/c/tr' would\n"
+	    													+ "produce, e.g, '/a/b/c/tr_1_15'", false,
+	    												"file=X,num=Y"));
+    	commandVariants.add(simulateVariant);
+
+    	
+    	final List<String> tips = new ArrayList<String>();
+    	tips.add("When using the  '-generateSpecTE' you can version the generated specification by doing:\n\t"
+    				+ "./tla2tools.jar -generateSpecTE MySpec.tla && NAME=\"SpecTE-$(date +%s)\" && sed -e \"s/MODULE"
+    				+ " SpecTE/MODULE $NAME/g\" SpecTE.tla > $NAME.tla");
+    	tips.add("If, while checking a SpecTE created via '-generateSpecTE', you get an error message concerning\n"
+    				+ "CONSTANT declaration and you've previous used 'integers' as model values, rename your\n"
+    				+ "model values to start with a non-numeral and rerun the model check to generate a new SpecTE.");
+    	tips.add("If, while checking a SpecTE created via '-generateSpecTE', you get a warning concerning\n"
+					+ "duplicate operator definitions, this is likely due to the 'monolith' specification\n"
+					+ "creation. Try re-running TLC adding the 'nomonolith' option to the '-generateSpecTE'\n"
+					+ "parameter.");
+    	
+    	UsageGenerator.displayUsage(ToolIO.out, "TLC", TLCGlobals.versionOfTLC,
+    								"provides model checking and simulation of TLA+ specifications",
+    								Messages.getString("TLCDescription"),
+    								commandVariants, tips, ' ');
     }
 
     FPSetConfiguration getFPSetConfiguration() {
     	return fpSetConfiguration;
     }
+    
+    public RunMode getRunMode() {
+    	return runMode;
+    }
 
     public String getMainFile() {
         return mainFile;
diff --git a/tlatools/src/tlc2/TLCGlobals.java b/tlatools/src/tlc2/TLCGlobals.java
index 8c588e65bd3a9ee296cb96063230bab7c254eafb..e6aee0b5c60b17f2d671a4038194dada25ccfe68 100644
--- a/tlatools/src/tlc2/TLCGlobals.java
+++ b/tlatools/src/tlc2/TLCGlobals.java
@@ -23,7 +23,7 @@ public class TLCGlobals
 	public static final int DEFAULT_CHECKPOINT_DURATION = (30 * 60 * 1000) + 42;
 
 	// The current version of TLC
-    public static String versionOfTLC = "Version 2.14 of 10 July 2019";
+    public static String versionOfTLC = "Version 2.15 of Day Month 20??";
     
     // The bound for set enumeration, used for pretty printing
     public static int enumBound = 2000;
@@ -52,7 +52,11 @@ public class TLCGlobals
 	public static String lnCheck = "default";
 	
 	public static boolean doLiveness() {
-		return !lnCheck.equals("final");
+		return !(lnCheck.equals("final") || lnCheck.equals("seqfinal"));
+	}
+
+	public static boolean doSequentialLiveness() {
+		return lnCheck.startsWith("seq");
 	}
 
 	public synchronized static void setNumWorkers(int n)
diff --git a/tlatools/src/tlc2/TLCRunner.java b/tlatools/src/tlc2/TLCRunner.java
new file mode 100644
index 0000000000000000000000000000000000000000..dcd35035ac4e1310ae3e3f5b857a1bd1ac4b1980
--- /dev/null
+++ b/tlatools/src/tlc2/TLCRunner.java
@@ -0,0 +1,191 @@
+package tlc2;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import tlc2.output.EC;
+import tlc2.output.TeeOutputStream;
+import tlc2.tool.fp.FPSetFactory;
+
+/**
+ * Originally i was attempting to run the model check in the same JVM in which {@link TraceExplorer} was invoked (and 
+ * 	then did its parsing and generating TLA and CFG files.) The model check process would fail with a message of:
+ * 
+ * 				@!@!@STARTMSG 2233:1 @!@!@
+ * 				The initial predicate _TEInit cannot be a constant.
+ * 				@!@!@ENDMSG 2233 @!@!@
+ * 
+ * ... however, running TLC from command line freshly on the same TLA/CFG would not produce this error.  I can only
+ * 	surmise that the parsing process is setting some static value somewhere which is not being cleared and which is
+ * 	then making the model checking process fail.
+ * 
+ * In light of that, i've written this class to spin off a new JVM for the model check.
+ */
+class TLCRunner {
+	static List<String> JVM_ARGUMENTS;
+	private static final String TLC_CLASS = TLC.class.getName();
+	
+	static {
+		JVM_ARGUMENTS = new ArrayList<>();
+		JVM_ARGUMENTS.add("-XX:+UseParallelGC");
+		JVM_ARGUMENTS.add("-Dfile.encoding=UTF-8");
+		JVM_ARGUMENTS.add("-Dtlc2.tool.fp.FPSet.impl=" + FPSetFactory.getImplementationDefault());
+	}
+	
+	
+	private final File outputLogfile;
+	private final OutputStream outputOutputStream;
+	private final List<String> arguments;
+	
+	private boolean silenceStdOut;
+
+	TLCRunner(final List<String> tlcArguments, final File logfileDestination) {
+		outputLogfile = logfileDestination;
+		outputOutputStream = null;
+		arguments = tlcArguments;
+		
+		silenceStdOut = false;
+	}
+
+	TLCRunner(final List<String> tlcArguments, final OutputStream logfileOutputStream) {
+		outputLogfile = null;
+		outputOutputStream = logfileOutputStream;
+		arguments = tlcArguments;
+		
+		silenceStdOut = false;
+	}
+	
+	/**
+	 * @param flag if true, no output from the TLC process will be sent to System.out
+	 */
+	void setSilenceStdOut(final boolean flag) {
+		silenceStdOut = flag;
+	}
+	
+	/**
+	 * This will not return until the process has finished.
+	 * @return the exit value of the TLC process
+	 * @throws IOException
+	 */
+	int run() throws IOException {
+		final ProcessBuilder processBuilder = createProcess();
+		final Process p = processBuilder.start();
+		final BufferedInputStream stdOutReader = new BufferedInputStream(p.getInputStream());
+		final BufferedInputStream stdErrReader = new BufferedInputStream(p.getErrorStream());
+		final BufferedOutputStream logfileOutputStream;
+		if (outputOutputStream != null) {
+			if (outputOutputStream instanceof BufferedOutputStream) {
+				logfileOutputStream = (BufferedOutputStream)outputOutputStream;
+			} else {
+				logfileOutputStream = new BufferedOutputStream(outputOutputStream);
+			}
+		} else {
+			final FileOutputStream fos = new FileOutputStream(outputLogfile);
+			logfileOutputStream = new BufferedOutputStream(fos);
+		}
+		final OutputStream stdOutPumpOutput;
+		if (silenceStdOut) {
+			stdOutPumpOutput = logfileOutputStream;
+		} else {
+			stdOutPumpOutput = new TeeOutputStream(System.out, logfileOutputStream);
+		}
+		final StreamPump stdOutPump = new StreamPump(stdOutReader, stdOutPumpOutput);
+		final StreamPump stdErrPump = new StreamPump(stdErrReader, null);
+		
+		try {
+			(new Thread(stdOutPump)).start();
+			(new Thread(stdErrPump)).start();
+			
+			p.waitFor();
+			
+			return p.exitValue();
+		} catch (final InterruptedException ie) {
+			// TODO improve logging here
+			System.out.println("TLC process was interrupted: " + ie.getMessage());
+		} finally {
+			stdOutPump.stop();
+			stdErrPump.stop();
+			
+			try {
+				logfileOutputStream.close();
+			} catch (final Exception e) { }
+		}
+		
+		return EC.ExitStatus.ERROR_SYSTEM;
+	}
+
+	private ProcessBuilder createProcess() {
+		final boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
+		final String jvm = System.getProperty("java.home")
+								+ File.separator
+								+ "bin"
+								+ File.separator
+								+ "java"
+								+ (isWindows ? ".exe" : "");
+		final List<String> command = new ArrayList<String>();
+		command.add(jvm);
+		command.addAll(JVM_ARGUMENTS);
+		command.add(TLC_CLASS);
+		command.addAll(arguments);
+
+		final ProcessBuilder processBuilder = new ProcessBuilder(command);
+		final Map<String, String> environment = processBuilder.environment();
+		environment.put("CLASSPATH", System.getProperty("java.class.path"));
+		
+		return processBuilder;
+	}
+
+	
+	private static class StreamPump implements Runnable {
+	    private static final int WAIT_SLEEP = 125;
+
+	    
+	    private final InputStream inputStream;
+	    private final OutputStream outputStream;
+
+	    private volatile boolean shouldStop;
+
+	    /**
+	     * @param is
+	     * @param os pass null to simply drain the input stream
+	     */
+	    StreamPump(final InputStream is, final OutputStream os) {
+	        this.inputStream = is;
+	        this.outputStream = os;
+	        this.shouldStop = false;
+	    }
+
+		public void run() {
+			try {
+				while (!shouldStop) {
+					while ((inputStream.available() > 0) && !shouldStop) {
+						if (outputStream != null) {
+							outputStream.write(inputStream.read());
+						} else {
+							inputStream.read();
+						}
+					}
+					if (outputStream != null) {
+						outputStream.flush();
+					}
+
+					try {
+						Thread.sleep(WAIT_SLEEP);
+					} catch (final Exception e) { }
+				}
+			} catch (final Exception e) { }
+		}
+
+		void stop() {
+	        shouldStop = true;
+	    }
+	}
+}
diff --git a/tlatools/src/tlc2/TraceExplorer.java b/tlatools/src/tlc2/TraceExplorer.java
new file mode 100644
index 0000000000000000000000000000000000000000..bed61c179df1d628aee88f2ad0e0e4573146eb7a
--- /dev/null
+++ b/tlatools/src/tlc2/TraceExplorer.java
@@ -0,0 +1,846 @@
+package tlc2;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReentrantLock;
+
+import tlc2.input.MCOutputParser;
+import tlc2.input.MCOutputPipeConsumer;
+import tlc2.input.MCParser;
+import tlc2.input.MCParserResults;
+import tlc2.model.MCError;
+import tlc2.model.MCState;
+import tlc2.output.CFGCopier;
+import tlc2.output.EC;
+import tlc2.output.MP;
+import tlc2.output.Messages;
+import tlc2.output.SpecTraceExpressionWriter;
+import tlc2.output.TLACopier;
+import tlc2.util.Vect;
+import tlc2.value.impl.SetEnumValue;
+import tlc2.value.impl.Value;
+import tlc2.value.impl.ValueEnumeration;
+import util.TLAConstants;
+import util.ToolIO;
+import util.UsageGenerator;
+
+/**
+ * This is an application class which provides the following functionalities:
+ * 
+ * 		. given a directory of a previously run model check (containing a .tla/.cfg/.out triplet), produce a "SpecTE"
+ * 				.tla / .cfg file pair
+ * 		. given a directory of a previously run model check (containing a .out file), dump a pretty print of the
+ *				errors states to {@link System#out}
+ * 		. given a directory of a previously run model check (containing a .tla/.cfg/.out triplet) and a file of
+ * 				trace expressions, one per line, produce a "SpecTE" file pair, then run a model check
+ * 				evaluating the expressions, writing the triplet TE.tla, TE.cfg, TE.out
+ * 		. given a directory of a previously generated SpecTE file pair and a file of trace expressions, one per line,
+ * 				run a model check evaluating the expressions, writing the triplet TE.tla, TE.cfg, TE.out
+ *		. given an already executed output pipe consumer, generated a "SpecTE" .tla / .cfg pair
+ */
+public class TraceExplorer {
+	private static final String GENERATE_SPEC_FUNCTION_PARAMETER_NAME = "-generateSpecTE";
+	private static final String PRETTY_PRINT_FUNCTION_PARAMETER_NAME = "-prettyPrint";
+	private static final String QUASI_REPL_PARAMETER_NAME = "-replBis";
+	private static final String TRACE_EXPRESSIONS_FUNCTION_PARAMETER_NAME = "-traceExpressions";
+
+    private static final String EXPRESSIONS_FILE_PARAMETER_NAME = "-expressionsFile";
+    private static final String MODEL_CHECK_JVM_ARGUMENTS_PARAMETER_NAME = "-jvmArguments";
+    private static final String MODEL_CHECK_TLC_ARGUMENTS_PARAMETER_NAME = "-tlcArguments";
+
+    private static final String SOURCE_DIR_PARAMETER_NAME = "-source";
+    private static final String GENERATE_SPEC_OVERWRITE_PARAMETER_NAME = "-overwrite";
+    
+    static final String SPEC_TE_INIT_ID = "_SpecTEInit";
+    static final String SPEC_TE_NEXT_ID = "_SpecTENext";
+    private static final String SPEC_TE_ACTION_CONSTRAINT_ID = "_SpecTEActionConstraint";
+    
+    // <parameter name, whether the parameter takes an argument>
+    private static final HashMap<String, Boolean> TLC_ARGUMENTS_TO_IGNORE;
+    
+    static {
+    	TLC_ARGUMENTS_TO_IGNORE = new HashMap<>();
+    	
+    	TLC_ARGUMENTS_TO_IGNORE.put("-config", Boolean.TRUE);
+    	TLC_ARGUMENTS_TO_IGNORE.put("-metadir", Boolean.TRUE);
+    	TLC_ARGUMENTS_TO_IGNORE.put("-tool", Boolean.FALSE);
+    }
+    
+    
+    /**
+	 * @param sourceDirectory
+	 * @param originalSpecName
+	 * @param results
+	 * @param error
+	 * @return an array of length two; the 0-index is the location to the
+	 *         destination TLA file, and the 1-index is that of the CFG file
+	 * @throws IOException
+	 */
+    public static File[] writeSpecTEFiles(final File sourceDirectory, final String originalSpecName,
+    									  final MCParserResults results, final MCError error) throws IOException {
+    	final StringBuilder tlaBuffer = new StringBuilder();
+    	final StringBuilder cfgBuffer = new StringBuilder();
+    	
+    	final Vect<?> configDeclaredConstants = results.getModelConfig().getConstants();
+    	final HashSet<String> constantModelValuesToDeclare = new HashSet<>();
+    	final int constantsCount = configDeclaredConstants.size();
+    	for (int i = 0; i < constantsCount; i++) {
+    		final Vect<?> constantDeclaration = (Vect<?>)configDeclaredConstants.elementAt(i);
+    		final Object value = constantDeclaration.elementAt(1);
+    		if (value instanceof SetEnumValue) {
+    			final SetEnumValue sev = (SetEnumValue)value;
+    			final ValueEnumeration ve = sev.elements();
+    			Value v = ve.nextElement();
+    			while (v != null) {
+    				constantModelValuesToDeclare.add(v.toString());
+    				v = ve.nextElement();
+    			}
+    		}
+    	}
+    	if (constantModelValuesToDeclare.size() > 0) {
+	    	cfgBuffer.append(TLAConstants.KeyWords.CONSTANTS).append(TLAConstants.CR);
+	    	for (final String modelValue : constantModelValuesToDeclare) {
+	    		cfgBuffer.append(TLAConstants.INDENT).append(modelValue).append(TLAConstants.EQ);
+	    		cfgBuffer.append(modelValue).append(TLAConstants.CR);
+	    	}
+	    	cfgBuffer.append(TLAConstants.CR);
+	    	
+	    	tlaBuffer.append(TLAConstants.CR).append(TLAConstants.KeyWords.CONSTANTS).append(' ');
+	    	boolean firstDone = false;
+	    	for (final String modelValue : constantModelValuesToDeclare) {
+	    		if (firstDone) {
+	    			tlaBuffer.append(", ");
+	    		} else {
+	    			firstDone = true;
+	    		}
+	    		
+	    		tlaBuffer.append(modelValue);
+	    	}
+	    	tlaBuffer.append(TLAConstants.CR).append(TLAConstants.CR);
+    	}
+    	
+    	final List<MCState> trace = error.getStates();
+    	final StringBuilder[] tlaBuffers
+    		= SpecTraceExpressionWriter.addInitNextToBuffers(cfgBuffer, trace, null, SPEC_TE_INIT_ID, SPEC_TE_NEXT_ID,
+    														 SPEC_TE_ACTION_CONSTRAINT_ID,
+    														 results.getOriginalNextOrSpecificationName(), true);
+    	tlaBuffer.append(tlaBuffers[0].toString());
+    	SpecTraceExpressionWriter.addTraceFunctionToBuffers(tlaBuffer, cfgBuffer, trace);
+    	tlaBuffer.append(tlaBuffers[1].toString());
+    	
+    	final List<String> extendedModules = results.getOriginalExtendedModules();
+    	final boolean specExtendsTLC = extendedModules.contains(TLAConstants.BuiltInModules.TLC);
+    	final boolean specExtendsToolbox = extendedModules.contains(TLAConstants.BuiltInModules.TRACE_EXPRESSIONS);
+		final TLACopier tlaCopier = new TLACopier(originalSpecName, TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME,
+												  sourceDirectory, tlaBuffer.toString(), specExtendsTLC,
+												  specExtendsToolbox);
+		tlaCopier.copy();
+		MP.printMessage(EC.GENERAL,
+						"The file " + tlaCopier.getDestinationFile().getAbsolutePath() + " has been created.");
+		
+		final CFGCopier cfgCopier = new CFGCopier(originalSpecName, TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME,
+												  sourceDirectory, cfgBuffer.toString());
+		cfgCopier.copy();
+		MP.printMessage(EC.GENERAL,
+						"The file " + cfgCopier.getDestinationFile().getAbsolutePath() + " has been created.");
+		
+		return new File[] { tlaCopier.getDestinationFile(), cfgCopier.getDestinationFile() };
+    }
+    
+    
+    private enum RunMode {
+    	GENERATE_SPEC_TE, PRETTY_PRINT, GENERATE_FROM_TLC_RUN, QUASI_REPL, TRACE_EXPLORATION;
+    }
+
+    
+    private File specGenerationSourceDirectory;
+    private String specGenerationOriginalSpecName;
+    private boolean expectedOutputFromStdIn;
+    private boolean overwriteGeneratedFiles;
+    
+    private List<String> expressions;
+    private List<String> tlcArguments;
+    
+    private String replSpecName;
+    private File temporaryREPLSpec;
+    
+    private RunMode runMode;
+
+    /**
+     * @param commandLineArguments arguments, ostensibly from the command line, with which this instance will configure
+     * 								itself.
+     */
+    public TraceExplorer(final String[] commandLineArguments) {
+    	processArguments(commandLineArguments);
+    	
+    	if (runMode == null) {
+			printUsageAndExit();
+    	}
+    }
+    
+    protected final void processArguments(final String[] args) {
+    	runMode = determineRunModeFromArguments(args);
+    	if (runMode == null) {
+    		return;
+    	}
+
+    	switch (runMode) {
+			case QUASI_REPL:
+			case TRACE_EXPLORATION:
+	    		tlcArguments = new ArrayList<>();
+				break;
+			default:
+				break;
+    	}
+    	
+		specGenerationSourceDirectory = new File(System.getProperty("user.dir"));
+		specGenerationOriginalSpecName = args[args.length - 1];
+		expectedOutputFromStdIn = (specGenerationOriginalSpecName.charAt(0) == '-');
+		if (expectedOutputFromStdIn) {
+			specGenerationOriginalSpecName = null;
+		} else if (RunMode.QUASI_REPL.equals(runMode)) {
+			printUsageAndExit();
+		}
+		overwriteGeneratedFiles = false;
+
+		String expressionsSourceFilename = null;
+		
+		boolean consumedAdditionalParameters = true;
+		final int upperIndex = expectedOutputFromStdIn ? args.length : (args.length - 1);
+    	int index = 0;
+		while (consumedAdditionalParameters) {
+			if (index < upperIndex) {
+				final String nextArg = args[index];
+				
+				if (getRunModeForArgument(nextArg) != null) {
+					index++;
+					continue;
+				}
+				
+				if (SOURCE_DIR_PARAMETER_NAME.equals(nextArg)) {
+					index++;
+					final String runDirectory = args[index++];
+            		final File f = new File(runDirectory);
+            		
+            		if (!f.exists()) {
+            			printErrorMessage("specified source directory does not exist.");
+            			return;
+            		}
+            		
+            		if (!f.isDirectory()) {
+            			printErrorMessage("specified source directory is not a directory.");
+            			return;
+            		}
+            		specGenerationSourceDirectory = f;
+
+					index++;
+				} else if (GENERATE_SPEC_OVERWRITE_PARAMETER_NAME.equals(nextArg)) {
+					overwriteGeneratedFiles = true;
+					
+					index++;
+				} else if (EXPRESSIONS_FILE_PARAMETER_NAME.equals(nextArg)) {
+					index++;
+
+					expressionsSourceFilename = args[index++];
+				} else if (MODEL_CHECK_JVM_ARGUMENTS_PARAMETER_NAME.equals(nextArg)) {
+					index++;
+
+					final String argumentList = args[index++];
+					final String[] arguments = argumentList.split(" ");
+					TLCRunner.JVM_ARGUMENTS.addAll(Arrays.asList(arguments));
+				} else if (MODEL_CHECK_TLC_ARGUMENTS_PARAMETER_NAME.equals(nextArg)) {
+					index++;
+					final String argumentList = args[index++];
+					final String[] arguments = argumentList.split(" ");
+					int argIndex = 0;
+					
+					while (argIndex < arguments.length) {
+						final String argument = arguments[argIndex];
+						final Boolean ignoreAdditionalParameter = TLC_ARGUMENTS_TO_IGNORE.get(argument);
+						
+						if (ignoreAdditionalParameter == null) {
+							tlcArguments.add(argument);
+						} else {
+							if (ignoreAdditionalParameter.booleanValue()) {
+								argIndex++;
+							}
+						}
+						
+						argIndex++;
+					}
+				} else {
+    				consumedAdditionalParameters = false;
+				}
+			} else {
+				consumedAdditionalParameters = false;
+			}
+		}
+		
+		if (RunMode.TRACE_EXPLORATION.equals(runMode) || RunMode.QUASI_REPL.equals(runMode)) {
+			if (expressionsSourceFilename == null) {
+    			printErrorMessage("no expressions file specified.");
+				runMode = null;
+				return;
+			}
+			
+			final File sourceDirFile = new File(specGenerationSourceDirectory, expressionsSourceFilename);
+			final File absoluteFile = new File(expressionsSourceFilename);
+			final File f;
+			if (sourceDirFile.exists()) {
+				f = sourceDirFile;
+			} else if (absoluteFile.exists()) {
+				f = absoluteFile;
+			} else {
+				final String errorMessageSuffix;
+				if (sourceDirFile.getAbsolutePath().equals(absoluteFile.getAbsolutePath())) {
+					errorMessageSuffix = sourceDirFile.getAbsolutePath();
+				} else {
+					errorMessageSuffix = sourceDirFile.getAbsolutePath()
+													+ " nor " + absoluteFile.getAbsolutePath();
+				}
+				printErrorMessage("an expressions file could not be found at " + errorMessageSuffix);
+				runMode = null;
+				return;
+			}
+
+			try {
+				expressions = new ArrayList<>();
+				try (final BufferedReader br = new BufferedReader(new FileReader(f))) {
+					String line;
+					while ((line = br.readLine()) != null) {
+						final String trimmed = line.trim();
+						
+						if (trimmed.length() > 0) {
+							expressions.add(trimmed);
+						}
+					}
+				}
+			} catch (final IOException e) {
+				printErrorMessage("encountered an exception reading from expressions file "
+									+ f.getAbsolutePath() + " :: " + e.getMessage());
+				runMode = null;
+				return;
+			}
+
+			if (RunMode.TRACE_EXPLORATION.equals(runMode)) {
+				tlcArguments.add("-config");
+				tlcArguments.add(TLAConstants.TraceExplore.EXPLORATION_MODULE_NAME 
+									+ TLAConstants.Files.CONFIG_EXTENSION);
+				
+				tlcArguments.add("-tool");
+			} else {
+				replSpecName = "repl"; //"REPL_" + System.currentTimeMillis();
+				temporaryREPLSpec = new File(specGenerationSourceDirectory,
+											 replSpecName + TLAConstants.Files.TLA_EXTENSION);
+				temporaryREPLSpec.deleteOnExit();
+			}
+
+			tlcArguments.add("-metadir");
+			tlcArguments.add(specGenerationSourceDirectory.getAbsolutePath());
+			
+			if (RunMode.TRACE_EXPLORATION.equals(runMode)) {
+				tlcArguments.add(TLAConstants.TraceExplore.EXPLORATION_MODULE_NAME);
+			} else {
+				tlcArguments.add(replSpecName);
+			}
+		}
+     }
+    
+    /**
+     * @return an {@link EC} defined error code representing success or failure.
+     */
+    public int execute() throws Exception {
+    	if (RunMode.QUASI_REPL.equals(runMode)) {
+    		return performREPL();
+    	} else if (expectedOutputFromStdIn) {
+    		return executeStreaming();
+    	} else {
+    		return executeNonStreaming();
+    	}
+    }
+    
+    private RunMode determineRunModeFromArguments(final String[] args) {
+    	for (int i = 0; i < args.length; i++) {
+    		final RunMode rm = getRunModeForArgument(args[i]);
+    		
+    		if (rm != null) {
+    			return rm;
+    		}
+    	}
+
+    	return null;
+    }
+    
+    private RunMode getRunModeForArgument(final String arg) {
+    	if (GENERATE_SPEC_FUNCTION_PARAMETER_NAME.equals(arg)) {
+        	return RunMode.GENERATE_SPEC_TE;
+        } else if (PRETTY_PRINT_FUNCTION_PARAMETER_NAME.equals(arg)) {
+        	return RunMode.PRETTY_PRINT;
+        } else if (TRACE_EXPRESSIONS_FUNCTION_PARAMETER_NAME.equals(arg)) {
+        	return RunMode.TRACE_EXPLORATION;
+        } else if (QUASI_REPL_PARAMETER_NAME.equals(arg)) {
+        	return RunMode.QUASI_REPL;
+        }
+    	
+    	return null;
+    }
+    
+    private int executeNonStreaming() throws Exception {
+    	if (!performPreFlightFileChecks()) {
+			throw new IllegalStateException("There was an issue with the input, "
+												+ TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME + ", or "
+												+ TLAConstants.TraceExplore.EXPLORATION_MODULE_NAME + " file.");
+    	}
+    	
+		final boolean specifiedModuleIsSpecTE
+					= specGenerationOriginalSpecName.equals(TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME);
+		final boolean needGenerateSpecTE = RunMode.GENERATE_SPEC_TE.equals(runMode) 
+											|| (!specifiedModuleIsSpecTE && RunMode.TRACE_EXPLORATION.equals(runMode));
+    	if (needGenerateSpecTE) {
+			final MCParser parser = new MCParser(specGenerationSourceDirectory, specGenerationOriginalSpecName);
+    		final MCParserResults results = parser.parse();
+    		
+    		if (results.getOutputMessages().size() == 0) {
+				MP.printMessage(EC.GENERAL, "The output file had no tool messages; was TLC not run with"
+												+ " the '-tool' option when producing it?");
+
+    			return EC.ExitStatus.ERROR;
+    		} else if (results.getError() == null) {
+    			final String msg;
+    			if (RunMode.GENERATE_SPEC_TE.equals(runMode)) {
+    				msg = "The output file contained no error-state messages, no "
+    							+ TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME + " will be produced.";
+    			} else {
+    				msg = "The output file contained no error-state messages, no "
+								+ TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME + " nor "
+								+ TLAConstants.TraceExplore.EXPLORATION_MODULE_NAME + " will be produced, and, so, "
+								+ "no trace expressions will be evaluated.";
+    			}
+				MP.printMessage(EC.GENERAL, msg);
+
+    			return EC.NO_ERROR;
+    		} else {
+				try {
+					writeSpecTEFiles(results, results.getError());
+
+					if (RunMode.GENERATE_SPEC_TE.equals(runMode)) {
+						return EC.NO_ERROR;
+					} else if (RunMode.TRACE_EXPLORATION.equals(runMode)) { 	// currently always true
+			    		return performTraceExploration();
+			    	}
+				} catch (final Exception e) { }
+    		}
+    	} else if (RunMode.PRETTY_PRINT.equals(runMode)) {
+    		try {
+	    		MCOutputParser.prettyPrintToStream(System.out, specGenerationSourceDirectory,
+	    										   specGenerationOriginalSpecName);
+				
+				return EC.NO_ERROR;
+    		} catch (final Exception e) { }
+    	}
+    	    	
+		return EC.ExitStatus.ERROR;
+    }
+    
+    private int executeStreaming() throws Exception {
+    	final AtomicBoolean mcParserCompleted = new AtomicBoolean(false);
+    	final ReentrantLock parseLock = new ReentrantLock();
+    	final ArrayList<MCParser> parserList = new ArrayList<>(1);
+		final MCOutputPipeConsumer.ConsumerLifespanListener listener
+							= new MCOutputPipeConsumer.ConsumerLifespanListener() {
+			@Override
+			public void consumptionFoundSourceDirectoryAndSpecName(MCOutputPipeConsumer consumer) {
+				specGenerationSourceDirectory = consumer.getSourceDirectory();
+				specGenerationOriginalSpecName = consumer.getSpecName();
+				
+				final boolean specifiedModuleIsSpecTE
+							= specGenerationOriginalSpecName.equals(TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME);
+				final boolean needGenerateSpecTE
+							= RunMode.GENERATE_SPEC_TE.equals(runMode)
+											|| (!specifiedModuleIsSpecTE && RunMode.TRACE_EXPLORATION.equals(runMode));
+
+				if (!performPreFlightFileChecks()) {
+					throw new IllegalStateException("There was an issue with the input, "
+														+ TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME + ", or "
+														+ TLAConstants.TraceExplore.EXPLORATION_MODULE_NAME + " file.");
+				}
+
+				if (needGenerateSpecTE) {
+					MP.printMessage(EC.GENERAL,
+							"Have encountered the source spec in the output logging, will begin parsing of those assets now.");
+					
+					final Runnable r = () -> {
+						final MCParser parser
+								= new MCParser(specGenerationSourceDirectory, specGenerationOriginalSpecName, true);
+						parserList.add(parser);
+						
+						parseLock.lock();
+						try {
+							parser.parse();
+						} finally {
+							mcParserCompleted.set(true);
+							parseLock.unlock();
+						}
+					};
+					(new Thread(r)).start();
+				}
+			}
+		};
+		final MCOutputPipeConsumer pipeConsumer = new MCOutputPipeConsumer(System.in, listener);
+		
+		MP.printMessage(EC.GENERAL, "TraceExplorer is expecting input on stdin...");
+
+		pipeConsumer.consumeOutput(false);
+		
+		if (pipeConsumer.outputHadNoToolMessages()) {
+			MP.printMessage(EC.GENERAL, "The output had no tool messages; was TLC not run with"
+					+ " the '-tool' option when producing it?");
+
+			return EC.ExitStatus.ERROR;
+		}
+
+		MP.printMessage(EC.GENERAL, "Have received the final output logging message - finishing TraceExplorer work.");
+
+		final boolean specifiedModuleIsSpecTE
+				= specGenerationOriginalSpecName.equals(TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME);
+		final boolean needGenerateSpecTE
+				= RunMode.GENERATE_SPEC_TE.equals(runMode)
+								|| (!specifiedModuleIsSpecTE && RunMode.TRACE_EXPLORATION.equals(runMode));
+    	if (needGenerateSpecTE) {
+    		if (pipeConsumer.getError() == null) {
+    			final String msg;
+    			if (RunMode.GENERATE_SPEC_TE.equals(runMode)) {
+    				msg = "The output contained no error-state messages, no "
+    							+ TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME + " will be produced.";
+    			} else {
+    				msg = "The output contained no error-state messages, no "
+								+ TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME + " nor "
+								+ TLAConstants.TraceExplore.EXPLORATION_MODULE_NAME + " will be produced, and, so, "
+								+ "no trace expressions will be evaluated.";
+    			}
+				MP.printMessage(EC.GENERAL, msg);
+
+    			return EC.NO_ERROR;
+    		} else {
+        		if (!mcParserCompleted.get()) {
+        			parseLock.lock();
+        		}
+        		final MCParserResults results = parserList.get(0).getParseResults();
+    			
+				try {
+					writeSpecTEFiles(results, pipeConsumer.getError());
+
+					if (RunMode.GENERATE_SPEC_TE.equals(runMode)) {
+						return EC.NO_ERROR;
+					} else if (RunMode.TRACE_EXPLORATION.equals(runMode)) { 	// currently always true
+			    		return performTraceExploration();
+			    	}
+				} catch (final Exception e) { }
+    		}
+    	} else if (RunMode.PRETTY_PRINT.equals(runMode)) {
+    		if (pipeConsumer.getError() == null) {
+    			MP.printMessage(EC.GENERAL, "The output contained no error-state messages; there is nothing to display.");
+				
+				return EC.NO_ERROR;
+    		} else {
+        		try {
+    	    		MCOutputParser.prettyPrintToStream(System.out, pipeConsumer.getError());
+    				
+    				return EC.NO_ERROR;
+        		} catch (final Exception e) { }
+    		}
+    	}
+    	
+		return EC.ExitStatus.ERROR;
+    }
+    
+    private int performREPL() throws IOException {
+    	final REPLSpecWriter writer = new REPLSpecWriter(replSpecName, expressions);
+    	final File cfgFile = new File(specGenerationSourceDirectory, replSpecName + TLAConstants.Files.CONFIG_EXTENSION);
+    	cfgFile.deleteOnExit();
+    	writer.writeFiles(temporaryREPLSpec, cfgFile);
+
+    	final REPLSpecWriter.REPLLogConsumerStream outputStream = new REPLSpecWriter.REPLLogConsumerStream();
+		final TLCRunner tlcRunner = new TLCRunner(tlcArguments, outputStream);
+		tlcRunner.setSilenceStdOut(true);
+		final int errorCode = tlcRunner.run();
+		
+		System.out.println(String.join("\n", expressions));
+		System.out.println("\t" + TLAConstants.EQ);
+		// TODO indent on multi-line
+		System.out.println("\t\t" + outputStream.getCollectedContent());
+
+    	return errorCode;
+    }
+    
+	private int performTraceExploration() throws IOException {
+		final File tlaFile = new File(specGenerationSourceDirectory,
+				TLAConstants.TraceExplore.EXPLORATION_MODULE_NAME + TLAConstants.Files.TLA_EXTENSION);
+		final TraceExpressionExplorerSpecWriter writer = new TraceExpressionExplorerSpecWriter(expressions);
+		final String configContent = writer.getConfigBuffer().toString();
+		writer.writeFiles(tlaFile, null);
+
+		final CFGCopier cfgCopier = new CFGCopier(TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME,
+				TLAConstants.TraceExplore.EXPLORATION_MODULE_NAME, specGenerationSourceDirectory, configContent);
+		cfgCopier.copy();
+
+		final File outFile = new File(specGenerationSourceDirectory,
+				TLAConstants.TraceExplore.EXPLORATION_MODULE_NAME + TLAConstants.Files.OUTPUT_EXTENSION);
+		final TLCRunner tlcRunner = new TLCRunner(tlcArguments, outFile);
+		System.out.println("Forking TLC...");
+		final int errorCode = tlcRunner.run();
+
+		MCOutputParser.prettyPrintToStream(System.out, specGenerationSourceDirectory,
+										   TLAConstants.TraceExplore.EXPLORATION_MODULE_NAME);
+
+		return errorCode;
+	}
+
+    private boolean performPreFlightFileChecks() {
+		final boolean specifiedModuleIsSpecTE
+				= specGenerationOriginalSpecName.equals(TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME);
+		final boolean outputShouldExist = !expectedOutputFromStdIn 
+											|| (specifiedModuleIsSpecTE && RunMode.TRACE_EXPLORATION.equals(runMode));
+
+		String filename;
+    	
+    	if (outputShouldExist) {
+    		filename = specGenerationOriginalSpecName + TLAConstants.Files.OUTPUT_EXTENSION;
+    		final File outputFile = new File(specGenerationSourceDirectory, filename);
+    		if (!outputFile.exists()) {
+    			printErrorMessage("source directory (" + specGenerationSourceDirectory + ") does not contain "
+    					+ filename);
+    			
+    			runMode = null;
+    			return false;
+    		}
+    	}
+    	
+		if (RunMode.GENERATE_SPEC_TE.equals(runMode) || RunMode.TRACE_EXPLORATION.equals(runMode)) {
+			filename = specGenerationOriginalSpecName + TLAConstants.Files.TLA_EXTENSION;
+			final File tlaFile = new File(specGenerationSourceDirectory, filename);
+			if (!tlaFile.exists()) {
+				printErrorMessage("source directory (" + specGenerationSourceDirectory + ") does not contain "
+						+ filename);
+				
+				runMode = null;
+				return false;
+			}
+	    	
+			filename = specGenerationOriginalSpecName + TLAConstants.Files.CONFIG_EXTENSION;
+			final File configFile = new File(specGenerationSourceDirectory, filename);
+			if (!configFile.exists()) {
+				printErrorMessage("source directory (" + specGenerationSourceDirectory + ") does not contain "
+						+ filename);
+				
+				runMode = null;
+				return false;
+			}
+			
+			if (!overwriteGeneratedFiles) {
+				if (!specifiedModuleIsSpecTE) {
+					final File specTETLA = new File(specGenerationSourceDirectory,
+							(TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME + TLAConstants.Files.TLA_EXTENSION));
+
+					if (specTETLA.exists()) {
+						printErrorMessage("specified source directory already contains " + specTETLA.getName()
+								+ "; specify '" + GENERATE_SPEC_OVERWRITE_PARAMETER_NAME + "' to overwrite.");
+
+						runMode = null;
+						return false;
+					}
+				}
+				
+				if (RunMode.TRACE_EXPLORATION.equals(runMode)) {
+					final File teTLA = new File(specGenerationSourceDirectory,
+								(TLAConstants.TraceExplore.EXPLORATION_MODULE_NAME + TLAConstants.Files.TLA_EXTENSION));
+
+					if (teTLA.exists()) {
+						printErrorMessage("specified source directory already contains " + teTLA.getName()
+								+ "; specify '" + GENERATE_SPEC_OVERWRITE_PARAMETER_NAME + "' to overwrite.");
+
+						runMode = null;
+						return false;
+					}
+				}
+			}
+		}
+		
+		return true;
+    }
+    
+    private void writeSpecTEFiles(final MCParserResults results, final MCError error) throws IOException {
+    	writeSpecTEFiles(specGenerationSourceDirectory, specGenerationOriginalSpecName, results, error);
+    }
+    
+    private void printErrorMessage(final String message) {
+    	MP.printError(EC.GENERAL, message);
+    }
+    
+    
+    private static void printUsageAndExit() {
+    	final List<List<UsageGenerator.Argument>> commandVariants = new ArrayList<>();
+    	final UsageGenerator.Argument expressionFile
+				= new UsageGenerator.Argument(EXPRESSIONS_FILE_PARAMETER_NAME, "file",
+											 "expressions specified, one per line if being used in conjunction\n"
+													+ "with " + TRACE_EXPRESSIONS_FUNCTION_PARAMETER_NAME
+													+ " and just one if being used with "
+													+ QUASI_REPL_PARAMETER_NAME
+													+ "\nthis file must be in the source "
+													+ "directory or specified by\nfull path", false);
+    	final UsageGenerator.Argument jvmArguments
+				= new UsageGenerator.Argument(MODEL_CHECK_JVM_ARGUMENTS_PARAMETER_NAME,
+											  "\"-Xmx3072m -Xms512m\"",
+											  "these arguments will be passed on to the TLC JVM when performing\n"
+													+ "the model check",
+											  true);
+    	final UsageGenerator.Argument overwrite
+	    		= new UsageGenerator.Argument(GENERATE_SPEC_OVERWRITE_PARAMETER_NAME,
+	    									  "if specified, and if a SpecTE, or TE, file pair already exists,\n"
+	    											+ "they will be overwritten; if they exist, and this has not been\n"
+	    											+ "specified, the process will halt", true);
+    	final UsageGenerator.Argument sourceDirectory
+				= new UsageGenerator.Argument(SOURCE_DIR_PARAMETER_NAME, "path",
+											  "the path to the directory containing tool output from model\n"
+													+ "checking; defaults to CWD. This will be ignored if no SpecName\n"
+													+ "has been specified (and so tool output will be expected to\n"
+													+ "arrive on stdin)", true);
+    	final UsageGenerator.Argument spec
+				= new UsageGenerator.Argument("SpecName",
+											  "if no spec name is specified, tool output will be expected to arrive\n"
+													+ "via stdin and any " + SOURCE_DIR_PARAMETER_NAME
+													+ " definition will be ignored.", false);
+    	final UsageGenerator.Argument tlcArguments
+				= new UsageGenerator.Argument(MODEL_CHECK_TLC_ARGUMENTS_PARAMETER_NAME,
+											  "\"-some -other 2 -tlc arguments\"",
+											  "these arguments will be passed on to TLC when performing the\n"
+													+ "model check; -config, -tool, and -metadir will be ignored,\n"
+													+ "if specified",
+											  true);
+    	
+    	final List<UsageGenerator.Argument> traceExpressionsVariant = new ArrayList<>();
+    	traceExpressionsVariant.add(jvmArguments);
+    	traceExpressionsVariant.add(overwrite);
+    	traceExpressionsVariant.add(sourceDirectory);
+    	traceExpressionsVariant.add(tlcArguments);
+    	traceExpressionsVariant.add(spec);
+    	traceExpressionsVariant.add(expressionFile);
+    	traceExpressionsVariant.add(new UsageGenerator.Argument(
+    												TRACE_EXPRESSIONS_FUNCTION_PARAMETER_NAME,
+    												"evaluate trace expressions in the context of an error state\n"
+    													+ "specified through a generated SpecTE file; if the 'SpecName'\n"
+    													+ "specified is anything other that 'SpecTE', the tool will\n"
+    													+ "generate the SpecTE file pair, prior to generating the TE\n"
+    													+ "file pair for the subsequently performed model checking",
+    													false));
+    	commandVariants.add(traceExpressionsVariant);
+
+    	
+    	final List<UsageGenerator.Argument> replBisVariant = new ArrayList<>();
+    	replBisVariant.add(jvmArguments);
+    	replBisVariant.add(tlcArguments);
+    	replBisVariant.add(new UsageGenerator.Argument(
+    												QUASI_REPL_PARAMETER_NAME,
+    												"perform a one-off evaluation of an expression", false));
+    	replBisVariant.add(expressionFile);
+    	commandVariants.add(replBisVariant);
+
+    	
+    	final List<UsageGenerator.Argument> generateSpecVariant = new ArrayList<>();
+    	generateSpecVariant.add(overwrite);
+    	generateSpecVariant.add(sourceDirectory);
+    	generateSpecVariant.add(spec);
+    	generateSpecVariant.add(new UsageGenerator.Argument(
+    												GENERATE_SPEC_FUNCTION_PARAMETER_NAME,
+    												"generate a SpecTE tla/cfg pair from a model checking tool mode\n"
+    													+ "output", false));
+    	commandVariants.add(generateSpecVariant);
+
+    	
+    	final List<UsageGenerator.Argument> prettyPrintVariant = new ArrayList<>();
+    	prettyPrintVariant.add(sourceDirectory);
+    	prettyPrintVariant.add(spec);
+    	prettyPrintVariant.add(new UsageGenerator.Argument(
+    												PRETTY_PRINT_FUNCTION_PARAMETER_NAME,
+    												"pretty print the error states of a model checking tool mode\n"
+    													+ "output", false));
+    	commandVariants.add(prettyPrintVariant);
+
+    	
+    	UsageGenerator.displayUsage(ToolIO.out, "TraceExplorer", TLCGlobals.versionOfTLC,
+    								"a tool for working with TLC tool output and exploring trace expressions",
+    								Messages.getString("TraceExplorerDescription"),
+    								commandVariants, null, ' ');
+    	
+    	System.exit(-1);
+    }
+    
+    /**
+     * Ways to run this application:
+     * 
+     *  1. Evaluation of trace expressions from afrom an existing .tla/.out/.cfg triplet in which the .out contains
+     *  	one or more MP.ERROR messages - see https://github.com/tlaplus/tlaplus/issues/393 for background:
+     *  				java tlc2.TraceExplorer -traceExpressions \
+     *  						-expressionsFile=_file_containing_expressions_one_per_line_ \
+     *  						[-tlcArguments=_directory_containing_prior_run_output_] \
+     *  						[-source=_directory_containing_prior_run_output_] \
+     *  						[-overwrite] \
+     *  						SpecName
+     *  	the source directory defaults to CWD if not defined; the expressions file must either exist in the source
+     *  	directory or be a full path; if TLC arguments are specified (all within quotes) they will be passed on to
+     *  	TLC when performing the model check; -config, -tool, and -metadir will be ignored, if specified;  if no
+     *  	SpecName is specified then we will expect the output data to arrive on stdin - anything specified via
+     *  	-source will be ignore in this case as we will derive that from the output log content.
+     *  
+     *  2. Evaluation of an expression, ala REPL-ese:
+     *  				java tlc2.TraceExplorer -replBis \
+     *  						-expressionsFile=_file_containing_expressions_to_evaluate_ \
+     *  						[-tlcArguments=_directory_containing_prior_run_output_]
+     *  	the expressions file must either exist in the source directory or be a full path; if TLC arguments are
+     *  	specified (all within quotes) they will be passed on to TLC when performing the model check; -config,
+     *  	-tool, and -metadir will be ignored, if specified
+     *  
+     *  3. Generation of a 'SpecTE.tla' from an existing .tla/.out/.cfg triplet in which the .out contains
+     *  	one or more MP.ERROR messages - see https://github.com/tlaplus/tlaplus/issues/393 for background:
+     *  				java tlc2.TraceExplorer -generateSpecTE \
+     *  						[-source=_directory_containing_prior_run_output_] \
+     *  						[-overwrite] \
+     *  						SpecName
+     *  	the source directory defaults to CWD if not defined; if overwrite is not specified and a SpecTE.tla
+     *  	already exists in the source directory, execution will halt; if no SpecName is specified then we
+     *  	will expect the output data to arrive on stdin - anything specified via -source will be ignore in this
+     *  	case as we will derive that from the output log content.
+     *  
+     *  4. Pretty print the error states from an existing .out file to {@link System#out}:
+     *  				java tlc2.TraceExplorer -prettyPrint \
+     *  						[-source=_directory_containing_prior_run_output_] \
+     *  						SpecName
+     *  	the source directory defaults to CWD if not defined; if no SpecName is specified then we
+     *  	will expect the output data to arrive on stdin - anything specified via -source will be ignore in this
+     *  	case as we will derive that from the output log content.
+     */
+    public static void main(final String[] args) {
+    	if (args.length == 0) {
+    		printUsageAndExit();
+    	}
+    	
+    	try {
+        	final TraceExplorer te = new TraceExplorer(args);
+	    	final int returnCode = te.execute();
+	    	
+	    	System.exit(returnCode);
+    	} catch (final Exception e) {
+    		System.err.println("Caught exception: " + e.getLocalizedMessage());
+    		
+    		printUsageAndExit();
+    	}
+    }
+}
diff --git a/tlatools/src/tlc2/TraceExpressionExplorerSpecWriter.java b/tlatools/src/tlc2/TraceExpressionExplorerSpecWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..c422a7d21ed886162846044594764c4605aa5614
--- /dev/null
+++ b/tlatools/src/tlc2/TraceExpressionExplorerSpecWriter.java
@@ -0,0 +1,152 @@
+package tlc2;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import tlc2.output.AbstractSpecWriter;
+import tlc2.output.SpecWriterUtilities;
+import util.TLAConstants;
+
+/**
+ * The class name is quite wordy - but the 'more appropriate' TraceExpressionSpecWriter class name is too close to
+ * 	the already-existing SpecTraceExpressionWriter class name.
+ * 
+ * This is the spec writer concrete class which has niceties that lend themselves to the creation of the "TE" tla/cfg
+ * 	pair.
+ */
+public class TraceExpressionExplorerSpecWriter extends AbstractSpecWriter {
+	private static final String EXPRESSION_VARIABLE_NAME_PREFIX = "_traceExpression_";
+	private static final String EXPRESSION_COMMENT_LINE_PREFIX = TLAConstants.COMMENT + " TRACE EXPRESSION: ";
+	
+    private static final String TE_INIT_ID = "_TEInit";
+    private static final String TE_INIT_ATTRIBUTE_NAME = "teBehaviorInit";
+    private static final String TE_NEXT_ID = "_TENext";
+    private static final String TE_NEXT_ATTRIBUTE_NAME = "teBehaviorNext";
+    
+    /**
+     * If the TLA file exists, it will be examined; if it is found to have been generated by this writer, a
+     * 	map of variableName -> traceExpression will be returned. Otherwise null will be returned.
+     * 
+     * @param tlaFile
+     * @return a map of variableName -> traceExpression if the file exists and was created by this writer, else null.
+     */
+    public static HashMap<String, String> getVariableExpressionMapFromTLAFile(final File tlaFile) throws IOException {
+    	if (tlaFile.exists()) {
+    		try (final BufferedReader br = new BufferedReader(new FileReader(tlaFile))) {
+    			final ArrayList<String> declarations = new ArrayList<>();
+    			boolean foundLine = true;
+    			String line;
+    			
+    			while (foundLine && ((line = br.readLine()) != null)) {
+    				if (line.startsWith(EXPRESSION_COMMENT_LINE_PREFIX)) {
+    					declarations.add(line.substring(EXPRESSION_COMMENT_LINE_PREFIX.length()));
+    				} else {
+    					foundLine = false;
+    				}
+    			}
+
+    			if (declarations.size() > 0) {
+    				final HashMap<String, String> variableExpressionMap = new HashMap<>();
+    				
+    				for (final String declaration : declarations) {
+    					final int index = declaration.indexOf(TLAConstants.EQ);
+    					if (index != -1) {
+        					final String variable = declaration.substring(0, index);
+        					final String expression = declaration.substring(index + TLAConstants.EQ.length());
+
+        					variableExpressionMap.put(variable, expression);
+    					}
+    				}
+    				
+    				return variableExpressionMap;
+    			}
+    		}
+    	}
+    	
+    	return null;
+    }
+    
+
+    private final TreeMap<String, String> variableExpressionMap;
+    
+	TraceExpressionExplorerSpecWriter(final List<String> expressions) {
+		super(true);
+		
+		variableExpressionMap = new TreeMap<>();
+		int count = 1;
+		for (final String expression : expressions) {
+			final String key = EXPRESSION_VARIABLE_NAME_PREFIX + count;
+			variableExpressionMap.put(key, expression);
+			tlaBuffer.append(EXPRESSION_COMMENT_LINE_PREFIX).append(key).append(TLAConstants.EQ);
+			tlaBuffer.append(expression).append(TLAConstants.CR);
+			count++;
+		}
+		
+		addPrimer(TLAConstants.TraceExplore.EXPLORATION_MODULE_NAME,
+				  TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME);
+		
+		declareExpressionVariables();
+		createInitNextWithExpressions();
+		
+		tlaBuffer.append(SpecWriterUtilities.getGeneratedTimeStampCommentLine()).append(TLAConstants.CR);
+	}
+	
+	StringBuilder getConfigBuffer() {
+		return cfgBuffer;
+	}
+	
+	private void declareExpressionVariables() {
+		tlaBuffer.append("VARIABLES ");
+
+		boolean notFirst = false;
+		for (final String variable : variableExpressionMap.keySet()) {
+			if (notFirst) {
+				tlaBuffer.append(", ");
+			} else {
+				notFirst = true;
+			}
+			
+			tlaBuffer.append(variable);
+		}
+		
+		tlaBuffer.append(TLAConstants.CR).append(TLAConstants.CR);
+	}
+	
+	private void createInitNextWithExpressions() {
+		final StringBuilder initConjunction = new StringBuilder(TLAConstants.INDENTED_CONJUNCTIVE);
+		initConjunction.append(TraceExplorer.SPEC_TE_INIT_ID).append(TLAConstants.CR);
+		addExpressionsToBuffer(initConjunction, false);
+		
+		final List<String[]> initContent
+						= SpecWriterUtilities.createSourceContent(initConjunction.toString(), TE_INIT_ID, false);
+		addFormulaList(initContent, TLAConstants.KeyWords.INIT, TE_INIT_ATTRIBUTE_NAME);
+		
+		
+		final StringBuilder nextConjunction = new StringBuilder(TLAConstants.INDENTED_CONJUNCTIVE);
+		nextConjunction.append(TraceExplorer.SPEC_TE_NEXT_ID).append(TLAConstants.CR);
+		addExpressionsToBuffer(nextConjunction, true);
+
+		final List<String[]> nextContent
+						= SpecWriterUtilities.createSourceContent(nextConjunction.toString(), TE_NEXT_ID, false);
+		addFormulaList(nextContent, TLAConstants.KeyWords.NEXT, TE_NEXT_ATTRIBUTE_NAME);
+	}
+	
+	private void addExpressionsToBuffer(final StringBuilder buffer, final boolean primed) {
+		for (final Map.Entry<String, String> me : variableExpressionMap.entrySet()) {
+			buffer.append(TLAConstants.INDENTED_CONJUNCTIVE).append(me.getKey());
+			if (primed) {
+				buffer.append(TLAConstants.PRIME);
+			}
+			buffer.append(TLAConstants.EQ);
+			buffer.append(TLAConstants.L_PAREN).append(me.getValue()).append(TLAConstants.R_PAREN);
+			buffer.append(TLAConstants.CR);
+		}
+	}
+}
diff --git a/tlatools/src/tlc2/input/AbstractMCOutputConsumer.java b/tlatools/src/tlc2/input/AbstractMCOutputConsumer.java
new file mode 100644
index 0000000000000000000000000000000000000000..439629cd36cb5c21b2c46f28e261ce03b8e6af87
--- /dev/null
+++ b/tlatools/src/tlc2/input/AbstractMCOutputConsumer.java
@@ -0,0 +1,150 @@
+package tlc2.input;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import tlc2.model.MCError;
+import tlc2.model.MCState;
+import tlc2.output.MP;
+
+abstract class AbstractMCOutputConsumer {
+	private static final int MAX_READ_RETRIES = 60;
+	private static final long SLEEP_BETWEEN_RETRIES = 500;
+	
+	// In the current world, the 'message class' (the second number run in the regex) is only a single digit, but i
+	//		specify potentially two to give room for future expansion without needing to change this code.
+	private static final String START_MESSAGE_REGEX
+				= MP.DELIM + MP.STARTMSG + "([0-9]{4})" + MP.COLON + "([0-9]{1,2})" + MP.SPACE + MP.DELIM;
+	private static final String END_MESSAGE_REGEX = MP.DELIM + MP.ENDMSG + "[0-9]{4}" + MP.SPACE + MP.DELIM;
+	
+	protected static final Pattern START_MESSAGE_PATTERN = Pattern.compile(START_MESSAGE_REGEX);
+	protected static final Pattern END_MESSAGE_PATTERN = Pattern.compile(END_MESSAGE_REGEX);
+	
+
+	private MCError error;
+	
+	public MCError getError() {
+		return error;
+	}
+
+	/**
+	 * Subclasses may override this should they wish; via this method, they will be
+	 * 	handed any line which is read and does not exist in a message block. This line
+	 * 	will not be written to the output file (if a non-null writer has been supplied to
+	 * 	the parseChunk(BufferedReader, BufferedWriter) method) until this method returns.
+	 * 
+	 * @param line
+	 */
+	protected void handleUnknownReadLine(final String line) throws IOException { }
+	
+	protected void consumeErrorMessageAndStates(final BufferedReader reader, final MCOutputMessage errorMessage)
+			throws IOException {
+		MCError currentError = null;
+		
+		// TODO unclear how - if - nested errors can occur; there is support for them in TLCError
+		//			which has [therefore] been mirrored in MCError
+		if (error == null) {
+			error = new MCError(null, errorMessage.getBody());
+			currentError = error;
+		} else {
+			currentError = new MCError((currentError != null) ? currentError : error, errorMessage.getBody());
+		}
+		
+		MCOutputMessage message = parseChunk(reader);
+		if ((message == null) || (message.getType() != MP.ERROR)) {
+			throw new IOException("Expected a useless error message like "
+									+ "'The behavior up to this point is...' but didn't find one after"
+									+ "[" + currentError.getMessage() + "]");
+		}
+		
+		boolean inStateTrace = true;
+		while (inStateTrace) {
+			message = parseChunk(reader);
+			if (message == null) {
+				throw new IOException("Unexpected end of the log during state consumption for "
+										+ "[" + currentError.getMessage() + "]");
+			}
+			
+			if (message.getType() == MP.STATE) {
+				currentError.addState(MCState.parseState(message.getBody()));
+			} else {
+				inStateTrace = false;
+				// TODO do we want to process this message?
+			}
+		}
+	}
+	
+	/**
+	 * The reader is assumed to be parked at a line containing a start message; if
+	 * not, lines will be consumed until one is found, and then the ensuing chunk
+	 * is consumed.
+	 * 
+	 * @param reader
+	 * @return a consumed message, or null if a new chunk could not be encountered
+	 * @throws IOException on a read error, or, if in an attempt to consume the next
+	 *                     chunk, we're unable to find the end of the chunk
+	 */
+	protected MCOutputMessage parseChunk(final BufferedReader reader) throws IOException {
+		MCOutputMessage message = null;
+		String startLine = null;
+		while (startLine == null) {
+			final String line = blockingReadLine(reader, true);
+			
+			if (line == null) {
+				return null;
+			}
+			
+			final Matcher m = START_MESSAGE_PATTERN.matcher(line);
+			if (m.find()) {
+				message = new MCOutputMessage(Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)));
+				startLine = line;
+			} else {
+				handleUnknownReadLine(line);
+			}
+		}
+		
+		boolean chunkEndEncountered = false;
+		final StringBuilder sb = new StringBuilder();
+		while (!chunkEndEncountered) {
+			final String line = blockingReadLine(reader, false);
+			final Matcher m = END_MESSAGE_PATTERN.matcher(line);
+			if (m.find()) {
+				message.setBody(sb);
+				chunkEndEncountered = true;
+			} else {
+				if (sb.length() > 0) {
+					sb.append(MP.CR);
+				}
+				sb.append(line);
+			}
+		}
+		
+		return message;
+	}
+	
+	private String blockingReadLine(final BufferedReader reader, final boolean eofOK) throws IOException {
+		int retry = 0;
+		String line = reader.readLine();
+		while (line == null) {
+			retry++;
+			
+			if (retry == MAX_READ_RETRIES) {
+				if (eofOK) {
+					return null;
+				} else {
+					throw new IOException("We ran out of input unexpectedly.");
+				}
+			}
+			
+			try {
+				Thread.sleep(SLEEP_BETWEEN_RETRIES);
+			} catch (final Exception e) { }
+			
+			line = reader.readLine();
+		}
+		
+		return line;
+	}
+}
diff --git a/tlatools/src/tlc2/input/MCOutputMessage.java b/tlatools/src/tlc2/input/MCOutputMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..38b8db803b628fedf992f7dfa570fe6e38b59c5d
--- /dev/null
+++ b/tlatools/src/tlc2/input/MCOutputMessage.java
@@ -0,0 +1,44 @@
+package tlc2.input;
+
+public class MCOutputMessage {
+	private final int code;
+	private final int type;
+	private String body;
+	
+	MCOutputMessage(final int messageCode, final int messageType) {
+		code = messageCode;
+		type = messageType;
+	}
+	
+	void setBody(final StringBuilder sb) {
+		body = sb.toString();
+	}
+
+	/**
+	 * @return e.g EC.TLC_VERSION
+	 */
+	public int getCode() {
+		return code;
+	}
+
+	/**
+	 * Returns the type of the message - a.k.a message class
+	 * @return e.g MP.ERROR
+	 */
+	public int getType() {
+		return type;
+	}
+
+	/**
+	 * @return the body of the message - the content of the lines found between the
+	 *         start and end message delimiters
+	 */
+	public String getBody() {
+		return body;
+	}
+	
+	@Override
+	public String toString() {
+		return "[" + code + "," + type + "]\n" + body;
+	}
+}
diff --git a/tlatools/src/tlc2/input/MCOutputParser.java b/tlatools/src/tlc2/input/MCOutputParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..d3b0a0bbf586df23e952e1f2d7dc7ed01e8bc728
--- /dev/null
+++ b/tlatools/src/tlc2/input/MCOutputParser.java
@@ -0,0 +1,125 @@
+package tlc2.input;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import tlc2.TraceExpressionExplorerSpecWriter;
+import tlc2.model.MCError;
+import tlc2.model.MCState;
+import tlc2.output.EC;
+import tlc2.output.MP;
+import util.TLAConstants;
+
+/**
+ * This class provides a parser to extract error & state from an MC.out file; it also provides a public static
+ * 	method which does a pretty-print dump to a provided output stream of the collected states in order.
+ */
+public class MCOutputParser extends AbstractMCOutputConsumer {
+	private final File mcOutFile;
+	
+	MCOutputParser(final File outFile) {
+		mcOutFile = outFile;
+	}
+
+	List<MCOutputMessage> parse(final boolean returnAllMessages) throws IOException {
+		final ArrayList<MCOutputMessage> encounteredMessages = returnAllMessages ? new ArrayList<>() : null;
+		
+		try (final BufferedReader br = new BufferedReader(new FileReader(mcOutFile))) {
+			MCOutputMessage message;
+			
+			while ((message = parseChunk(br)) != null) {
+				if (returnAllMessages) {
+					encounteredMessages.add(message);
+				}
+
+				if (message.getType() == MP.ERROR) {
+					consumeErrorMessageAndStates(br, message);
+				} else if (message.getCode() == EC.TLC_FINISHED) {
+					break;
+				}
+			}
+		}
+
+		return encounteredMessages;
+	}
+
+	
+	private static String getPrettyPrintForState(final MCState state) {
+		if (state.isStuttering()) {
+			return "<Stuttering>";
+		} else if (state.isBackToState()) {
+			return "<Back to state " + state.getStateNumber() + ">";
+		}
+		return state.getLabel();
+	}
+	
+	/**
+	 * @param os an output stream to send the 'pretty printed' trace to, or a
+	 *              notification if the output file contains no error-state
+	 *              messages, or if there is no output file to be found.
+	 * @param sourceDirectory
+	 * @param specName
+	 * @throws IOException
+	 */
+	public static void prettyPrintToStream(final OutputStream os, final File sourceDirectory, final String specName)
+			throws IOException {
+		final File outFile = new File(sourceDirectory, specName + TLAConstants.Files.OUTPUT_EXTENSION);
+		final MCOutputParser parser = new MCOutputParser(outFile);
+		parser.parse(false);
+		
+		final File tlaFile = new File(sourceDirectory, specName + TLAConstants.Files.TLA_EXTENSION);
+		final HashMap<String, String> variableTraceExpressionMap
+									= TraceExpressionExplorerSpecWriter.getVariableExpressionMapFromTLAFile(tlaFile);
+		prettyPrintToStream(os, parser.getError(), variableTraceExpressionMap);
+	}
+	
+	/**
+	 * @param os an output stream to send the 'pretty printed' trace to, or a
+	 *              notification if the error is null
+	 *              messages.
+	 * @param error
+	 * @throws IOException
+	 */
+	public static void prettyPrintToStream(final OutputStream os, final MCError error) {
+		prettyPrintToStream(os, error, null);
+	}
+	
+	/**
+	 * @param os an output stream to send the 'pretty printed' trace to, or a
+	 *              notification if the error is null
+	 *              messages.
+	 * @param error
+	 * @param variableTraceExpressionMap if non-null; any keys which are variable names will have the expressions
+	 * 										substituted for the display.
+	 * @throws IOException
+	 */
+	public static void prettyPrintToStream(final OutputStream os, final MCError error,
+										   final HashMap<String, String> variableTraceExpressionMap) {
+		final PrintStream ps;
+		if (os instanceof PrintStream) {
+			ps = (PrintStream)os;
+		} else {
+			ps = new PrintStream(os);
+		}
+		
+		if (error == null) {
+			ps.println("The output log contained no error-state messages; there is nothing to display.");
+		} else {
+			if (variableTraceExpressionMap != null) {
+				error.updateStatesForTraceExpression(variableTraceExpressionMap);
+			}
+			
+			for (final MCState state : error.getStates()) {
+				ps.println(getPrettyPrintForState(state));
+				ps.println(state.getConjunctiveDescription(true, "\t", true));
+			}
+		}
+	}
+}
diff --git a/tlatools/src/tlc2/input/MCOutputPipeConsumer.java b/tlatools/src/tlc2/input/MCOutputPipeConsumer.java
new file mode 100644
index 0000000000000000000000000000000000000000..911d62febe47d6a8cd51e2c906b548ddf76cdf58
--- /dev/null
+++ b/tlatools/src/tlc2/input/MCOutputPipeConsumer.java
@@ -0,0 +1,137 @@
+package tlc2.input;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+
+import tlc2.output.EC;
+import tlc2.output.MP;
+import util.TLAConstants;
+
+/**
+ * This class exists due to a request for the TraceExplorer CL application to be able to consume the output from TLC
+ * 	piped into TraceExplorer.  To that extent, this class will:
+ * 
+ * 	. read from a stream (for piping, this is System.in)
+ *	. ensure that it is reading tool messages (first line received will be a message of type EC.TLC_VERSION)
+ *			and fail appropriately if not
+ *	. look for the first TLAConstants.LoggingAtoms.PARSING_FILE line in order to derive spec name and source directory
+ *	. continue to read and wait and read and ... until an EC.TLC_FINISHED message is received - writing the content
+ *			to a temp file.
+ */
+public class MCOutputPipeConsumer extends AbstractMCOutputConsumer {
+	public interface ConsumerLifespanListener {
+		void consumptionFoundSourceDirectoryAndSpecName(final MCOutputPipeConsumer consumer);
+	}
+	
+	private String specName;
+	private File sourceDirectory;
+	private boolean currentlyEncounteringModuleInformation;
+	private final ArrayList<File> extendedModuleLocations;
+	
+	private MCOutputMessage tlcVersionMessage;
+
+	private final InputStream sourceStream;
+	private final ConsumerLifespanListener listener;
+	
+	
+	/**
+	 * @param inputStream the stream containing the tool output
+	 */
+	public MCOutputPipeConsumer(final InputStream inputStream, final ConsumerLifespanListener lifespanListener) {
+		sourceStream = inputStream;
+		listener = lifespanListener;
+		currentlyEncounteringModuleInformation = false;
+		extendedModuleLocations = new ArrayList<>();
+	}
+	
+	/**
+	 * This will not return until all output has been read and the output has correctly ended (or if there is a read
+	 * 	error, or if the output is not proper tool message output.)
+	 * 
+	 * @param returnAllMessages if true, all consumed messages will be returned
+	 * @return null or a {@link List} of {@link MCOutputMessage} instances of all messages consumed
+	 * @throws Exception
+	 */
+	public List<MCOutputMessage> consumeOutput(final boolean returnAllMessages) throws IOException {
+		final ArrayList<MCOutputMessage> encounteredMessages = returnAllMessages ? new ArrayList<>() : null;
+		
+		try (final BufferedReader br = new BufferedReader(new InputStreamReader(sourceStream))) {
+			MCOutputMessage message;
+
+			while ((message = parseChunk(br)) != null) {
+				if (returnAllMessages) {
+					encounteredMessages.add(message);
+				}
+
+				if (message.getType() == MP.ERROR) {
+					consumeErrorMessageAndStates(br, message);
+				} else if (message.getCode() == EC.TLC_VERSION) {
+					tlcVersionMessage = message;
+				} else if (message.getCode() == EC.TLC_FINISHED) {
+					break;
+				}
+			}
+		} catch (final IOException ioe) {
+			if (outputHadNoToolMessages()) {
+				// Either we threw this from handleUnknownReadLine(String), or the output was abortive.
+				return encounteredMessages;
+			}
+			
+			throw ioe;
+		}
+		
+		return encounteredMessages;
+	}
+	
+	public boolean outputHadNoToolMessages() {
+		return (tlcVersionMessage == null);
+	}
+	
+	public String getSpecName() {
+		return specName;
+	}
+	
+	public File getSourceDirectory() {
+		return sourceDirectory;
+	}
+	
+	public List<File> getExtendedModuleLocations() {
+		return extendedModuleLocations;
+	}
+	
+	@Override
+	protected void handleUnknownReadLine(final String line) throws IOException {
+		if (((specName == null) || currentlyEncounteringModuleInformation)
+							&& line.startsWith(TLAConstants.LoggingAtoms.PARSING_FILE)) {
+			if (tlcVersionMessage == null) {
+				throw new IOException("Output does not appear to be generated by TLC run with the '-tool' flag.");
+			}
+			
+			final String wholePath = line.substring(TLAConstants.LoggingAtoms.PARSING_FILE.length() + 1);
+			final File tlaFile = new File(wholePath);
+			
+			if (specName == null) {
+				sourceDirectory = tlaFile.getParentFile();
+				
+				final String tlaFilename = tlaFile.getName();
+				final int extensionDotIndex = tlaFilename.lastIndexOf('.');
+				specName = tlaFilename.substring(0, extensionDotIndex);
+				
+				if (listener != null) {
+					listener.consumptionFoundSourceDirectoryAndSpecName(this);
+				}
+				
+				currentlyEncounteringModuleInformation = true;
+			} else {
+				extendedModuleLocations.add(tlaFile);
+			}
+		} else if (currentlyEncounteringModuleInformation) {
+			currentlyEncounteringModuleInformation = false;
+		}
+	}	
+}
diff --git a/tlatools/src/tlc2/input/MCParser.java b/tlatools/src/tlc2/input/MCParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..b4fe53ebe4abaef18a20bbaaae2d5eae438e51be
--- /dev/null
+++ b/tlatools/src/tlc2/input/MCParser.java
@@ -0,0 +1,283 @@
+package tlc2.input;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+
+import tla2sany.semantic.InstanceNode;
+import tla2sany.semantic.ModuleNode;
+import tla2sany.semantic.OpDefNode;
+import tla2sany.semantic.SymbolMatcher;
+import tla2sany.semantic.SymbolNode;
+import tla2sany.st.Location;
+import tlc2.model.MCError;
+import tlc2.tool.Defns;
+import tlc2.tool.impl.ModelConfig;
+import tlc2.tool.impl.SpecProcessor;
+import tlc2.tool.impl.SymbolNodeValueLookupProvider;
+import tlc2.tool.impl.TLAClass;
+import util.FilenameToStream;
+import util.SimpleFilenameToStream;
+import util.TLAConstants;
+
+/**
+ * This class parses the triplet of .out, .cfg, and .tla files - typically thought of as MC.out, MC.cfg, MC.tla, but
+ * 	not required to be such.
+ */
+public class MCParser {
+	private static final int TOOL_ID = 0;
+	
+	/**
+	 * @param specProcessor
+	 * @param modelConfig
+	 * @return an instance of {@link MCParserResults} with neither error nor output messages set, yet
+	 */
+	public static MCParserResults generateResultsFromProcessorAndConfig(final SpecProcessor specProcessor,
+																		final ModelConfig modelConfig) {
+		final String rootModuleName;
+		final String nextOrSpecName;
+		final ArrayList<Location> initNextLocationsToDelete = new ArrayList<>();
+		final boolean isInitNext = !modelConfig.configDefinesSpecification();
+		final ModuleNode root = specProcessor.getRootModule();
+		if (isInitNext) {
+			final String initDefinitionName = modelConfig.getInit();
+			nextOrSpecName = modelConfig.getNext();
+			final Collection<SymbolNode> initNodes = root.getSymbols(new NodeNameMatcher(initDefinitionName));
+			final Collection<SymbolNode> nextNodes = root.getSymbols(new NodeNameMatcher(nextOrSpecName));
+
+			if (initNodes.size() == 1) {
+				final OpDefNode initNode = (OpDefNode) initNodes.iterator().next();
+
+				if (initNode.getOriginallyDefinedInModuleNode().equals(root)) {
+					initNextLocationsToDelete.add(initNode.getLocation());
+				}
+				// else it is defined in a module which the original spec is extending.. nothing to document
+			}
+
+			if (nextNodes.size() == 1) {
+				final OpDefNode nextNode = (OpDefNode) nextNodes.iterator().next();
+
+				if (nextNode.getOriginallyDefinedInModuleNode().equals(root)) {
+					initNextLocationsToDelete.add(nextNode.getLocation());
+				}
+				// else it is defined in a module which the original spec is extending.. nothing to document
+			}
+		} else {
+			nextOrSpecName = modelConfig.getSpec();
+		}
+		initNextLocationsToDelete.sort(new LocationComparator());
+
+		final ArrayList<String> extendees = new ArrayList<>();
+		root.getExtendedModuleSet(false).stream().forEach(moduleNode -> extendees.add(moduleNode.getName().toString()));
+
+		final HashSet<String> allExtendees = new HashSet<>();
+		root.getExtendedModuleSet(true).stream().forEach(moduleNode -> allExtendees.add(moduleNode.getName().toString()));
+		
+		rootModuleName = root.getName().toString();
+		
+		final HashSet<String> instantiatedModules = new HashSet<>();
+		collectionInstantiatedModules(root, instantiatedModules, allExtendees);
+
+		return new MCParserResults(rootModuleName, extendees, allExtendees, instantiatedModules,
+								   initNextLocationsToDelete, isInitNext, nextOrSpecName, modelConfig);
+	}
+	
+	private static void collectionInstantiatedModules(final ModuleNode node, final HashSet<String> modulesList,
+													  final HashSet<String> allExtendees) {
+		final InstanceNode[] instances = node.getInstances();
+		for (final InstanceNode instance : instances) {
+			final ModuleNode instanceModule = instance.getModule();
+			instanceModule.getExtendedModuleSet(true)
+							.stream().forEach(moduleNode -> allExtendees.add(moduleNode.getName().toString()));
+			modulesList.add(instanceModule.getName().toString());
+			collectionInstantiatedModules(instanceModule, modulesList, allExtendees);
+		}
+	}
+	
+	
+	private final ModelConfig configParser;
+
+	private MCOutputParser outputParser;
+	
+	private final TLAClass tlaClass;
+	private final Defns defns;
+	
+	private final FilenameToStream resolver;
+
+	private MCParserResults parserResults;
+	
+	private final String specBaseName;
+	
+	/**
+	 * @param sourceDirectory
+	 * @param specName
+	 * @param specialCaseOutputFile if non-null, this will be used as the source for the output parser
+	 */
+	public MCParser(final File sourceDirectory, final String specName) {
+		this(sourceDirectory, specName, null);
+		
+		File f= new File(sourceDirectory, (specBaseName + TLAConstants.Files.OUTPUT_EXTENSION));
+		if (!f.exists()) {
+			throw new IllegalArgumentException("No readable output file could be found at " + f.getAbsolutePath());
+		}
+		
+		outputParser = new MCOutputParser(f);
+		
+		f = new File(sourceDirectory, (specBaseName + TLAConstants.Files.TLA_EXTENSION));
+		if (!f.exists()) {
+			throw new IllegalArgumentException("No readable TLA file could be found at " + f.getAbsolutePath());
+		}
+	}
+	
+	/**
+	 * @param sourceDirectory
+	 * @param specName
+	 * @param ignoreOutputParse if this is true, no output parsing will be done by this instance; the results returned
+	 * 			by {@link #parse()} will contain no output messages nor any potential {@code MCError}
+	 */
+	public MCParser(final File sourceDirectory, final String specName, final boolean ignoreOutputParse) {
+		this(sourceDirectory, specName, null);
+
+		if (!ignoreOutputParse) {
+			final File f = new File(sourceDirectory, (specBaseName + TLAConstants.Files.OUTPUT_EXTENSION));
+			if (!f.exists()) {
+				throw new IllegalArgumentException("No readable output file could be found at " + f.getAbsolutePath());
+			}
+			
+			outputParser = new MCOutputParser(f);
+		}
+		
+		final File f = new File(sourceDirectory, (specBaseName + TLAConstants.Files.TLA_EXTENSION));
+		if (!f.exists()) {
+			throw new IllegalArgumentException("No readable TLA file could be found at " + f.getAbsolutePath());
+		}
+	}
+	
+	private MCParser(final File sourceDirectory, final String specName, final Object signatureDifferentiator) {
+		resolver = new SimpleFilenameToStream(sourceDirectory.getAbsolutePath());
+		specBaseName = specName;
+		
+		final File f = new File(sourceDirectory, (specBaseName + TLAConstants.Files.CONFIG_EXTENSION));
+		if (!f.exists()) {
+			throw new IllegalArgumentException("No readable config file could be found at " + f.getAbsolutePath());
+		}
+		configParser = new ModelConfig(f.getAbsolutePath(), resolver);
+		
+		tlaClass = new TLAClass("tlc2.module", resolver);
+		defns = new Defns();
+	}
+	
+	/**
+	 * @return will return null until {@link #parse()} has been run successfully
+	 */
+	public MCParserResults getParseResults() {
+		return parserResults;
+	}
+
+	/**
+	 * @return an instance of {@link MCParserResults} representing the results. If
+	 *         this instance was constructed via
+	 *         {@link #MCParser(File, String, boolean)} with the third argument
+	 *         {@code true} then the results returned will contain no output
+	 *         messages nor any potential {@code MCError}
+	 * @throws IllegalStateException if parse has already been called on this
+	 *                               instance
+	 */
+	public MCParserResults parse() {
+		if (parserResults != null) {
+			throw new IllegalStateException("Parse has already been called.");
+		}
+		
+		try {
+			final List<MCOutputMessage> encounteredMessages = (outputParser != null) ? outputParser.parse(true) : null;
+
+			configParser.parse();
+
+			// No reason to start-up SANY if we're not going to generate something because the output file is unusable
+			if ((encounteredMessages == null) || (encounteredMessages.size() > 0)) {
+				final SymbolNodeValueLookupProvider defaultLookup = new SymbolNodeValueLookupProvider() {};
+				final SpecProcessor specProcessor = new SpecProcessor(specBaseName, resolver, TOOL_ID, defns,
+																	  configParser, defaultLookup, null, tlaClass);
+				parserResults = generateResultsFromProcessorAndConfig(specProcessor, configParser);
+				
+				if (outputParser != null) {
+					parserResults.setError(outputParser.getError());
+					parserResults.setOutputMessages(encounteredMessages);
+				}
+			} else {
+				// we'll have a zero size if the output generated came from a TLC run that did not have the '-tool' flag
+				parserResults = new MCParserResults(null, ((outputParser != null) ? outputParser.getError() : null),
+													encounteredMessages, new ArrayList<>(), new HashSet<>(),
+													new HashSet<>(), new ArrayList<>(), true, null, configParser);
+			}
+			
+			return parserResults;
+		} catch (final IOException e) {
+			System.out.println("Caught exception while performing MC parsing: " + e.getMessage());
+			e.printStackTrace();
+		}
+
+		return null;
+	}
+
+	
+	public static void main(final String[] args) throws Exception {
+		final MCParser parser = new MCParser(new File(args[0]), TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, null);
+		final MCParserResults results = parser.parse();
+		
+		System.out.println("Parse encountered " + results.getOutputMessages().size() + " messages.");
+		final MCError error = results.getError();
+		if (error != null) {
+			System.out.println("Encountered error: ");
+			System.out.println(error.toSequenceOfRecords(true));
+		}
+		
+		final List<String> extendedModules = results.getOriginalExtendedModules();
+		System.out.println("Found " + extendedModules.size() + " module(s) being extended explicitly by the root spec:");
+		for (final String module : extendedModules) {
+			System.out.println("\t" + module);
+		}
+	}
+	
+	
+	private static class NodeNameMatcher implements SymbolMatcher {
+		private final String name;
+		
+		NodeNameMatcher(final String nameToMatch) {
+			name = nameToMatch;
+		}
+
+		@Override
+		public boolean matches(final SymbolNode aSymbol) {
+			if (aSymbol.getName() != null) {
+				return name.equals(aSymbol.getName().toString());
+			}
+			return false;
+		}
+	}
+	
+	
+	// orders from location first in document to that which is last in document
+	private static class LocationComparator implements Comparator<Location> {
+		@Override
+		public int compare(final Location l2, final Location l1) {
+			if (l1.beginLine() == l2.beginLine()) {
+				if (l1.beginColumn() != l2.beginColumn()) {
+					return l1.beginColumn() - l2.beginColumn();
+				}
+				
+				if (l1.endLine() != l2.endLine()) {
+					return l1.endLine() - l2.endLine();
+				}
+				
+				return l1.endColumn() - l2.endColumn();
+			}
+			
+			return l1.beginLine() - l2.beginLine();
+		}
+	}
+}
diff --git a/tlatools/src/tlc2/input/MCParserResults.java b/tlatools/src/tlc2/input/MCParserResults.java
new file mode 100644
index 0000000000000000000000000000000000000000..b3f57e89acfc96ddf63dbb780e7c88098551954c
--- /dev/null
+++ b/tlatools/src/tlc2/input/MCParserResults.java
@@ -0,0 +1,122 @@
+package tlc2.input;
+
+import java.util.List;
+import java.util.Set;
+
+import tla2sany.st.Location;
+import tlc2.model.MCError;
+import tlc2.tool.impl.ModelConfig;
+
+public class MCParserResults {
+	private final String moduleName;
+	
+	private MCError error;
+	private List<MCOutputMessage> outputMessages;
+
+	private final List<String> immediateExtendedModules;
+	private final Set<String> allExtendedModules;
+	private final Set<String> modulesInstantiated;
+
+	private final List<Location> initNextLocationsToDelete;
+
+	private final boolean behaviorIsInitNext;
+	
+	private final String originalNextOrSpecificationName;
+	
+	private final ModelConfig modelConfig;
+
+	MCParserResults(final String rootModuleName, final List<String> immediateExtendeds, final Set<String> allExtendeds,
+			 		final Set<String> allInstantiated, final List<Location> initNextLocations,
+			 		final boolean wasInitNext, final String nextOrSpecName, final ModelConfig config) {
+		moduleName = rootModuleName;
+		
+		immediateExtendedModules = immediateExtendeds;
+		allExtendedModules = allExtendeds;
+		
+		modulesInstantiated = allInstantiated;
+		
+		initNextLocationsToDelete = initNextLocations;
+		
+		behaviorIsInitNext = wasInitNext;
+		
+		originalNextOrSpecificationName = nextOrSpecName;
+		
+		modelConfig = config;
+	}
+	
+	MCParserResults(final String rootModuleName, final MCError mcError, final List<MCOutputMessage> messages,
+					final List<String> immediateExtendeds, final Set<String> allExtendeds,
+					final Set<String> allInstantiated, final List<Location> initNextLocations,
+					final boolean wasInitNext, final String nextOrSpecName, final ModelConfig config) {
+		this(rootModuleName, immediateExtendeds, allExtendeds, allInstantiated, initNextLocations, wasInitNext,
+			 nextOrSpecName, config);
+		
+		error = mcError;
+		outputMessages = messages;
+	}
+	
+	public ModelConfig getModelConfig() {
+		return modelConfig;
+	}
+	
+	public String getModuleName() {
+		return moduleName;
+	}
+	
+	public String getOriginalNextOrSpecificationName() {
+		return originalNextOrSpecificationName;
+	}
+
+	public MCError getError() {
+		return error;
+	}
+	
+	void setError(final MCError mcError) {
+		error = mcError;
+	}
+	
+	public List<MCOutputMessage> getOutputMessages() {
+		return outputMessages;
+	}
+	
+	void setOutputMessages(final List<MCOutputMessage> messages) {
+		outputMessages = messages;
+	}
+
+	/**
+	 * @return the {@link List} of all modules extended by the root spec explicitly - in other words, for example,
+	 * 				the X, Y, Z cited by a root spec's "EXTENDS X, Y, Z"
+	 */
+	public List<String> getOriginalExtendedModules() {
+		return immediateExtendedModules;
+	}
+	
+	/**
+	 * @return the {@link Set} of all modules extended - in other words, the modules extended by all modules extended
+	 * 				by all modules extended by ... the root spec.
+	 */
+	public Set<String> getAllExtendedModules() {
+		return allExtendedModules;
+	}
+	
+	/**
+	 * @return this returns a {@link Set} of all instantiated modules - in other words, all modules, X, found in any
+	 * 				module of the entire module tree that is instantiated in TLA+ code like {@code ... = INSTANCE X}
+	 * 				<b>Note:</b> the is the possibility of a non-null intersection between this set and the set of
+	 * 				extended modules.
+	 */
+	public Set<String> getAllInstantiatedModules() {
+		return modulesInstantiated;
+	}
+
+	/**
+	 * @return ordered from location first in document to that which is last in document
+	 */
+	public List<Location> getInitNextLocationsToDelete() {
+		return initNextLocationsToDelete;
+	}
+
+	public boolean isBehaviorInitNext() {
+		return behaviorIsInitNext;
+	}
+}
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Assignment.java b/tlatools/src/tlc2/model/Assignment.java
similarity index 85%
rename from org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Assignment.java
rename to tlatools/src/tlc2/model/Assignment.java
index 71c7954451b72a237d504604521addb86a5b5ce4..29e9e4a425810fa6164e44aa389732f0025d52d6 100644
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Assignment.java
+++ b/tlatools/src/tlc2/model/Assignment.java
@@ -1,6 +1,4 @@
-package org.lamport.tla.toolbox.tool.tlc.model;
-
-
+package tlc2.model;
 
 /**
  * An Assignment consists of a label, a list of parameters and the right side.
@@ -29,29 +27,27 @@ package org.lamport.tla.toolbox.tool.tlc.model;
  * @author Simon Zambrovski
  * @version $Id$
  */
-public class Assignment extends Formula
-{
+public class Assignment extends Formula {
     public static final String ASSIGNMENT_SIGN = " <- ";
     public static final String IS_MV = " [ model value ] ";
     public static final String SYMMETRICAL = " <symmetrical> ";
 
+    
     private String label;
     private String[] params = new String[0];
     private boolean modelValue = false;
     private boolean symmetry = false;
+    private TypedSet setOfModelValues = null;
 
     /**
      * Constructs the assignment
      * if the right side is equals to the label, the assignment is treated as a model value assignment
      */
-    public Assignment(String label, String[] params, String right)
-    {
-
+	public Assignment(String label, String[] params, String right) {
         super(right);
         this.label = label;
         this.setParams(params);
-        if (this.label != null && right != null && this.label.equals(right))
-        {
+		if ((this.label != null) && (right != null) && this.label.equals(right)) {
             // right side equals label => model value
             setModelValue(true);
         }
@@ -120,14 +116,14 @@ public class Assignment extends Formula
         {
             return "";
         }
-        StringBuffer buffer = new StringBuffer();
-        buffer.append("(");
+        final StringBuilder buffer = new StringBuilder();
+        buffer.append('(');
         for (int i = 0; i < params.length; i++)
         {
             buffer.append(params[i]);
             buffer.append((i != params.length - 1) ? ", " : "");
         }
-        buffer.append(")");
+        buffer.append(')');
         return buffer.toString();
     }
 
@@ -195,10 +191,10 @@ public class Assignment extends Formula
      * Sets the right part
      * @param right
      */
-    public void setRight(String right)
-    {
-        super.setFormula(right);
-    }
+	public synchronized void setRight(String right) {
+		super.setFormula(right);
+		setOfModelValues = null;
+	}
 
     /**
      * Set parameters, the left part depends on
@@ -222,8 +218,7 @@ public class Assignment extends Formula
     }
 
     /**
-     * Returns if this assignment is to be set to the model value
-     * @return
+     * @return if this assignment is to be set to the model value
      */
     public boolean isModelValue()
     {
@@ -238,19 +233,32 @@ public class Assignment extends Formula
     }
     
     /**
-     * Returns true, iff the assignment is a set of model values
+     * @return true, iff the assignment is a set of model values
      */
-    public boolean isSetOfModelValues()
-    {
+	public boolean isSetOfModelValues() {
         return modelValue && !getLabel().equals(getRight());
     }
+	
+	/**
+	 * @return the TypedSet for model values if {@link #isSetOfModelValues()} returns true, otherwise null
+	 */
+	public synchronized TypedSet getSetOfModelValues() {
+		if (isSetOfModelValues()) {
+			if (setOfModelValues == null) {
+				setOfModelValues = TypedSet.parseSet(getRight());
+			}
+			
+			return setOfModelValues;
+		}
+		
+		return null;
+	}
 
     /**
-     * Returns true, if the set of model values is symmetrical 
+     * @return true, if the set of model values is symmetrical 
      */
-    public boolean isSymmetricalSet()
-    {
-        return symmetry;
+	public boolean isSymmetricalSet() {
+		return symmetry;
     }
 
     /**
diff --git a/tlatools/src/tlc2/model/Formula.java b/tlatools/src/tlc2/model/Formula.java
new file mode 100644
index 0000000000000000000000000000000000000000..aa429c18a6269444679fa42764df77b12239b62e
--- /dev/null
+++ b/tlatools/src/tlc2/model/Formula.java
@@ -0,0 +1,86 @@
+package tlc2.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Representation of a formula.
+ * @author Simon Zambrovski
+ */
+public class Formula {
+    /**
+     * De-serialize formula list, to a list of formulas, that are selected (have a leading "1")
+     * 
+     * The first character of the formula is used to determine if the formula is enabled in the model 
+     * editor or not. This allows the user to persist formulas, which are not used in the current model 
+     */
+	public static List<Formula> deserializeFormulaList(final List<String> serializedList) {
+		final ArrayList<Formula> result = new ArrayList<>(serializedList.size());
+		for (final String entry : serializedList) {
+			if ("1".equals(entry.substring(0, 1))) {
+				result.add(new Formula(entry.substring(1)));
+			}
+		}
+		return result;
+	}
+	
+    // DOTALL to match beyond line endings.
+    private static final Pattern PATTERN = Pattern.compile("^\\s*(\\w+)\\s*==(.*)$", Pattern.DOTALL);
+    
+	
+    private String formula;
+
+    /**
+     * Constructs a formula representation
+     * @param formula
+     */
+	public Formula(String formulaString) {
+		formula = formulaString;
+	}
+
+	/**
+	 * Retrives formula
+	 * 
+	 * @return
+	 */
+	public String getFormula() {
+		return formula;
+	}
+
+	@Override
+	public String toString() {
+		return formula;
+	}
+
+	/**
+	 * @param formulaString
+	 */
+	public void setFormula(String formulaString) {
+		formula = formulaString;
+	}
+
+	// MAK 03/2019: This methods below appear redundant to the Assignment subclass
+	// but I don't have time to look into it.
+    
+    public boolean isNamed()  {
+    	return !getLeftHandSide().equals(getFormula());
+    }
+    
+    public String getLeftHandSide() {
+		final Matcher matcher = PATTERN.matcher(this.formula);
+		if (matcher.find()) {
+			return matcher.group(1).trim();
+		}
+		return getFormula();
+    }
+    
+    public String getRightHandSide() {
+		final Matcher matcher = PATTERN.matcher(this.formula);
+		if (matcher.find()) {
+			return matcher.group(2).trim();
+		}
+		return getFormula();
+    }
+}
diff --git a/tlatools/src/tlc2/model/MCError.java b/tlatools/src/tlc2/model/MCError.java
new file mode 100644
index 0000000000000000000000000000000000000000..69b60a9e894d84394628760bc6c5bc633892bdf1
--- /dev/null
+++ b/tlatools/src/tlc2/model/MCError.java
@@ -0,0 +1,79 @@
+package tlc2.model;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import util.TLAConstants;
+
+public class MCError {
+	private final String message;
+	private final MCError cause;
+	private final ArrayList<MCState> states;
+	
+	public MCError(final MCError errorCause, final String errorMessage) {
+		cause = errorCause;
+		message = errorMessage;
+		states = new ArrayList<>();
+	}
+	
+	public void addState(final MCState state) {
+		states.add(state);
+	}
+	
+	public List<MCState> getStates() {
+		return states;
+	}
+	
+	public String getMessage() {
+		return message;
+	}
+	
+	public MCError getCause() {
+		return cause;
+	}
+	
+	public void updateStatesForTraceExpression(final HashMap<String, String> variableExpressionMap) {
+		for (final MCState state : states) {
+			for (final MCVariable variable : state.getVariables()) {
+				final String expression = variableExpressionMap.get(variable.getName());
+
+				if (expression != null) {
+					variable.setTraceExpression(expression);
+				}
+			}
+		}
+	}
+
+	public String toSequenceOfRecords(final boolean includeHeaders) {
+		final StringBuilder buf = new StringBuilder();
+		buf.append(TLAConstants.BEGIN_TUPLE);
+		buf.append(TLAConstants.CR);
+		
+		for (int i = 0; i < states.size(); i++) {
+			final MCState tlcState = states.get(i);
+			
+			if (tlcState.isBackToState() || tlcState.isStuttering()) {
+				//TODO How to represent these two types of states?
+				continue;
+			}
+			
+			if ((tlcState.getVariables().length == 0) && !includeHeaders) {
+				// When an user has used filtering to hide all variables, the error trace here
+				// has no variables. In this case just return empty sequence <<>> by breaking
+				// from the loop.
+				break;
+			}
+			
+			if (i > 0) {
+				// Append a comma if a record is going to be added below.
+				buf.append(TLAConstants.COMMA).append(TLAConstants.CR);
+			}
+			buf.append(tlcState.asRecord(includeHeaders));
+		}
+			
+		buf.append(TLAConstants.CR);
+		buf.append(TLAConstants.END_TUPLE);
+		return buf.toString();
+	}
+}
diff --git a/tlatools/src/tlc2/model/MCState.java b/tlatools/src/tlc2/model/MCState.java
new file mode 100644
index 0000000000000000000000000000000000000000..aa1af885eab94d9126af0437d2c2fc68812ef216
--- /dev/null
+++ b/tlatools/src/tlc2/model/MCState.java
@@ -0,0 +1,303 @@
+package tlc2.model;
+
+import java.util.ArrayList;
+
+import tla2sany.st.Location;
+import util.TLAConstants;
+
+public class MCState {
+	private static final String BACK_TO_STATE = " " + TLAConstants.BACK_TO_STATE;
+
+	public static MCState parseState(final String stateInputString) {
+		// state number
+		final int index = stateInputString.indexOf(TLAConstants.COLON);
+		// multi line
+		int index2 = stateInputString.indexOf(TLAConstants.CR, index);
+		if (index2 == -1) {
+			index2 = stateInputString.length();
+		}
+
+		final int stateNumber = Integer.parseInt(stateInputString.substring(0, index).trim());
+		final String label = stateInputString.substring((index + 1), index2);
+		final boolean isStuttering = (label.indexOf(TLAConstants.STUTTERING) == 0);
+		final boolean isBackToState = (label.indexOf(BACK_TO_STATE) == 0);
+
+		MCVariable[] vars = null;
+		final String name;
+		final Location location;
+		if (!isBackToState && !isStuttering) {
+			// string from which the variables can be parsed
+			final String variableInputString = stateInputString.substring(index2 + 1);
+			vars = parseVariables(variableInputString);
+			
+			final String sublabel = label.substring(2, (label.length() - 1));
+			final int lineIndex = sublabel.indexOf(TLAConstants.LINE);
+			if (lineIndex != -1) {
+				name = sublabel.substring(0, (lineIndex - 1));
+				location = Location.parseLocation(sublabel.substring(lineIndex));
+			} else {
+				name = sublabel;
+				location = null;
+			}
+		} else {
+			name = null;
+			location = null;
+		}
+
+		return new MCState(vars, name, label, location, isStuttering, isBackToState, stateNumber);
+	}
+
+	
+	private final MCVariable[] variables;
+	private final String name;
+	private final String label;
+	private final Location location;
+	private final boolean isStuttering;
+	private final boolean isBackToState;
+	private final int stateNumber;
+
+	/**
+	 * @param vars            variables in this state.
+	 * @param stateName       the name for this state
+	 * @param stateLabel      the display label, usually including line location and module
+	 * @param moduleLocation  the name of this module whose checking this state is from
+	 * @param stuttering      whether this is a stuttering state or not
+	 * @param backToState     whether this is a back to state or not
+	 * @param ordinal         number of the state in the trace
+	 */
+	public MCState(final MCVariable[] vars, final String stateName, final String stateLabel,
+			final Location moduleLocation, final boolean stuttering, final boolean backToState, final int ordinal) {
+		variables = vars;
+		name = stateName;
+		label = stateLabel;
+		location = moduleLocation;
+		isStuttering = stuttering;
+		isBackToState = backToState;
+		stateNumber = ordinal;
+	}
+
+	public MCVariable[] getVariables() {
+		return variables;
+	}
+	
+	public String getLabel() {
+		 return label;
+	}
+
+	public boolean isStuttering() {
+		return isStuttering;
+	}
+
+	public boolean isBackToState() {
+		return isBackToState;
+	}
+
+	public int getStateNumber() {
+		return stateNumber;
+	}
+	
+	public String asRecord(final boolean includeHeader) {
+		final StringBuilder result = new StringBuilder();
+		result.append(TLAConstants.L_SQUARE_BRACKET);
+		result.append(TLAConstants.CR);
+		
+		if (includeHeader) {
+			result.append(TLAConstants.SPACE);
+			result.append(TLAConstants.TraceExplore.ACTION);
+			result.append(TLAConstants.RECORD_ARROW);
+			
+			result.append(TLAConstants.L_SQUARE_BRACKET);
+			result.append(TLAConstants.CR);
+			result.append(TLAConstants.SPACE).append(TLAConstants.SPACE).append(TLAConstants.SPACE);
+				result.append("position");
+				result.append(TLAConstants.RECORD_ARROW);
+				result.append(getStateNumber());
+				result.append(TLAConstants.COMMA).append(TLAConstants.CR);
+			
+				result.append(TLAConstants.SPACE).append(TLAConstants.SPACE).append(TLAConstants.SPACE);
+				result.append("name");
+				result.append(TLAConstants.RECORD_ARROW);
+				result.append(TLAConstants.QUOTE);
+				result.append(name);
+				result.append(TLAConstants.QUOTE);
+				result.append(TLAConstants.COMMA).append(TLAConstants.CR);
+				
+				result.append(TLAConstants.SPACE).append(TLAConstants.SPACE).append(TLAConstants.SPACE);
+				result.append("location");
+				result.append(TLAConstants.RECORD_ARROW);
+				result.append(TLAConstants.QUOTE);
+				result.append(location);
+				result.append(TLAConstants.QUOTE);
+				
+			result.append(TLAConstants.CR);
+			result.append(TLAConstants.SPACE).append(TLAConstants.R_SQUARE_BRACKET);
+			if (variables.length != 0) {
+				// only append comma for additional records iff there are any variables to
+				// append.
+				result.append(TLAConstants.COMMA).append(TLAConstants.CR);
+			}
+		}
+		
+		for (int i = 0; i < variables.length; i++) {
+			final MCVariable variable = variables[i];
+			if (variable.isTraceExplorerExpression()) {
+				result.append(variable.getSingleLineDisplayName());
+			} else {
+				result.append(variable.getName());
+			}
+
+			result.append(TLAConstants.RECORD_ARROW);
+
+			result.append(variable.getValueAsString());
+			
+			if (i < (variables.length - 1)) {
+				result.append(TLAConstants.COMMA).append(TLAConstants.CR);
+			}
+		}
+		
+		result.append(TLAConstants.CR).append(TLAConstants.R_SQUARE_BRACKET);
+		return result.toString();
+	}
+
+	public String asSimpleRecord() {
+		final StringBuilder buf = new StringBuilder();
+		buf.append(TLAConstants.L_SQUARE_BRACKET);
+		for (int i = 0; i < variables.length; i++) {
+			final MCVariable var = variables[i];
+
+			buf.append(var.getName());
+			buf.append(TLAConstants.RECORD_ARROW);
+			buf.append(var.getValueAsString());
+
+			if (i < variables.length - 1) {
+				buf.append(TLAConstants.COMMA);
+			}
+		}
+		buf.append(TLAConstants.R_SQUARE_BRACKET);
+		return buf.toString();
+	}
+
+    /**
+     * The returns a conjunction list of variables.
+     * 
+     * For variables representing trace explorer expressions, if {@code includeTraceExpressions} is true,
+     * the returned string has:
+     * 
+     * /\ expr = value
+     * 
+     * where expr is the single line form of the trace explorer expression as shown in the Name column of
+     * the trace viewer.
+     *  
+     * For all other variables, this method attempts to display them as TLC does.
+     * 
+     * @param includeTraceExpressions whether trace expressions should be included.
+     * @param indent if non-null, this will be prepended to each line
+     * @return
+     */
+    public String getConjunctiveDescription(final boolean includeTraceExpressions, final String indent) {
+        return getConjunctiveDescription(includeTraceExpressions, indent, false);
+    }
+
+    /**
+     * The returns a conjunction list of variables.
+     * 
+     * For variables representing trace explorer expressions, if {@code includeTraceExpressions} is true,
+     * the returned string has:
+     * 
+     * /\ expr = value
+     * 
+     * where expr is the single line form of the trace explorer expression as shown in the Name column of
+     * the trace viewer.
+     *  
+     * For all other variables, this method attempts to display them as TLC does.
+     * 
+     * @param includeTraceExpressions whether trace expressions should be included.
+     * @param indent if non-null, this will be prepended to each line
+     * @param ansiMarkup if true, the String will include ANSI markup for trace expressions; this is currently ignored
+     * 							if includeTraceExpressions is false
+     * @return
+     */
+    public String getConjunctiveDescription(final boolean includeTraceExpressions, final String indent,
+    										final boolean ansiMarkup) {
+        final StringBuilder result = new StringBuilder();
+        
+		for (int i = 0; i < variables.length; i++) {
+			final MCVariable var = variables[i];
+			
+			if (var.isTraceExplorerExpression() && !includeTraceExpressions) {
+				continue;
+			}
+			
+			if (indent != null) {
+				result.append(indent);
+			}
+			
+            result.append("/\\ ");
+			if (var.isTraceExplorerExpression()) {
+				if (ansiMarkup) {
+					result.append(TLAConstants.ANSI.BOLD_CODE);
+				}
+				
+				result.append(var.getSingleLineDisplayName());
+			} else {
+				result.append(var.getName());
+			}
+
+            result.append(" = ").append(var.getValueAsString());
+
+			if (var.isTraceExplorerExpression() && ansiMarkup) {
+				result.append(TLAConstants.ANSI.RESET_CODE);
+			}
+			
+            result.append('\n');
+        }
+		
+        return result.toString();
+    }
+
+	
+	private static MCVariable[] parseVariables(final String variableInputString) {
+		String[] lines = variableInputString.split(TLAConstants.CR);
+		ArrayList<MCVariable> vars = new ArrayList<>();
+		int index;
+
+		// buffer for accumulating the state variable
+		String[] stateVarString = null;
+
+		// iterate line-wise
+		for (int j = 0; j < lines.length; j++) {
+			// find the index of the first /\ in the line
+			index = lines[j].indexOf(TLAConstants.TLA_AND);
+			// adding the current line to the previous lines
+			if (index != -1) {
+				// there was something in the buffer for the state variable
+				// found an empty line, which means that this is the end of the current state
+				if (stateVarString != null) {
+					final MCVariable var = new MCVariable(stateVarString[0], stateVarString[1]);
+					vars.add(var);
+				}
+
+				stateVarString = lines[j].substring(index + TLAConstants.TLA_AND.length() + 1).split(TLAConstants.EQ);
+			} else {
+				// no index
+
+				if (stateVarString != null) {
+					// either an empty line
+					stateVarString[1] += TLAConstants.CR;
+					stateVarString[1] += lines[j];
+				} else {
+					// the state has one variable only
+					stateVarString = lines[j].split(TLAConstants.EQ);
+				}
+			}
+		}
+
+		// write the last one
+		if (stateVarString != null) {
+			final MCVariable var = new MCVariable(stateVarString[0], stateVarString[1]);
+			vars.add(var);
+		}
+
+		return (MCVariable[]) vars.toArray(new MCVariable[vars.size()]);
+	}
+}
diff --git a/tlatools/src/tlc2/model/MCVariable.java b/tlatools/src/tlc2/model/MCVariable.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff057303a0cbd1cd270cf2935cea9d07e652382f
--- /dev/null
+++ b/tlatools/src/tlc2/model/MCVariable.java
@@ -0,0 +1,62 @@
+package tlc2.model;
+
+public class MCVariable {
+    private final String name;
+    private final String valueAsString;
+    private String traceExpression;
+
+	/**
+	 * @param varName   name of the variable
+	 * @param value     TLC string representation of the variable value
+	 */
+	public MCVariable(final String varName, final String value) {
+		name = varName;
+		valueAsString = value;
+		traceExpression = null;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+    /**
+	 * @return the name, or the trace expression if it is defined, for this variable
+	 *         in a single line String; the name could be multiple lines if this
+	 *         represents a trace explorer expression.
+	 */
+	public String getSingleLineDisplayName() {
+		final String s = isTraceExplorerExpression() ? traceExpression : name;
+		
+		return s.replaceAll("\\n", "").replaceAll("\\r", "");
+	}
+
+	public String getValueAsString() {
+		return valueAsString;
+	}
+	
+	public String getValueAsStringReIndentedAs(final String indent) {
+		final String[] split = valueAsString.split("(\\r\\n|\\r|\\n)");
+		final StringBuilder sb = new StringBuilder();
+
+		for (int i = 0; i < split.length; i++) {
+			sb.append(indent).append(split[i]);
+			if (i < (split.length - 1)) {
+				sb.append("\n");
+			}
+		}
+		
+		return sb.toString();
+	}
+	
+	public boolean isTraceExplorerExpression() {
+		return (traceExpression != null);
+	}
+	
+	public void setTraceExpression(final String expression) {
+		traceExpression = expression;
+	}
+	
+	public String getTraceExpression() {
+		return traceExpression;
+	}
+}
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TraceExpressionInformationHolder.java b/tlatools/src/tlc2/model/TraceExpressionInformationHolder.java
similarity index 51%
rename from org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TraceExpressionInformationHolder.java
rename to tlatools/src/tlc2/model/TraceExpressionInformationHolder.java
index 8fc7e5e67fc4af145fbaac10442fbd2df1474644..a771e76a13d090112b7002deaa062f914b1e42cc 100644
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TraceExpressionInformationHolder.java
+++ b/tlatools/src/tlc2/model/TraceExpressionInformationHolder.java
@@ -1,4 +1,9 @@
-package org.lamport.tla.toolbox.tool.tlc.launch;
+package tlc2.model;
+
+import java.util.List;
+
+import tlc2.output.SpecWriterUtilities;
+import util.TLAConstants;
 
 /**
  * A container class for the relevant information about a
@@ -9,9 +14,39 @@ package org.lamport.tla.toolbox.tool.tlc.launch;
  * @author Daniel Ricketts
  *
  */
-public class TraceExpressionInformationHolder
-{
+public class TraceExpressionInformationHolder {
+	/**
+	 * @param expressions
+	 * @param attributeName
+	 * @return expressions.size() instances of {@code TraceExpressionInformationHolder}
+	 */
+	public static TraceExpressionInformationHolder[] createHolders(final List<Formula> expressions, final String attributeName) {
+		final TraceExpressionInformationHolder[] holders = new TraceExpressionInformationHolder[expressions.size()];
+	    int position = 0;
+	    for (final Formula formula : expressions) {
+			final String expression = formula.getFormula();
+	
+			if ((expression != null) && (expression.length() > 0)) {
+	        	final String identifier
+	        			= SpecWriterUtilities.getValidIdentifier(TLAConstants.Schemes.TRACE_EXPR_DEF_SCHEME);
+	        	if (formula.isNamed()) {
+	        		final String varname = formula.getLeftHandSide();
+	        		final String rightHandSide = formula.getRightHandSide();
+					holders[position] = new TraceExpressionInformationHolder(rightHandSide, identifier, varname);
+	        	} else  {
+	        		final String varname
+	        				= SpecWriterUtilities.getValidIdentifier(TLAConstants.Schemes.TRACE_EXPR_VAR_SCHEME);
+	        		holders[position] = new TraceExpressionInformationHolder(expression, identifier, varname);
+	        	}
+	        }
+	
+	        position++;
+	    }
+	    
+	    return holders;
+	}
 
+	
     /*
      * The expression that the user wants to be evaluated at every
      * state of the trace. 
diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TypedSet.java b/tlatools/src/tlc2/model/TypedSet.java
similarity index 92%
rename from org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TypedSet.java
rename to tlatools/src/tlc2/model/TypedSet.java
index 00c183d4c6c9d2d6acbbb4ab817cd7e8ee4363d5..e890e7e486bc9c699d998453bbd36bef4fc8edf6 100644
--- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TypedSet.java
+++ b/tlatools/src/tlc2/model/TypedSet.java
@@ -1,4 +1,4 @@
-package org.lamport.tla.toolbox.tool.tlc.model;
+package tlc2.model;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -22,11 +22,13 @@ import java.util.List;
  * @author Simon Zambrovski
  * @version $Id$
  */
-public class TypedSet
-{
+public class TypedSet {
+	public static final TypedSet EMPTY_SET = new TypedSet();
+	
     private static final String SEPARATOR = "_";
     private static final String PATTERN = "[\\s]*,[\\s]*";
 
+    
     private String[] values = new String[0];
     private String type = null;
 
@@ -161,6 +163,24 @@ public class TypedSet
     public void unsetType() {
     	setType(null);
     }
+    
+    /**
+     * Not remotely efficient.
+     * 
+     * @param value
+     * @return true if the parameter value is one of this set's values.
+     */
+    public boolean contains(final String value) {
+    	if (value != null) {
+    		for (final String aValue : values) {
+    			if (value.equals(aValue)) {
+    				return true;
+    			}
+    		}
+    	}
+    	
+    	return false;
+    }
 
     public String[] getValues()
     {
diff --git a/tlatools/src/tlc2/module/AnySet.java b/tlatools/src/tlc2/module/AnySet.java
index dd9263c8f52dd84296fbb4ad5a8ba178cdb5f284..90785d9d1363bf79079d950fea09ff4f307c23d4 100644
--- a/tlatools/src/tlc2/module/AnySet.java
+++ b/tlatools/src/tlc2/module/AnySet.java
@@ -16,28 +16,32 @@ public class AnySet extends UserObj
 {
 	public static final long serialVersionUID = 20160822L;
 
-    private static Value AnySet = new UserValue(new AnySet());
+    private final static Value AnySet = new UserValue(new AnySet());
 
     public static Value ANY()
     {
         return AnySet;
     }
 
+    @Override
     public final int compareTo(Value val)
     {
         throw new EvalException(EC.TLC_MODULE_COMPARE_VALUE, new String[] { "ANY", Values.ppr(val.toString()) });
     }
 
+    @Override
     public final boolean member(Value val)
     {
         return true;
     }
 
+    @Override
     public final boolean isFinite()
     {
         return false;
     }
 
+    @Override
     public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow)
     {
         return sb.append("ANY");
diff --git a/tlatools/src/tlc2/module/Bags.java b/tlatools/src/tlc2/module/Bags.java
index 255edfad01dc424fe0ef6d9d28f60f89651ef2da..d6651aade02556e11c05bb1058063f0c8fd2cfed 100644
--- a/tlatools/src/tlc2/module/Bags.java
+++ b/tlatools/src/tlc2/module/Bags.java
@@ -184,8 +184,8 @@ public class Bags implements ValueConstants
         Value[] values = new Value[dVec.size()];
         for (int i = 0; i < domain.length; i++)
         {
-            domain[i] = (Value) dVec.elementAt(i);
-            values[i] = (Value) vVec.elementAt(i);
+            domain[i] = dVec.elementAt(i);
+            values[i] = vVec.elementAt(i);
         }
         return new FcnRcdValue(domain, values, false);
     }
@@ -232,8 +232,8 @@ public class Bags implements ValueConstants
         Value[] values = new Value[vVec.size()];
         for (int i = 0; i < domain.length; i++)
         {
-            domain[i] = (Value) dVec.elementAt(i);
-            values[i] = (Value) vVec.elementAt(i);
+            domain[i] = dVec.elementAt(i);
+            values[i] = vVec.elementAt(i);
         }
         return new FcnRcdValue(domain, values, fcn1.isNormalized());
     }
diff --git a/tlatools/src/tlc2/module/FiniteSets.java b/tlatools/src/tlc2/module/FiniteSets.java
index 76b45c3fcf98fa10543cc9de31ce12a209eadfb6..2c4d4314093637c35696b2d5d5b0f2421ba3a00e 100644
--- a/tlatools/src/tlc2/module/FiniteSets.java
+++ b/tlatools/src/tlc2/module/FiniteSets.java
@@ -28,7 +28,7 @@ public class FiniteSets implements ValueConstants
     {
         if (val instanceof Enumerable)
         {
-            return IntValue.gen(((Enumerable) val).size());
+            return IntValue.gen(val.size());
         }
         throw new EvalException(EC.TLC_MODULE_COMPUTING_CARDINALITY, Values.ppr(val.toString()));
     }
diff --git a/tlatools/src/tlc2/module/Integers.java b/tlatools/src/tlc2/module/Integers.java
index 25117605d676498b66c352afb911531db0c02928..bb99dc59d5b8b3f8ef7330f315afb6bbc74b2cbf 100644
--- a/tlatools/src/tlc2/module/Integers.java
+++ b/tlatools/src/tlc2/module/Integers.java
@@ -44,7 +44,7 @@ public class Integers extends UserObj implements ValueConstants
         TLARegistry.put("Expt", "^");
     }
 
-    private static Value SetInt = new UserValue(new Integers());
+    private static final Value SetInt = new UserValue(new Integers());
 
     public static Value Int()
     {
@@ -209,6 +209,7 @@ public class Integers extends UserObj implements ValueConstants
         return IntValue.gen((int) res);
     }
 
+    @Override
     public final int compareTo(Value val)
     {
         if (val instanceof UserValue)
@@ -227,6 +228,7 @@ public class Integers extends UserObj implements ValueConstants
         throw new EvalException(EC.TLC_MODULE_COMPARE_VALUE, new String[] { "Int", Values.ppr(val.toString()) });
     }
 
+    @Override
     public final boolean member(Value val)
     {
         if (val instanceof IntValue)
@@ -238,11 +240,13 @@ public class Integers extends UserObj implements ValueConstants
         throw new EvalException(EC.TLC_MODULE_CHECK_MEMBER_OF, new String[] { Values.ppr(val.toString()), "Int" });
     }
 
+    @Override
     public final boolean isFinite()
     {
         return false;
     }
 
+    @Override
     public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow)
     {
         return sb.append("Int");
diff --git a/tlatools/src/tlc2/module/Naturals.java b/tlatools/src/tlc2/module/Naturals.java
index d03f7cb41d781242302111fcdad46417afe82a0c..ac1421b7f0565ed22442012ea9fbf22e590cf144 100644
--- a/tlatools/src/tlc2/module/Naturals.java
+++ b/tlatools/src/tlc2/module/Naturals.java
@@ -219,6 +219,7 @@ public class Naturals extends UserObj implements ValueConstants
         return IntValue.gen((int) res);
     }
 
+    @Override
     public final int compareTo(Value val)
     {
         if (val instanceof UserValue)
@@ -237,6 +238,7 @@ public class Naturals extends UserObj implements ValueConstants
         throw new EvalException(EC.TLC_MODULE_COMPARE_VALUE, new String[] { "Nat", Values.ppr(val.toString()) });
     }
 
+    @Override
     public final boolean member(Value val)
     {
         if (val instanceof IntValue)
@@ -247,11 +249,13 @@ public class Naturals extends UserObj implements ValueConstants
         throw new EvalException(EC.TLC_MODULE_CHECK_MEMBER_OF, new String[] { Values.ppr(val.toString()), "Nat" });
     }
 
+    @Override
     public final boolean isFinite()
     {
         return false;
     }
 
+    @Override
     public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow)
     {
         return sb.append("Nat");
diff --git a/tlatools/src/tlc2/module/Sequences.java b/tlatools/src/tlc2/module/Sequences.java
index 2569b6e05467d6acd4d68a33f902b6607a3d4894..5d4dc6c4c42e0d31c7cfe79052d0b683f7ef4d4a 100644
--- a/tlatools/src/tlc2/module/Sequences.java
+++ b/tlatools/src/tlc2/module/Sequences.java
@@ -73,6 +73,15 @@ public class Sequences extends UserObj implements ValueConstants
 
     public static Value Head(Value s)
     {
+    	// Implementation of Head(string) by MAK on 4 Dec 2019
+    	if (s instanceof StringValue) {
+    		String str = ((StringValue) s).val.toString();
+    		if (str.equals("")) {
+    			throw new EvalException(EC.TLC_MODULE_APPLY_EMPTY_SEQ, "Head");
+    		}
+    		return new StringValue(str.substring(0,1));
+    	}
+    	
         TupleValue seq = (TupleValue) s.toTuple();
         if (seq != null)
         {
@@ -130,6 +139,19 @@ public class Sequences extends UserObj implements ValueConstants
 
     public static Value Append(Value s, Value v)
     {
+    	// Implementation of Append(string, string) by MAK on 4 Dec 2019
+        if (s instanceof StringValue)
+        {
+            if (!(v instanceof StringValue))
+            {
+                throw new EvalException(EC.TLC_MODULE_EVALUATING, new String[] { "t \\o s", "string",
+                        Values.ppr(v.toString()) });
+            }
+            UniqueString u1 = ((StringValue) s).val;
+            UniqueString u2 = ((StringValue) v).val;
+            return new StringValue(u1.concat(u2));
+        }
+        
         TupleValue seq = (TupleValue) s.toTuple();
         if (seq == null)
         {
@@ -365,6 +387,7 @@ public class Sequences extends UserObj implements ValueConstants
         return new TupleValue(elems);
     }
 
+    @Override
     public final int compareTo(Value s)
     {
         if ((s instanceof UserValue) && (((UserValue) s).userObj instanceof Sequences))
@@ -387,6 +410,7 @@ public class Sequences extends UserObj implements ValueConstants
                 Values.ppr(s.toString()) });
     }
 
+    @Override
     public final boolean member(Value s)
     {
         TupleValue seq = (TupleValue) s.toTuple();
@@ -408,11 +432,13 @@ public class Sequences extends UserObj implements ValueConstants
         return true;
     }
 
+    @Override
     public final boolean isFinite()
     {
         return this.size != Integer.MAX_VALUE;
     }
 
+    @Override
     public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow)
     {
         if (this.size == Integer.MAX_VALUE)
diff --git a/tlatools/src/tlc2/module/Strings.java b/tlatools/src/tlc2/module/Strings.java
index befa29a1aca8d1dff3b545a851da7e1b04e14476..2be9f901b8539d66fcb40832c7459a27c8569cfe 100644
--- a/tlatools/src/tlc2/module/Strings.java
+++ b/tlatools/src/tlc2/module/Strings.java
@@ -25,6 +25,7 @@ public class Strings extends UserObj
         return SetString;
     }
 
+    @Override
     public final int compareTo(Value val)
     {
         if ((val instanceof UserValue) && (((UserValue) val).userObj instanceof Strings))
@@ -36,6 +37,7 @@ public class Strings extends UserObj
         throw new EvalException(EC.TLC_MODULE_COMPARE_VALUE, new String[] { "STRING", Values.ppr(val.toString()) });
     }
 
+    @Override
     public final boolean member(Value val)
     {
         if (val instanceof StringValue)
@@ -45,11 +47,13 @@ public class Strings extends UserObj
         throw new EvalException(EC.TLC_MODULE_CHECK_MEMBER_OF, new String[] { Values.ppr(val.toString()), "STRING" });
     }
 
+    @Override
     public final boolean isFinite()
     {
         return false;
     }
 
+    @Override
     public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow)
     {
         return sb.append("STRING");
diff --git a/tlatools/src/tlc2/module/TLC.java b/tlatools/src/tlc2/module/TLC.java
index 45e058f1502af366937a689ab9e01698e5c212fa..1f87e6cea5471800cf97d19c15381dd40dd4dbd7 100644
--- a/tlatools/src/tlc2/module/TLC.java
+++ b/tlatools/src/tlc2/module/TLC.java
@@ -40,6 +40,14 @@ import util.UniqueString;
 
 public class TLC implements ValueConstants
 {
+	private static final UniqueString LEVEL = UniqueString.uniqueStringOf("level");
+	private static final UniqueString DURATION = UniqueString.uniqueStringOf("duration");
+	private static final UniqueString QUEUE = UniqueString.uniqueStringOf("queue");
+	private static final UniqueString DISTINCT = UniqueString.uniqueStringOf("distinct");
+	private static final UniqueString DIAMETER = UniqueString.uniqueStringOf("diameter");
+	private static final UniqueString EXIT = UniqueString.uniqueStringOf("exit");
+	private static final UniqueString PAUSE = UniqueString.uniqueStringOf("pause");
+
 	public static final long serialVersionUID = 20160822L;
 
 	private static final long startTime = System.currentTimeMillis();
@@ -168,7 +176,7 @@ public class TLC implements ValueConstants
 
 	private static final Value TLCGetStringValue(final Value vidx) {
 		final StringValue sv = (StringValue) vidx;
-		if (UniqueString.uniqueStringOf("diameter") == sv.val) {
+		if (DIAMETER == sv.val) {
 			try {
 				return IntValue.gen(TLCGlobals.mainChecker.getProgress());
 			} catch (ArithmeticException e) {
@@ -180,7 +188,7 @@ public class TLC implements ValueConstants
 				// NPE.
 				throw new EvalException(EC.TLC_MODULE_TLCGET_UNDEFINED, String.valueOf(sv.val));
 			}
-		} else if (UniqueString.uniqueStringOf("distinct") == sv.val) {
+		} else if (DISTINCT == sv.val) {
 			try {
 				return IntValue.gen(Math.toIntExact(TLCGlobals.mainChecker.getDistinctStatesGenerated()));
 			} catch (ArithmeticException e) {
@@ -189,7 +197,7 @@ public class TLC implements ValueConstants
 			} catch (NullPointerException npe) {
 				throw new EvalException(EC.TLC_MODULE_TLCGET_UNDEFINED, String.valueOf(sv.val));
 			}
-		} else if (UniqueString.uniqueStringOf("queue") == sv.val) {
+		} else if (QUEUE == sv.val) {
 			try {
 				return IntValue.gen(Math.toIntExact(TLCGlobals.mainChecker.getStateQueueSize()));
 			} catch (ArithmeticException e) {
@@ -198,7 +206,7 @@ public class TLC implements ValueConstants
 			} catch (NullPointerException npe) {
 				throw new EvalException(EC.TLC_MODULE_TLCGET_UNDEFINED, String.valueOf(sv.val));
 			}
-		} else if (UniqueString.uniqueStringOf("duration") == sv.val) {
+		} else if (DURATION == sv.val) {
 			try {
 				final int duration = (int) ((System.currentTimeMillis() - startTime) / 1000L);
 				return IntValue.gen(Math.toIntExact(duration));
@@ -206,7 +214,7 @@ public class TLC implements ValueConstants
 				throw new EvalException(EC.TLC_MODULE_OVERFLOW,
 						Long.toString(((System.currentTimeMillis() - startTime) / 1000L)));
 			}
-		} else if (UniqueString.uniqueStringOf("level") == sv.val) {
+		} else if (LEVEL == sv.val) {
 			// Contrary to "diameter", "level" is not monotonically increasing. "diameter" is
 			// because it calls tlc2.tool.TLCTrace.getLevelForReporting(). "level" is the height
 			// stores as part of the state that is currently explored.
@@ -214,14 +222,15 @@ public class TLC implements ValueConstants
 			if (currentState != null) {
 				return IntValue.gen(currentState.getLevel());
 			} else {
-				if (TLCGlobals.mainChecker == null) {
+				if (TLCGlobals.mainChecker == null && TLCGlobals.simulator == null) {
 					// Be consistent with TLCGet("diameter") when TLCGet("level") appears as
 					// constant substitution.
 					throw new EvalException(EC.TLC_MODULE_TLCGET_UNDEFINED, String.valueOf(sv.val));
 				}
-				// Not an IdThread implies that TLCGet("level") is part of the initial predicate
-				// where the level is 0.
-				return IntValue.gen(0);
+				// Not an IdThread (hence currentState is null) implies that TLCGet("level") is
+				// evaluated as part of the initial predicate where the level - by definition -
+				// is 0 (see TLCState#level).
+				return IntValue.gen(TLCState.INIT_LEVEL - 1);
 			}
 		}
 		throw new EvalException(EC.TLC_MODULE_TLCGET_UNDEFINED, String.valueOf(sv.val));
@@ -249,12 +258,12 @@ public class TLC implements ValueConstants
             }
         } else if (vidx instanceof StringValue) {
         	final StringValue sv = (StringValue) vidx;
-        	if (UniqueString.uniqueStringOf("exit") == sv.val) {
+        	if (EXIT == sv.val) {
         		if (val == BoolValue.ValTrue) {
         			TLCGlobals.mainChecker.stop();
         		}
         		return BoolValue.ValTrue;
-        	} else if (UniqueString.uniqueStringOf("pause") == sv.val) {
+        	} else if (PAUSE == sv.val) {
 				// Provisional TLCSet("pause", TRUE) implementation that suspends BFS model
 				// checking until enter is pressed on system.in.  Either use in spec as:
         		//   TLCSet("pause", guard)
diff --git a/tlatools/src/tlc2/module/TransitiveClosure.java b/tlatools/src/tlc2/module/TransitiveClosure.java
index b04c3f83f51669638582835aafbb21f507b5ca2d..49e53efa03be6c388127e369e5c27dffb8490dac 100644
--- a/tlatools/src/tlc2/module/TransitiveClosure.java
+++ b/tlatools/src/tlc2/module/TransitiveClosure.java
@@ -48,7 +48,7 @@ public class TransitiveClosure implements ValueConstants
             Value elem1 = tv.elems[0];
             Value elem2 = tv.elems[1];
             int num1 = cnt;
-            Integer num = (Integer) fps.get(elem1);
+            Integer num = fps.get(elem1);
             if (num == null)
             {
                 fps.put(elem1, new Integer(cnt));
@@ -59,7 +59,7 @@ public class TransitiveClosure implements ValueConstants
                 num1 = num.intValue();
             }
             int num2 = cnt;
-            num = (Integer) fps.get(elem2);
+            num = fps.get(elem2);
             if (num == null)
             {
                 fps.put(elem2, new Integer(cnt));
@@ -94,8 +94,8 @@ public class TransitiveClosure implements ValueConstants
             {
                 if (matrix[i][j])
                 {
-                	Value elem1 = (Value) elemList.elementAt(i);
-                	Value elem2 = (Value) elemList.elementAt(j);
+                	Value elem1 = elemList.elementAt(i);
+                	Value elem2 = elemList.elementAt(j);
                 	Value newElem = new TupleValue(elem1, elem2);
                     newElems.addElement(newElem);
                 }
diff --git a/tlatools/src/tlc2/output/AbstractCopier.java b/tlatools/src/tlc2/output/AbstractCopier.java
new file mode 100644
index 0000000000000000000000000000000000000000..2289cb54b1dc1c9c6858f86b99442716e7623a16
--- /dev/null
+++ b/tlatools/src/tlc2/output/AbstractCopier.java
@@ -0,0 +1,93 @@
+package tlc2.output;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+
+/**
+ * This is the abstract copying class for the generation of SpecTE file assets.
+ */
+abstract class AbstractCopier {
+	protected final String originalModuleName;
+	protected final String newModuleName;
+
+	protected final File sourceDirectory;
+	
+	protected File sourceFile;
+	protected File destinationFile;
+	
+	AbstractCopier(final String originalName, final String newName, final File sourceLocation) {
+		originalModuleName = originalName;
+		newModuleName = newName;
+		
+		sourceDirectory = sourceLocation;
+	}
+	
+	/**
+	 * @return the extension including the prefixed '.'
+	 */
+	protected abstract String getFileExtension();
+
+	/**
+	 * @param writer
+	 * @param originalLine
+	 * @param lineNumber this is 1-based (e.g the first line of the file read will be lineNumber == 1)
+	 * @throws IOException
+	 */
+	protected abstract void copyLine(final BufferedWriter writer, final String originalLine, final int lineNumber)
+			throws IOException;
+	
+	/**
+	 * Overriders will receive this notification after the final line of input has
+	 * been consumed and {@link #copyLine(BufferedWriter, String, int)} has been
+	 * invoked on that line.
+	 */
+	protected void allInputHasBeenConsumed(final BufferedWriter writer) throws IOException { }
+	
+	/**
+	 * Overriders will receive this notification after the reader and writer
+	 * instances employed in the copy haven been closed but before
+	 * {@link #copy(Reader, Writer)} exits.
+	 */
+	protected void copyHasFinished() throws IOException { }
+
+	/**
+	 * @return null until {@link #copy()} has been invoked, thereafter the location of the destination file.
+	 */
+	public File getDestinationFile() {
+		return destinationFile;
+	}
+	
+	public final void copy() throws IOException {
+		final String extension = getFileExtension();
+		
+		sourceFile = new File(sourceDirectory, (originalModuleName + extension));
+		destinationFile = new File(sourceDirectory, (newModuleName + extension));
+		
+		copy(new FileReader(sourceFile), new FileWriter(destinationFile));
+	}
+	
+	// This extra level of abstraction is done for unit tests
+	protected void copy(final Reader reader, final Writer writer) throws IOException {
+		try (final BufferedReader br = new BufferedReader(reader)) {
+			try (final BufferedWriter bw = new BufferedWriter(writer)) {
+				String line;
+				int lineCount = 1;	// staying 1-based since Location is as well and our subclasses use Location instances
+				while ((line = br.readLine()) != null) {
+					copyLine(bw, line, lineCount);
+
+					lineCount++;
+				}
+				
+				allInputHasBeenConsumed(bw);
+			}
+		}
+		
+		copyHasFinished();
+	}
+}
diff --git a/tlatools/src/tlc2/output/AbstractSpecWriter.java b/tlatools/src/tlc2/output/AbstractSpecWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..bb6e81936a8fe2470934743f536ddcb55b3d24af
--- /dev/null
+++ b/tlatools/src/tlc2/output/AbstractSpecWriter.java
@@ -0,0 +1,499 @@
+package tlc2.output;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.CopyOption;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+
+import tlc2.model.Assignment;
+import tlc2.model.TypedSet;
+import util.TLAConstants;
+
+/**
+ * This is the abstract class of spec writers; there's no reason this need be abstract, it is more a semantic
+ * 	denoting that within our code base, it acts as only a superclass to other employed classes.
+ */
+public abstract class AbstractSpecWriter {
+    /**
+     * Assigns a right side to a label using an id generated from given schema
+	 * @param tlaBuffer the buffer into which the TLA code will be placed
+	 * @param cfgBuffer if non-null, the buffer into which the CFG code will be placed
+     * @param constant, constant containing the values
+     * @param schema schema to generate the Id
+     * @return generated id
+     */
+	public static String addArrowAssignmentToBuffers(final StringBuilder tlaBuffer, final StringBuilder cfgBuffer,
+			final Assignment constant, final String schema) {
+		// constant instantiation
+		// to .cfg : foo <- <id>
+		// to _MC.tla : <id>(a, b, c)==
+		// <expression>
+		final String id = SpecWriterUtilities.getValidIdentifier(schema);
+		tlaBuffer.append(constant.getParametrizedLabel(id)).append(TLAConstants.DEFINES).append(TLAConstants.CR);
+		tlaBuffer.append(constant.getRight()).append(TLAConstants.CR);
+		
+		if (cfgBuffer != null) {
+			cfgBuffer.append(TLAConstants.KeyWords.CONSTANT).append(TLAConstants.CR);
+			cfgBuffer.append(constant.getLabel()).append(TLAConstants.ARROW).append(id).append(TLAConstants.CR);
+		}
+		
+		return id;
+	}
+
+	
+	/**
+	 * Subclasses may implement this interface in order to invoke {@link #writeFiles(ContentWriter)} for cases
+	 * in which the subclass is has file handles which are not suitable to being converted and used in
+	 * {@link #writeStreamToFile(InputStream, boolean)}
+	 */
+    protected interface ContentWriter {
+    	void writeStreamToFile(final InputStream inputStream, final boolean forTLAFile) throws IOException;
+    }
+    
+
+    protected static final String CLOSING_SEP = TLAConstants.CR + TLAConstants.SEP + TLAConstants.CR;
+	
+	
+    protected final StringBuilder tlaBuffer;
+    protected final StringBuilder cfgBuffer;
+    
+    /**
+	 * @param generateConfigurationContent if true, configuration file (.cfg)
+	 *                                     accompanying the TLA module content will
+	 *                                     be generated
+	 */
+    protected AbstractSpecWriter(final boolean generateConfigurationContent) {
+    	tlaBuffer = new StringBuilder();
+    	cfgBuffer = generateConfigurationContent ? new StringBuilder() : null;
+    }
+
+    /**
+     * Subclasses may override this to set their own spin on a closing tag.
+     * 
+     * @return the String content of a module closing tag.
+     */
+    protected String getTLAModuleClosingTag() {
+    	final StringBuilder sb = SpecWriterUtilities.getModuleClosingTag(77, false);
+    	
+    	return sb.toString();
+    }
+    
+    /**
+     * Provided for test code
+     * @param tla if non-null the content will be appended to the tlaBuffer
+     * @param cfg if non-null the content will be appended to the cfgBuffer
+     */
+    void appendContentToBuffers(final String tla, final String cfg) {
+    	if (tla != null) {
+    		tlaBuffer.append(tla);
+    	}
+    	
+    	if (cfg != null) {
+    		cfgBuffer.append(cfg);
+    	}
+    }
+    
+    /**
+     * Write the buffers to files.
+     * 
+     * @param tlaFile if null, nothing is written
+     * @param cfgFile if null, nothing is written
+     * @throws IOException
+     */
+	public void writeFiles(final File tlaFile, final File cfgFile) throws IOException {
+		final ContentWriter cw = (inputStream, forTLAFile) -> {
+			final File f = (forTLAFile ? tlaFile: cfgFile);
+			
+			if (f != null) {
+		        Files.copy(inputStream, f.toPath(), StandardCopyOption.REPLACE_EXISTING);
+			}
+		};
+		
+		writeFiles(cw);
+	}
+	
+	/**
+	 * Subclasses may use to this to provide a content writer which deals with output other than using {@code java.io}
+	 * directly.
+	 * 
+	 * @param contentWriter
+	 * @throws IOException
+	 */
+	protected void writeFiles(final ContentWriter contentWriter) throws IOException {
+        tlaBuffer.append(getTLAModuleClosingTag());
+        final ByteArrayInputStream tlaBAIS = new ByteArrayInputStream(tlaBuffer.toString().getBytes());
+        contentWriter.writeStreamToFile(tlaBAIS, true);
+        
+		if (cfgBuffer != null) {
+			cfgBuffer.append(SpecWriterUtilities.getGeneratedTimeStampCommentLine());
+	        final ByteArrayInputStream configurationBAIS = new ByteArrayInputStream(cfgBuffer.toString().getBytes());
+	        contentWriter.writeStreamToFile(configurationBAIS, false);
+		}
+	}
+
+	/**
+	 * Add file header, which consists of the module-beginning ----- MODULE ... ----
+	 * line and the EXTENDS statement.
+	 * 
+	 * @param moduleFilename
+	 * @param extendedModuleName
+	 */
+	public void addPrimer(final String moduleFilename, final String extendedModuleName) {
+		tlaBuffer.append(SpecWriterUtilities.getExtendingModuleContent(moduleFilename,
+																	   new String[] { extendedModuleName, "TLC" }));
+	}
+
+	/**
+	 * Add spec definition
+	 * 
+	 * @param specDefinition
+	 * @param attributeName
+	 */
+	public void addSpecDefinition(final String[] specDefinition, final String attributeName) {
+		if (cfgBuffer != null) {
+			cfgBuffer.append(TLAConstants.KeyWords.SPECIFICATION).append(TLAConstants.SPACE);
+			cfgBuffer.append(specDefinition[0]).append(TLAConstants.CR);
+		}
+		
+		tlaBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.SPECIFICATION).append(TLAConstants.SPACE);
+		tlaBuffer.append(TLAConstants.ATTRIBUTE).append(attributeName).append(TLAConstants.CR);
+		tlaBuffer.append(specDefinition[1]).append(CLOSING_SEP);
+	}
+	
+	/**
+	 * Add an init-next pair of definitions.
+	 * 
+	 * @param initDefinition the 0th element is the init definition name, the 1rst is the entire definition
+	 * @param nextDefinition the 0th element is the next definition name, the 1rst is the entire definition
+	 * @param initAttributeName
+	 * @param nextAttributeName
+	 */
+	public void addInitNextDefinitions(final String[] initDefinition, final String[] nextDefinition,
+									   final String initAttributeName, final String nextAttributeName) {
+		if (cfgBuffer != null) {
+			cfgBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.INIT).append(" definition");
+			cfgBuffer.append(TLAConstants.CR).append(TLAConstants.KeyWords.INIT).append(TLAConstants.CR);
+			cfgBuffer.append(initDefinition[0]).append(TLAConstants.CR);
+		}
+
+		tlaBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.INIT).append(" definition ");
+		tlaBuffer.append(TLAConstants.ATTRIBUTE).append(initAttributeName).append(TLAConstants.CR);
+		tlaBuffer.append(initDefinition[1]).append(TLAConstants.CR);
+
+		
+		if (cfgBuffer != null) {
+			cfgBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.NEXT).append(" definition");
+			cfgBuffer.append(TLAConstants.CR).append(TLAConstants.KeyWords.NEXT).append(TLAConstants.CR);
+			cfgBuffer.append(nextDefinition[0]).append(TLAConstants.CR);
+		}
+
+		tlaBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.NEXT).append(" definition ");
+		tlaBuffer.append(TLAConstants.ATTRIBUTE).append(nextAttributeName).append(TLAConstants.CR);
+		tlaBuffer.append(nextDefinition[1]).append(TLAConstants.CR);
+	}
+
+    /**
+     * Documentation by SZ: Add constants declarations. 
+     * 
+     * On 17 March 2012, LL split the original addConstants method
+     * into the current one plus the addConstantsBis method.  As explained in Bugzilla Bug 280,
+     * this was to allow the user definitions added on the Advanced Model page to appear between
+     * the CONSTANT declarations for model values and the definitions of the expressions that 
+     * instantiate CONSTANT parameters.  (This allows symbols defined in those user definitions to
+     * appear in the expressions instantiated for CONSTANT parameters.)
+     * 
+     * See the use of these two methods in TLCModelLaunchDelegate.buildForLaunch for a description
+     * of what these methods do.
+     * 
+     * @param constants
+     * @param modelValues
+     * @param attributeConstants
+     * @param attributeMVs
+     */
+	public void addConstants(final List<Assignment> constants, final TypedSet modelValues, final String attributeConstants,
+			final String attributeMVs) {
+        // add declarations for model values introduced on Advanced Model page.
+        addMVTypedSet(modelValues, "MV CONSTANT declarations ", attributeMVs);
+
+        final ArrayList<String> symmetrySets = new ArrayList<>();
+
+        Assignment constant;
+        // first run for all the declarations
+		for (int i = 0; i < constants.size(); i++) {
+			constant = constants.get(i);
+			if (constant.isModelValue()) {
+				if (constant.isSetOfModelValues()) {
+					// set model values
+					addMVTypedSet(constant.getSetOfModelValues(), "MV CONSTANT declarations", attributeConstants);
+				}
+			}
+		}
+
+        // now all the definitions
+		for (int i = 0; i < constants.size(); i++) {
+			constant = constants.get(i);
+			if (constant.isModelValue()) {
+				if (constant.isSetOfModelValues()) {
+                    // set model values
+					if (cfgBuffer != null) {
+						cfgBuffer.append(TLAConstants.COMMENT).append("MV CONSTANT definitions").append(TLAConstants.CR);
+					}
+                    tlaBuffer.append(TLAConstants.COMMENT).append("MV CONSTANT definitions " + constant.getLeft());
+                    tlaBuffer.append(TLAConstants.CR);
+
+                    final String id = addArrowAssignment(constant, TLAConstants.Schemes.CONSTANT_SCHEME);
+					if (constant.isSymmetricalSet()) {
+						symmetrySets.add(id);
+					}
+                    tlaBuffer.append(TLAConstants.SEP).append(TLAConstants.CR).append(TLAConstants.CR);
+				} else if (cfgBuffer != null) {
+					cfgBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.CONSTANT)
+							 .append(" declarations").append(TLAConstants.CR);
+					// model value assignment
+					// to .cfg : foo = foo
+					// to _MC.tla : <nothing>, since the constant is already defined in one of the
+					// spec modules
+					cfgBuffer.append(TLAConstants.KeyWords.CONSTANT).append(TLAConstants.SPACE).append(constant.getLabel());
+					cfgBuffer.append(TLAConstants.EQ).append(constant.getRight()).append(TLAConstants.CR);
+				}
+			} else {
+//                // simple constant value assignment
+//                cfgBuffer.append(COMMENT).append("CONSTANT definitions").append(CR);
+//
+//                tlaBuffer.append(COMMENT).append("CONSTANT definitions ").append(ATTRIBUTE).append(attributeConstants)
+//                        .append(INDEX).append(i).append(constant.getLeft()).append(CR);
+//                addArrowAssignment(constant, CONSTANT_SCHEME);
+//                tlaBuffer.append(SEP).append(CR).append(CR);
+            }
+        }
+
+        // symmetry
+		if (!symmetrySets.isEmpty()) {
+			final String label = SpecWriterUtilities.getValidIdentifier(TLAConstants.Schemes.SYMMETRY_SCHEME);
+
+			tlaBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.SYMMETRY)
+					 .append(" definition").append(TLAConstants.CR);
+			if (cfgBuffer != null) {
+				cfgBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.SYMMETRY)
+						 .append(" definition").append(TLAConstants.CR);
+			}
+
+			tlaBuffer.append(label).append(TLAConstants.DEFINES).append(TLAConstants.CR);
+			// symmetric model value sets added
+			for (int i = 0; i < symmetrySets.size(); i++) {
+				tlaBuffer.append(TLAConstants.BuiltInOperators.PERMUTATIONS).append("(");
+				tlaBuffer.append(symmetrySets.get(i)).append(")");
+				if (i != symmetrySets.size() - 1) {
+					tlaBuffer.append(' ').append(TLAConstants.KeyWords.UNION).append(' ');
+				}
+			}
+
+			tlaBuffer.append(CLOSING_SEP).append(TLAConstants.CR);
+			if (cfgBuffer != null) {
+				cfgBuffer.append(TLAConstants.KeyWords.SYMMETRY).append(TLAConstants.SPACE)
+						 .append(label).append(TLAConstants.CR);
+			}
+		}
+    }
+
+	public void addConstantsBis(final List<Assignment> constants, final String attributeConstants) {
+		for (int i = 0; i < constants.size(); i++) {
+			final Assignment constant = constants.get(i);
+			if (! constant.isModelValue()) {
+				if (cfgBuffer != null) {
+					// simple constant value assignment
+					cfgBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.CONSTANT).append(" definitions");
+					cfgBuffer.append(TLAConstants.CR);
+				}
+
+                tlaBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.CONSTANT).append(" definitions ");
+                tlaBuffer.append(TLAConstants.ATTRIBUTE).append(attributeConstants).append(TLAConstants.COLON);
+                tlaBuffer.append(i).append(constant.getLeft()).append(TLAConstants.CR);
+                
+                addArrowAssignment(constant, TLAConstants.Schemes.CONSTANT_SCHEME);
+                
+                tlaBuffer.append(TLAConstants.SEP).append(TLAConstants.CR).append(TLAConstants.CR);
+            }
+        }
+    }
+
+    /**
+     * Adds the ASSUME PrintT statement and identifier for the constant expression
+     * evaluation. The MC.tla file will contain:
+     * 
+     * const_expr_1232141234123 ==
+     * expression
+     * -----
+     * ASSUME PrintT(<<"$!@$!@$!@$!@$!", const_expr_1232141234123>>)
+     * 
+     * See the comments in the method for an explanation of defining
+     * an identifier.
+     * 
+     * @param expression
+     * @param attributeName
+     */
+	public void addConstantExpressionEvaluation(final String expression, final String attributeName) {
+		if (expression.trim().length() != 0) {
+			/*
+			 * Identifier definition We define an identifier for more sensible error
+			 * messages For example, if the user enters "1+" into the constant expression
+			 * field and "1+" is placed as the second element of the tuple that is the
+			 * argument for PrintT(), then the parse error would be something like
+			 * "Encountered >>" which would be mysterious to the user. With an identifier
+			 * defined, the message says "Encountered ----" which is the separator after
+			 * each section in TLA buffer. This error message is equally mysterious, but at
+			 * least it is the same message that would appear were the same error present in
+			 * another section in the model editor. We can potentially replace such messages
+			 * with something more sensible in the future in the appendError() method in
+			 * TLCErrorView.
+			 */
+			final String id = SpecWriterUtilities.getValidIdentifier(TLAConstants.Schemes.CONSTANTEXPR_SCHEME);
+			tlaBuffer.append(TLAConstants.COMMENT).append("Constant expression definition ");
+			tlaBuffer.append(TLAConstants.ATTRIBUTE).append(attributeName).append(TLAConstants.CR);
+			tlaBuffer.append(id).append(TLAConstants.DEFINES).append(TLAConstants.CR).append(expression);
+			tlaBuffer.append(CLOSING_SEP).append(TLAConstants.CR);
+
+			// ASSUME PrintT(<<"$!@$!@$!@$!@$!", const_expr_23423232>>) statement
+			// The "$!@$!@$!@$!@$!" allows the toolbox to identify the
+			// value of the constant expression in the TLC output
+			tlaBuffer.append(TLAConstants.COMMENT).append("Constant expression ASSUME statement ");
+			tlaBuffer.append(TLAConstants.ATTRIBUTE).append(attributeName).append(TLAConstants.CR);
+			tlaBuffer.append("ASSUME PrintT(").append(TLAConstants.BEGIN_TUPLE);
+			tlaBuffer.append(TLAConstants.CONSTANT_EXPRESSION_EVAL_IDENTIFIER).append(TLAConstants.COMMA).append(id);
+			tlaBuffer.append(TLAConstants.END_TUPLE).append(")").append(CLOSING_SEP).append(TLAConstants.CR);
+		}
+	}
+
+    /**
+     * New definitions are added to the TLA buffer only
+     * @param defnitions
+     * @param attributeName
+     */
+	public void addNewDefinitions(final String definitions, final String attributeName) {
+		if (definitions.trim().length() == 0) {
+			return;
+		}
+		tlaBuffer.append(TLAConstants.COMMENT).append("New definitions ");
+		tlaBuffer.append(TLAConstants.ATTRIBUTE).append(attributeName).append(TLAConstants.CR);
+		tlaBuffer.append(definitions).append(CLOSING_SEP);
+	}
+
+	/**
+	 * Convenience method to call {@link #addFormulaList(List, String, String)} wrapping the {@code element} parameter.
+	 * 
+	 * @param element
+	 * @param keyword
+	 * @param attributeName
+	 */
+    public void addFormulaList(final String element, final String keyword, final String attributeName) {
+    	final List<String[]> elements = new ArrayList<>(1);
+    	elements.add(new String[] {element, TLAConstants.EMPTY_STRING});
+    	addFormulaList(elements, keyword, attributeName);
+    }
+    
+    /**
+	 * Puts (String[])element[0] to configuration buffer; if this instance was
+	 * appropriately constructed, and element[1] to the TLA buffer; if element[2]
+	 * present, uses it as index.
+	 * 
+	 * @param elements      a list of String[] elements
+	 * @param keyword       the keyword to be used in the CFG buffer
+	 * @param attributeName the name of the attribute in the TLA buffer
+	 */
+	public void addFormulaList(final List<String[]> elements, final String keyword, final String attributeName) {
+		if (elements.isEmpty()) {
+			return;
+		}
+		
+		if (cfgBuffer != null) {
+			cfgBuffer.append(TLAConstants.COMMENT).append(keyword + " definition").append(TLAConstants.CR);
+			cfgBuffer.append(keyword).append(TLAConstants.CR);
+		}
+
+		for (int i = 0; i < elements.size(); i++) {
+			final String[] element = elements.get(i);
+			
+			if (cfgBuffer != null) {
+				cfgBuffer.append(element[0]).append(TLAConstants.CR);
+			}
+			
+			// when a definition in the root module is overridden as a model value
+			// there is nothing to add to the MC.tla file so, we do not do the following
+			if (!element[1].equals(TLAConstants.EMPTY_STRING)) {
+				tlaBuffer.append(TLAConstants.COMMENT).append(keyword + " definition ").append(TLAConstants.ATTRIBUTE);
+				tlaBuffer.append(attributeName).append(TLAConstants.COLON).append(element.length > 2 ? element[2] : i);
+				tlaBuffer.append(TLAConstants.CR).append(element[1]).append(CLOSING_SEP);
+			}
+		}
+	}
+
+    /**
+     * Add the view definition
+     * @param viewString the string that the user enters into the view field
+     * @param attributeName the attribute name of the view field
+     */
+	public void addView(final String viewString, final String attributeName) {
+		if (viewString.trim().length() != 0) {
+			final String id = SpecWriterUtilities.getValidIdentifier(TLAConstants.Schemes.VIEW_SCHEME);
+			
+			if (cfgBuffer != null) {
+				cfgBuffer.append(TLAConstants.COMMENT).append("VIEW definition").append(TLAConstants.CR);
+				cfgBuffer.append("VIEW").append(TLAConstants.CR).append(id).append(TLAConstants.CR);
+			}
+
+			tlaBuffer.append(TLAConstants.COMMENT).append("VIEW definition ").append(TLAConstants.ATTRIBUTE);
+			tlaBuffer.append(attributeName).append(TLAConstants.CR);
+			tlaBuffer.append(id).append(TLAConstants.DEFINES).append(TLAConstants.CR).append(viewString);
+			tlaBuffer.append(CLOSING_SEP).append(TLAConstants.CR);
+		}
+	}
+	
+    /**
+     * Assigns a right side to a label using an id generated from given schema
+     * @param constant, constant containing the values
+     * @param schema schema to generate the Id
+     * @return generated id
+     */
+	public String addArrowAssignment(final Assignment constant, final String schema) {
+		return addArrowAssignmentToBuffers(tlaBuffer, cfgBuffer, constant, schema);
+	}
+
+    /**
+     * Creates a serial version of an MV set in both files
+     * @param mvSet typed set containing the model values
+     * @param comment a comment to put before the declarations, null and empty strings are OK
+     */
+	public void addMVTypedSet(final TypedSet mvSet, final String comment, final String attributeName) {
+		if (mvSet.getValueCount() != 0) {
+            // create a declaration line
+            // CONSTANTS
+            // a, b, c
+			if ((comment != null) && (comment.length() != 0)) {
+                tlaBuffer.append(TLAConstants.COMMENT).append(comment).append(TLAConstants.ATTRIBUTE);
+                tlaBuffer.append(attributeName).append(TLAConstants.CR);
+            }
+            tlaBuffer.append(TLAConstants.KeyWords.CONSTANTS).append(TLAConstants.CR).append(mvSet.toStringWithoutBraces());
+            tlaBuffer.append(CLOSING_SEP).append(TLAConstants.CR);
+
+			if (cfgBuffer != null) {
+				// create MV assignments
+				// a = a
+				// b = b
+				// c = c
+				if ((comment != null) && (comment.length() != 0)) {
+					cfgBuffer.append(TLAConstants.COMMENT).append(comment).append(TLAConstants.CR);
+				}
+				cfgBuffer.append(TLAConstants.KeyWords.CONSTANTS).append(TLAConstants.CR);
+				for (int i = 0; i < mvSet.getValueCount(); i++) {
+					final String mv = mvSet.getValue(i);
+					cfgBuffer.append(mv).append(TLAConstants.EQ).append(mv).append(TLAConstants.CR);
+				}
+			}
+        }
+    }
+}
diff --git a/tlatools/src/tlc2/output/AbstractTLACopier.java b/tlatools/src/tlc2/output/AbstractTLACopier.java
new file mode 100644
index 0000000000000000000000000000000000000000..38c3a918fb7b896443584fa695032f209f089a59
--- /dev/null
+++ b/tlatools/src/tlc2/output/AbstractTLACopier.java
@@ -0,0 +1,35 @@
+package tlc2.output;
+
+import java.io.File;
+import java.util.regex.Pattern;
+
+import util.TLAConstants;
+
+/**
+ * The abstract superclass for classes which copy a TLA file.
+ */
+abstract class AbstractTLACopier extends AbstractCopier {
+	protected static final Pattern CLOSING_BODY_PATTERN = Pattern.compile(TLAConstants.MODULE_CLOSING_REGEX);
+	
+
+	protected final Pattern modulePattern;
+	
+	protected boolean inBody;
+	
+	AbstractTLACopier(final String originalName, final String newName, final File sourceLocation) {
+		super(originalName, newName, sourceLocation);
+
+		final String regex = TLAConstants.MODULE_OPENING_PREFIX_REGEX + originalModuleName;
+		modulePattern = Pattern.compile(regex);
+		
+		inBody = false;
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected String getFileExtension() {
+		return TLAConstants.Files.TLA_EXTENSION;
+	}
+}
diff --git a/tlatools/src/tlc2/output/CFGCopier.java b/tlatools/src/tlc2/output/CFGCopier.java
new file mode 100644
index 0000000000000000000000000000000000000000..89f80c77dedbff5b22d8cd65a3e16df5eda3eb35
--- /dev/null
+++ b/tlatools/src/tlc2/output/CFGCopier.java
@@ -0,0 +1,100 @@
+package tlc2.output;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import util.TLAConstants;
+
+/**
+ * This class which copies a CFG file, mutating it appropriately to become a SpecTE CFG file.  This is becoming
+ * 	pretty brittle; we would probably be better served at this point to work on the {@link ModelConfig} class
+ *  and make it able to write itself to a stream (and from that point forward, just modify an instance of that
+ *  directly.) (TODO)
+ */
+public class CFGCopier extends AbstractCopier {
+	private static final String SPECIFICATION_COMMENT_REGEX = "^\\\\\\* " + TLAConstants.KeyWords.SPECIFICATION + ".*$?";
+	private static final Pattern SPECIFICATION_COMMENT_PATTERN = Pattern.compile(SPECIFICATION_COMMENT_REGEX);
+	private static final String INIT_COMMENT_REGEX = "^\\\\\\* " + TLAConstants.KeyWords.INIT + ".*$?";
+	private static final Pattern INIT_COMMENT_PATTERN = Pattern.compile(INIT_COMMENT_REGEX);
+	private static final String NEXT_COMMENT_REGEX = "^\\\\\\* " + TLAConstants.KeyWords.NEXT + ".*$?";
+	private static final Pattern NEXT_COMMENT_PATTERN = Pattern.compile(NEXT_COMMENT_REGEX);
+
+	
+	private boolean skipNextLine;
+	
+	private final String initNextConfiguration;
+	
+	public CFGCopier(final String originalName, final String newName, final File sourceLocation, final String initNextCFG) {
+		super(originalName, newName, sourceLocation);
+
+		skipNextLine = false;
+		
+		initNextConfiguration = initNextCFG;
+	}
+	
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected String getFileExtension() {
+		return TLAConstants.Files.CONFIG_EXTENSION;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected void copyLine(final BufferedWriter writer, final String originalLine, final int lineNumber)
+			throws IOException {
+		if (skipNextLine) {
+			skipNextLine = false;
+			return;
+		}
+		
+		final Matcher comment = SPECIFICATION_COMMENT_PATTERN.matcher(originalLine);
+		if (!comment.matches()) {
+			final Matcher init = INIT_COMMENT_PATTERN.matcher(originalLine);
+			
+			if (!init.matches()) {
+				final Matcher next = NEXT_COMMENT_PATTERN.matcher(originalLine);
+				
+				if (!next.matches()) {
+					final String trimmed = originalLine.trim();
+
+					if (TLAConstants.KeyWords.SPECIFICATION.equals(trimmed)
+							|| TLAConstants.KeyWords.INIT.equals(trimmed)
+							|| TLAConstants.KeyWords.NEXT.equals(trimmed)) {
+						skipNextLine = true;
+					} else if (trimmed.startsWith(TLAConstants.KeyWords.SPECIFICATION)
+								|| trimmed.startsWith(TLAConstants.KeyWords.INIT)
+								|| trimmed.startsWith(TLAConstants.KeyWords.NEXT)) {
+						// NO-OP - don't write since it starts with the keyword, but trimmed doesn't match
+						//	the naming of the keyword-denoted-attribute is on this same line, e.g:
+						//			SPECIFICATION MySpec
+					} else if (!trimmed.startsWith(TLAConstants.GENERATION_TIMESTAMP_PREFIX)) {
+						writer.write(originalLine + '\n');
+					}
+				}
+			}
+		}
+	}
+	
+	@Override
+	protected void allInputHasBeenConsumed(final BufferedWriter writer) throws IOException {
+		writer.write(initNextConfiguration + '\n');
+		writer.write(SpecWriterUtilities.getGeneratedTimeStampCommentLine().toString() + '\n');
+	}
+	
+	
+	public static void main(final String[] args) throws Exception {
+		final String initNext = "INIT\ninit_abc_ldq\n\nNEXT\nnext_abc_ldq";
+		final CFGCopier copier = new CFGCopier(TLAConstants.Files.MODEL_CHECK_FILE_BASENAME,
+											   TLAConstants.TraceExplore.ERROR_STATES_MODULE_NAME,
+											   new File(args[0]),
+											   initNext);
+		copier.copy();
+	}
+}
diff --git a/tlatools/src/tlc2/output/EC.java b/tlatools/src/tlc2/output/EC.java
index fee1868abb3ccd5671c39d42c5c413c9041d4584..48203f947eb0b674ff3c768382525bffb4140380 100644
--- a/tlatools/src/tlc2/output/EC.java
+++ b/tlatools/src/tlc2/output/EC.java
@@ -48,10 +48,12 @@ public interface EC
 	 */
 	public static final int TLC_FEATURE_UNSUPPORTED = 2156;
 	public static final int TLC_FEATURE_UNSUPPORTED_LIVENESS_SYMMETRY = 2279;
+	public static final int TLC_FEATURE_LIVENESS_CONSTRAINTS = 2284;
 
     public static final int GENERAL = 1000;
     public static final int SYSTEM_OUT_OF_MEMORY = 1001;
     public static final int SYSTEM_OUT_OF_MEMORY_TOO_MANY_INIT = 1002;
+    public static final int SYSTEM_OUT_OF_MEMORY_LIVENESS = 1003;
     public static final int SYSTEM_STACK_OVERFLOW = 1005;
 
     public static final int WRONG_COMMANDLINE_PARAMS_SIMULATOR = 1101;
@@ -117,6 +119,10 @@ public interface EC
 	public static final int TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE = 2154;
     public static final int TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_LOADED = 2168;
     public static final int TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_MISMATCH = 2400;
+    public static final int TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_MODULE_MISMATCH = 2402;
+    public static final int TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_IDENTIFIER_MISMATCH = 2403;
+    // User-provided module overrides print to stdout.
+    public static final int TLC_MODULE_OVERRIDE_STDOUT = 20000;
 
     public static final int TLC_FP_NOT_IN_SET = 2133;
     public static final int TLC_FP_VALUE_ALREADY_ON_DISK = 2166;
@@ -160,6 +166,9 @@ public interface EC
     public static final int TLC_MODULE_ARGUMENT_NOT_IN_DOMAIN = 2183;
     public static final int TLC_MODULE_APPLY_EMPTY_SEQ = 2184;
     
+    public static final int TLC_SYMMETRY_SET_TOO_SMALL = 2300;
+    public static final int TLC_SPECIFICATION_FEATURES_TEMPORAL_QUANTIFIER = 2301;
+    
     public static final int TLC_STARTING = 2185;
     public static final int TLC_FINISHED = 2186;
     
@@ -276,7 +285,6 @@ public interface EC
     public static final int TLC_ENABLED_WRONG_FORMULA = 2260;
     public static final int TLC_ENCOUNTERED_FORMULA_IN_PREDICATE = 2261;
     public static final int TLC_VERSION = 2262;
-    public static final int TLC_USAGE = 2263;
     public static final int TLC_COUNTER_EXAMPLE = 2264;
     
     public static final int TLC_INTEGER_TOO_BIG = 2265;
diff --git a/tlatools/src/tlc2/output/MP.java b/tlatools/src/tlc2/output/MP.java
index 3bdc6f94c7a5f0759161f9a8ec7fc168b7edb347..38be2f879cd116781c5b6610c6109ad53e32626d 100644
--- a/tlatools/src/tlc2/output/MP.java
+++ b/tlatools/src/tlc2/output/MP.java
@@ -13,10 +13,12 @@ import tlc2.tool.TLCStateInfo;
 import tlc2.tool.liveness.LiveWorker;
 import tlc2.util.statistics.IBucketStatistics;
 import util.Assert;
+import util.Assert.TLCRuntimeException;
 import util.DebugPrinter;
 import util.Set;
+import util.TLAConstants;
+import util.TLAFlightRecorder;
 import util.ToolIO;
-import util.Assert.TLCRuntimeException;
 
 /**
  * This class is used in the following way to support the replacements of the
@@ -78,6 +80,82 @@ import util.Assert.TLCRuntimeException;
  */
 public class MP
 {
+	// https://stackoverflow.com/a/45444716/6291195
+	public static class Colors {
+		// Reset
+		public static final String RESET = "\033[0m"; // Text Reset
+
+		// Regular Colors
+		public static final String BLACK = "\033[0;30m"; // BLACK
+		public static final String RED = "\033[0;31m"; // RED
+		public static final String GREEN = "\033[0;32m"; // GREEN
+		public static final String YELLOW = "\033[0;33m"; // YELLOW
+		public static final String BLUE = "\033[0;34m"; // BLUE
+		public static final String PURPLE = "\033[0;35m"; // PURPLE
+		public static final String CYAN = "\033[0;36m"; // CYAN
+		public static final String WHITE = "\033[0;37m"; // WHITE
+
+		// Bold
+		public static final String BLACK_BOLD = "\033[1;30m"; // BLACK
+		public static final String RED_BOLD = "\033[1;31m"; // RED
+		public static final String GREEN_BOLD = "\033[1;32m"; // GREEN
+		public static final String YELLOW_BOLD = "\033[1;33m"; // YELLOW
+		public static final String BLUE_BOLD = "\033[1;34m"; // BLUE
+		public static final String PURPLE_BOLD = "\033[1;35m"; // PURPLE
+		public static final String CYAN_BOLD = "\033[1;36m"; // CYAN
+		public static final String WHITE_BOLD = "\033[1;37m"; // WHITE
+
+		// Underline
+		public static final String BLACK_UNDERLINED = "\033[4;30m"; // BLACK
+		public static final String RED_UNDERLINED = "\033[4;31m"; // RED
+		public static final String GREEN_UNDERLINED = "\033[4;32m"; // GREEN
+		public static final String YELLOW_UNDERLINED = "\033[4;33m"; // YELLOW
+		public static final String BLUE_UNDERLINED = "\033[4;34m"; // BLUE
+		public static final String PURPLE_UNDERLINED = "\033[4;35m"; // PURPLE
+		public static final String CYAN_UNDERLINED = "\033[4;36m"; // CYAN
+		public static final String WHITE_UNDERLINED = "\033[4;37m"; // WHITE
+
+		// Background
+		public static final String BLACK_BACKGROUND = "\033[40m"; // BLACK
+		public static final String RED_BACKGROUND = "\033[41m"; // RED
+		public static final String GREEN_BACKGROUND = "\033[42m"; // GREEN
+		public static final String YELLOW_BACKGROUND = "\033[43m"; // YELLOW
+		public static final String BLUE_BACKGROUND = "\033[44m"; // BLUE
+		public static final String PURPLE_BACKGROUND = "\033[45m"; // PURPLE
+		public static final String CYAN_BACKGROUND = "\033[46m"; // CYAN
+		public static final String WHITE_BACKGROUND = "\033[47m"; // WHITE
+
+		// High Intensity
+		public static final String BLACK_BRIGHT = "\033[0;90m"; // BLACK
+		public static final String RED_BRIGHT = "\033[0;91m"; // RED
+		public static final String GREEN_BRIGHT = "\033[0;92m"; // GREEN
+		public static final String YELLOW_BRIGHT = "\033[0;93m"; // YELLOW
+		public static final String BLUE_BRIGHT = "\033[0;94m"; // BLUE
+		public static final String PURPLE_BRIGHT = "\033[0;95m"; // PURPLE
+		public static final String CYAN_BRIGHT = "\033[0;96m"; // CYAN
+		public static final String WHITE_BRIGHT = "\033[0;97m"; // WHITE
+
+		// Bold High Intensity
+		public static final String BLACK_BOLD_BRIGHT = "\033[1;90m"; // BLACK
+		public static final String RED_BOLD_BRIGHT = "\033[1;91m"; // RED
+		public static final String GREEN_BOLD_BRIGHT = "\033[1;92m"; // GREEN
+		public static final String YELLOW_BOLD_BRIGHT = "\033[1;93m";// YELLOW
+		public static final String BLUE_BOLD_BRIGHT = "\033[1;94m"; // BLUE
+		public static final String PURPLE_BOLD_BRIGHT = "\033[1;95m";// PURPLE
+		public static final String CYAN_BOLD_BRIGHT = "\033[1;96m"; // CYAN
+		public static final String WHITE_BOLD_BRIGHT = "\033[1;97m"; // WHITE
+
+		// High Intensity backgrounds
+		public static final String BLACK_BACKGROUND_BRIGHT = "\033[0;100m";// BLACK
+		public static final String RED_BACKGROUND_BRIGHT = "\033[0;101m";// RED
+		public static final String GREEN_BACKGROUND_BRIGHT = "\033[0;102m";// GREEN
+		public static final String YELLOW_BACKGROUND_BRIGHT = "\033[0;103m";// YELLOW
+		public static final String BLUE_BACKGROUND_BRIGHT = "\033[0;104m";// BLUE
+		public static final String PURPLE_BACKGROUND_BRIGHT = "\033[0;105m"; // PURPLE
+		public static final String CYAN_BACKGROUND_BRIGHT = "\033[0;106m"; // CYAN
+		public static final String WHITE_BACKGROUND_BRIGHT = "\033[0;107m"; // WHITE
+	}
+
     /**
      * 
      */
@@ -85,15 +163,15 @@ public class MP
     /**
      * 
      */
-    private static final String CR = "\n";
+    public static final String CR = TLAConstants.CR;
     /**
      * 
      */
-    private static final String SPACE = " ";
+    public static final String SPACE = TLAConstants.SPACE;
     /**
      * 
      */
-    public static final String COLON = ":";
+    public static final String COLON = TLAConstants.COLON;
     public static final String DELIM = "@!@!@"; //$NON-NLS-1$
     public static final String STARTMSG = "STARTMSG "; //$NON-NLS-1$
 
@@ -212,7 +290,42 @@ public class MP
                 break;
             }
         }
-        // fill with different message depending on the error code
+        
+        b.append(getMessage0(messageClass, messageCode, parameters));
+
+        if (TLCGlobals.tool)
+        {
+            // for the tool we always print the message code
+            b.append(CR).append(DELIM).append(ENDMSG).append(messageCode).append(SPACE).append(DELIM);
+        } else
+        {
+
+            // post processing
+            switch (messageClass) {
+            case WARNING:
+            	if (instance.warningHistory.isEmpty()) {
+            		b.append("\n(Use the -nowarning option to disable this warning.)");
+            	}
+                break;
+            case ERROR:
+                if (TLCGlobals.tool)
+                {
+                    b.append("\n--End Error.");
+                }
+                break;
+            case TLCBUG:
+            case NONE:
+            default:
+                break;
+            }
+        }
+        DebugPrinter.print("Leaving getMessage()"); //$NON-NLS-1$
+        return b.toString();
+    }
+
+	private static String getMessage0(int messageClass, int messageCode, String[] parameters) {
+        final StringBuffer b = new StringBuffer();
+		// fill with different message depending on the error code
         switch (messageCode) {
         case EC.UNIT_TEST:
             b.append("[%1%][%2%]");
@@ -228,6 +341,11 @@ public class MP
                     + "pool (heap) may fix this.  But it won't help if some state has an enormous\n"
                     + "number of successor states, or if TLC must compute the value of a huge set.");
             break;
+        case EC.SYSTEM_OUT_OF_MEMORY_LIVENESS:
+            b.append("Java ran out of memory during liveness checking.  Running Java with a larger memory\n"
+                    + "allocation pool (heap) may fix this.  But it won't help if paths in the liveness graph\n"
+                    + "have an enormous number of states.");
+            break;
         case EC.SYSTEM_OUT_OF_MEMORY_TOO_MANY_INIT:
             b.append("Out Of Memory. There are probably too many initial states.");
             break;
@@ -303,9 +421,6 @@ public class MP
             b.append("%1%\nUsage: java tlc2.Simulator [-option] inputfile");
             break;
         /* ----------------------------------------------------------------- */
-        case EC.TLC_USAGE:
-            b.append(Messages.getString("HelpMessage"));// $NON-NLS-1$
-            break;
         case EC.TLC_VERSION:
             b.append("TLC2 %1%");
             break;
@@ -453,17 +568,17 @@ public class MP
                 // format same as state printing for easier
                 // parsing by toolbox
                 if (parameters.length == 1) {
-                    b.append("%1%: Back to state\n");
+                    b.append("%1%: ").append(TLAConstants.BACK_TO_STATE).append("\n");
                 }
                 else if (parameters.length == 2) {
-                    b.append("%1%: Back to state: %2%\n");
+                    b.append("%1%: ").append(TLAConstants.BACK_TO_STATE).append(": %2%\n");
                 }
             } else {
                 if (parameters.length == 1) {
-                    b.append("Back to state %1%\n");
+                    b.append(TLAConstants.BACK_TO_STATE).append(" %1%\n");
                 }
                 else if (parameters.length == 2) {
-                    b.append("Back to state %1%: %2%\n");
+                    b.append(TLAConstants.BACK_TO_STATE).append(" %1%: %2%\n");
                 }
             }
             break;
@@ -608,6 +723,14 @@ public class MP
         case EC.TLC_EXCEPT_APPLIED_TO_UNKNOWN_FIELD:
             b.append("The EXCEPT was applied to non-existing fields of the value at\n%1%");
             break;
+            
+        case EC.TLC_SYMMETRY_SET_TOO_SMALL:
+        	b.append("The set%1% %2% %3% been defined to be a symmetry set but contain%4% less than two elements.");
+        	break;
+            
+        case EC.TLC_SPECIFICATION_FEATURES_TEMPORAL_QUANTIFIER:
+        	b.append("TLC does not support temporal existential, nor universal, quantification over state variables.");
+        	break;
         /* ************************************************************************ */
         case EC.TLC_MODULE_TLCGET_UNDEFINED:
             b.append("TLCGet(%1%) was undefined.");
@@ -683,6 +806,15 @@ public class MP
         case EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_MISMATCH:
             b.append("Failed to match %1% operator override from %2% with signature: %3%.");
             break;
+        case EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_IDENTIFIER_MISMATCH:
+            b.append("Failed to match %1% operator override from %2% with signature: %3% (no such operator).");
+            break;
+        case EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_MODULE_MISMATCH:
+            b.append("Failed to match %1% operator override from %2% with signature: %3% (no such module).");
+            break;
+        case EC.TLC_MODULE_OVERRIDE_STDOUT:
+            b.append("%1%");
+            break;
        case EC.TLC_FEATURE_UNSUPPORTED:
             b.append("%1%");
             break;
@@ -691,6 +823,14 @@ public class MP
             		+ "It might cause TLC to miss violations of the stated liveness properties. "
             		+ "Please check liveness without symmetry defined.");
             break;
+        case EC.TLC_FEATURE_LIVENESS_CONSTRAINTS:
+        	// Specifying Systems Section 14.3.5 page 247.
+        	// https://lamport.azurewebsites.net/tla/book.html
+			b.append("Declaring state or action constraints during liveness checking is dangerous: "
+					+ "Please read section 14.3.5 on page 247 of Specifying Systems "
+					+ "(https://lamport.azurewebsites.net/tla/book.html) and optionally the "
+					+ "discussion at https://discuss.tlapl.us/msg00994.html for more details.");
+            break;
 
         /* Liveness errors */
         case EC.TLC_LIVE_BEGRAPH_FAILED_TO_CONSTRUCT:
@@ -1012,7 +1152,7 @@ public class MP
             b.append("In evaluation, the identifier %1% is either undefined or not an operator.\n%2%");
             break;
         case EC.TLC_CONFIG_SUBSTITUTION_NON_CONSTANT:
-            b.append("The configuration file substitutes constant %1% with non-constant %2%.");
+            b.append("The configuration file substitutes constant %1% with non-constant %2%%3%");
             break;
         case EC.TLC_CONFIG_WRONG_SUBSTITUTION_NUMBER_OF_ARGS:
             b.append("The configuration file substitutes for %1% with %2% of different number of arguments.");
@@ -1039,7 +1179,13 @@ public class MP
             break;
         case EC.TLC_CONFIG_MISSING_INIT:
             b.append("The configuration file did not specify the initial state predicate." +
-                     // Following part of error message added by LL on 15 Nov 2012
+                     // The below part of the error message was added by LL on 15 Nov 2012
+            		 //
+            		 //	ldq, 13 Feb 2020: I don't think this is semantically correct; I receive
+                     //			no errors when defining a specification that references
+            		 //			a formula which is a parameterized INSTANCE. I *do* receive
+                     //			such an error when that formula is being constrained via
+            		 //			the temporal existential qualifier.
                      "\nCan also be caused by trying to run TLC on a specification from" +
                      "\na module imported with a parameterized INSTANCE statement.");
             break;
@@ -1119,7 +1265,7 @@ public class MP
         	}
             break;
         case EC.TLC_STATE_PRINT3:
-            b.append("%1%: Stuttering");
+            b.append("%1%:").append(TLAConstants.STUTTERING);
             break;
 
         /* ************************************************************************ */
@@ -1169,36 +1315,8 @@ public class MP
         }
 
         replaceString(b, parameters);
-
-        if (TLCGlobals.tool)
-        {
-            // for the tool we always print the message code
-            b.append(CR).append(DELIM).append(ENDMSG).append(messageCode).append(SPACE).append(DELIM);
-        } else
-        {
-
-            // post processing
-            switch (messageClass) {
-            case WARNING:
-            	if (instance.warningHistory.isEmpty()) {
-            		b.append("\n(Use the -nowarning option to disable this warning.)");
-            	}
-                break;
-            case ERROR:
-                if (TLCGlobals.tool)
-                {
-                    b.append("\n--End Error.");
-                }
-                break;
-            case TLCBUG:
-            case NONE:
-            default:
-                break;
-            }
-        }
-        DebugPrinter.print("Leaving getMessage()"); //$NON-NLS-1$
         return b.toString();
-    }
+	}
 
     /**
      * Returns the error  
@@ -1469,7 +1587,9 @@ public class MP
     	recorder.record(errorCode, (Object[]) parameters);
         DebugPrinter.print("entering printMessage(int, String[]) with errorCode " + errorCode); //$NON-NLS-1$
         // write the output
-        ToolIO.out.println(getMessage(NONE, errorCode, parameters));
+		ToolIO.out.println(getMessage(NONE, errorCode, parameters));
+		// Don't log the start and end markers when in -tool mode.
+		TLAFlightRecorder.message(getMessage0(NONE, errorCode, parameters));
         DebugPrinter.print("leaving printError(int, String[]) with errorCode "); //$NON-NLS-1$
     }
 
diff --git a/tlatools/src/tlc2/output/SpecTraceExpressionWriter.java b/tlatools/src/tlc2/output/SpecTraceExpressionWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..0ccd401726e88e50bf6a875a3f9cf4d19e559a90
--- /dev/null
+++ b/tlatools/src/tlc2/output/SpecTraceExpressionWriter.java
@@ -0,0 +1,847 @@
+package tlc2.output;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import tlc2.model.Assignment;
+import tlc2.model.Formula;
+import tlc2.model.MCState;
+import tlc2.model.MCVariable;
+import tlc2.model.TraceExpressionInformationHolder;
+import util.TLAConstants;
+
+/**
+ * This is a reified class of spec writer which can produce specs capable of containing trace expressions; it is also
+ * 	the parent class for a more specialized version used by the toolbox, {@code TraceExpressionModelWriter}.
+ */
+public class SpecTraceExpressionWriter extends AbstractSpecWriter {
+	private static final String TRACE_EXPRESSION_VARIABLE = "TraceExp";
+	private static final String TRI_INDENT = TLAConstants.INDENT + TLAConstants.INDENT + TLAConstants.INDENT;
+	
+	/**
+	 * This will generate three identifiers equal to the initial and next state
+	 * predicate for the trace, and the action constraint.
+	 * 
+	 * @param tlaBuffer the buffer into which the TLA code will be placed
+	 * @param cfgBuffer if non-null, the buffer into which the CFG code will be placed
+	 * @param trace
+	 * @param expressionData data on trace explorer expressions, can be null
+	 * @return String[], first element is the identifier for the initial state predicate,
+	 * second element is the identifier for the next-state action, the third element is the identifier for
+	 * the action contraint
+	 * @see #addInitNextToBuffers(StringBuilder, StringBuilder, List, TraceExpressionInformationHolder[], String, String, String)
+	 */
+	public static String[] addInitNextToBuffers(final StringBuilder tlaBuffer, final StringBuilder cfgBuffer,
+			final List<MCState> trace, final TraceExpressionInformationHolder[] expressionData) {
+	    final String initId = SpecWriterUtilities.getValidIdentifier(TLAConstants.Schemes.INIT_SCHEME);
+	    final String nextId = SpecWriterUtilities.getValidIdentifier(TLAConstants.Schemes.NEXT_SCHEME);
+	    final String actionConstraintId = SpecWriterUtilities.getValidIdentifier(TLAConstants.Schemes.ACTIONCONSTRAINT_SCHEME);
+	
+	    addInitNextToBuffers(tlaBuffer, cfgBuffer, trace, expressionData, initId, nextId, actionConstraintId);
+	
+	    return new String[] { initId, nextId, actionConstraintId };
+	}
+	
+	/**
+	 * This calls:
+	 * 	{@code addInitNextToBuffers(tlaBuffer, cfgBuffer, trace, expressionData, initId, nextId, actionConstraintId, TLAConstants.Schemes.NEXT_SCHEME, false);}
+	 * 
+	 * @param tlaBuffer the buffer into which the TLA code will be placed
+	 * @param cfgBuffer if non-null, the buffer into which the CFG code will be placed
+	 * @param trace
+	 * @param expressionData data on trace explorer expressions, can be null
+	 * @param initId the identifier to be used for the initial state predicate, cannot be null
+	 * @param nextId the identifier to be used for the next-state action, cannot be null
+	 * @param actionConstraintId the indentified used for the action constraint
+	 * @see #addInitNextToBuffers(StringBuilder, StringBuilder, List, TraceExpressionInformationHolder[], String, String, String, String)
+	 */
+	public static void addInitNextToBuffers(final StringBuilder tlaBuffer, final StringBuilder cfgBuffer,
+			final List<MCState> trace, final TraceExpressionInformationHolder[] expressionData, final String initId,
+			final String nextId, final String actionConstraintId) {
+		addInitNextToBuffers(tlaBuffer, cfgBuffer, trace, expressionData, initId, nextId, actionConstraintId,
+							 TLAConstants.Schemes.NEXT_SCHEME, false);
+	}
+
+	/**
+	 * This calls:
+	 * 	{@code addInitNextToBuffers(cfgBuffer, trace, expressionData, initId, nextId, actionConstraintId, nextSubActionBasename, leaveStubsForTraceExpression);}
+	 * and then concatenates the returned {@code StringBuilder} instances in order to tlaBuffer.
+	 * 
+	 * @param tlaBuffer the buffer into which the TLA code will be placed
+	 * @param cfgBuffer if non-null, the buffer into which the CFG code will be placed
+	 * @param trace
+	 * @param expressionData data on trace explorer expressions, can be null
+	 * @param initId the identifier to be used for the initial state predicate, cannot be null
+	 * @param nextId the identifier to be used for the next-state action, cannot be null
+	 * @param actionConstraintId the indentified used for the action constraint
+	 * @param nextSubActionBasename the base string to be used as the prefix to unique names for next sub-actions
+	 * @param leaveStubsForTraceExpression if true, then a variable will be defined {@link TRACE_EXPRESSION_VARIABLE},
+	 * 						yet commented out, and similarly conjoined, but commented out in the SpecTE Init and Next
+	 * 						declarations
+	 */
+	public static void addInitNextToBuffers(final StringBuilder tlaBuffer, final StringBuilder cfgBuffer,
+			final List<MCState> trace, final TraceExpressionInformationHolder[] expressionData, final String initId,
+			final String nextId, final String actionConstraintId, final String nextSubActionBasename,
+			final boolean leaveStubsForTraceExpression) {
+		final StringBuilder[] tlaBuffers = addInitNextToBuffers(cfgBuffer, trace, expressionData, initId, nextId,
+				actionConstraintId, nextSubActionBasename, leaveStubsForTraceExpression);
+		
+		tlaBuffer.append(tlaBuffers[0].toString());
+		tlaBuffer.append(tlaBuffers[1].toString());
+	}
+
+	/**
+	 * This will set initId equal to the initial state predicate, nextId equal to the next state
+	 * action for the trace, and actionConstraintId equal to the action constraint for the trace.
+	 * If expressionData is not null, it should contain information about trace explorer expressions. This
+	 * information is used to appropriately put the variables representing trace explorer expressions
+	 * in the trace. In the following example, trace explorer expressions are used, but if expressionData
+	 * is null, those variables will not appear in the init and next definitions, but everything else will be the same.
+	 * 
+	 * Note: In the following example, the expressions expr1,...,expr6, texpr1, texpr2 can take up multiple
+	 * lines.
+	 * 
+	 * Consider the following trace:
+	 * 
+	 * <Initial predicate> <State num 1>
+	 * var1=expr1
+	 * var2=expr2
+	 * 
+	 * <Action...> <State num 2>
+	 * var1=expr3
+	 * var2=expr4
+	 * 
+	 * <Action...> <State num 3>
+	 * var1=expr5
+	 * var2=expr6
+	 * 
+	 * The user has defined two expressions in the trace explorer:
+	 * 
+	 * texpr1 (level 2 represented by var3)
+	 * texpr2 (level 1 represented by var4)
+	 * 
+	 * This method defines the following identifiers:
+	 * 
+	 * init_4123123123 ==
+	 * var1=(
+	 * expr1
+	 * )/\
+	 * var2=(
+	 * expr2
+	 * )/\
+	 * var3=(
+	 * "--"
+	 * )/\
+	 * var4=(
+	 * texpr2
+	 * )
+	 * 
+	 * next_12312312312 ==
+	 * (var1=(
+	 * expr1
+	 * )/\
+	 * var2=(
+	 * expr2
+	 * )/\
+	 * var1'=(
+	 * expr3
+	 * )/\
+	 * var2'=(
+	 * expr4
+	 * )/\
+	 * var3'=(
+	 * texpr1
+	 * )/\
+	 * var4'=(
+	 * texpr2
+	 * )')
+	 * \/
+	 * (var1=(
+	 * expr3
+	 * )/\
+	 * var2=(
+	 * expr4
+	 * )/\
+	 * var1'=(
+	 * expr5
+	 * )/\
+	 * var2'=(
+	 * expr6
+	 * )/\
+	 * var3'=(
+	 * texpr1
+	 * )/\
+	 * var4'=(
+	 * texpr2
+	 * )')
+	 * 
+	 * If the last state is back to state i, then this method treats
+	 * the trace as if it has the state labeled "Back to state i" removed and
+	 * replaced with a copy of state i.
+	 * 
+	 * If the last state is stuttering, then this method treats the trace as if it
+	 * has the state labeled "Stuttering" removed and replaced with a copy
+	 * of the state before the state labeled "Stuttering".
+	 * 
+	 * @param cfgBuffer if non-null, the buffer into which the CFG code will be placed
+	 * @param trace
+	 * @param expressionData data on trace explorer expressions, can be null
+	 * @param initId the identifier to be used for the initial state predicate, cannot be null
+	 * @param nextId the identifier to be used for the next-state action, cannot be null
+	 * @param actionConstraintId the indentified used for the action constraint
+	 * @param nextSubActionBasename the base string to be used as the prefix to unique names for next sub-actions
+	 * @param leaveStubsForTraceExpression if true, then a variable will be defined {@link TRACE_EXPRESSION_VARIABLE},
+	 * 						yet commented out, and similarly conjoined, but commented out in the SpecTE Init and Next
+	 * 						declarations
+	 * @return an array of length 2, the first element is a buffer containing all trace expression subaction
+	 * 				declarations followed by the action constraint definition; the second element is a buffer
+	 * 				containing a potential VARIABLE stub for the trace expression variable, followed by the
+	 * 				definitions for Init and finally Next. This will return null if {@code trace.size() == 0}
+	 */
+	public static StringBuilder[] addInitNextToBuffers(final StringBuilder cfgBuffer,
+													   final List<MCState> trace,
+													   final TraceExpressionInformationHolder[] expressionData,
+													   final String initId, final String nextId,
+													   final String actionConstraintId,
+													   final String nextSubActionBasename,
+													   final boolean leaveStubsForTraceExpression) {
+		if (trace.size() > 0) {
+	        final Iterator<MCState> it = trace.iterator();
+	        MCState currentState = it.next();
+	        final StringBuilder subActionsAndConstraint = new StringBuilder();
+	        final StringBuilder initAndNext = new StringBuilder();
+	
+	        /*******************************************************
+	         * Add the init definition.                            *
+	         *******************************************************/
+			if (cfgBuffer != null) {
+				cfgBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.INIT).append(" definition");
+				cfgBuffer.append(TLAConstants.CR).append(TLAConstants.KeyWords.INIT).append(TLAConstants.CR);
+				cfgBuffer.append(initId).append(TLAConstants.CR);
+			}
+			
+			if (leaveStubsForTraceExpression) {
+				initAndNext.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.VARIABLE).append(' ');
+				initAndNext.append(TRACE_EXPRESSION_VARIABLE).append(TLAConstants.CR).append(TLAConstants.CR);
+			}
+	
+			initAndNext.append(TLAConstants.COMMENT).append("TRACE INIT definition ");
+			initAndNext.append(TLAConstants.TraceExplore.TRACE_EXPLORE_INIT).append(TLAConstants.CR);
+			initAndNext.append(initId).append(TLAConstants.DEFINES_CR);
+	        final MCVariable[] vars = currentState.getVariables();
+	
+	        // variables from spec
+			for (int i = 0; i < vars.length; i++) {
+	            final MCVariable var = vars[i];
+	            /*
+	             *    /\ var = (
+	             *            expr
+	             *          )
+	             */
+	            initAndNext.append(TLAConstants.INDENTED_CONJUNCTIVE);
+	            initAndNext.append(var.getName()).append(TLAConstants.EQ).append(TLAConstants.L_PAREN);
+	            initAndNext.append(TLAConstants.CR);
+	            
+	            initAndNext.append(var.getValueAsStringReIndentedAs(TRI_INDENT)).append(TLAConstants.CR);
+	            
+	            initAndNext.append(TLAConstants.INDENT).append(TLAConstants.INDENT);
+	            initAndNext.append(TLAConstants.R_PAREN).append(TLAConstants.CR);
+	        }
+	
+	        // variables representing trace explorer expressions
+			if (expressionData != null) {
+				for (int i = 0; i < expressionData.length; i++) {
+	                final TraceExpressionInformationHolder expressionInfo = expressionData[i];
+	                initAndNext.append(TLAConstants.INDENTED_CONJUNCTIVE);
+	                initAndNext.append(expressionInfo.getVariableName()).append(TLAConstants.EQ);
+	                initAndNext.append(TLAConstants.L_PAREN).append(TLAConstants.CR);
+	
+	                initAndNext.append(TRI_INDENT);
+					if (expressionInfo.getLevel() == 2) {
+	                    // add "--" if the expression is temporal level
+						initAndNext.append(TLAConstants.TRACE_NA);
+					} else {
+	                    // add the actual expression if it is not temporal level
+						initAndNext.append(expressionInfo.getExpression());
+	                }
+	
+					initAndNext.append(TLAConstants.CR).append(TLAConstants.INDENT).append(TLAConstants.INDENT);
+		            initAndNext.append(TLAConstants.R_PAREN).append(TLAConstants.CR);
+	            }
+	        }
+			
+			if (leaveStubsForTraceExpression) {
+				initAndNext.append(TLAConstants.COMMENT).append(TLAConstants.INDENTED_CONJUNCTIVE);
+				initAndNext.append(TRACE_EXPRESSION_VARIABLE).append(TLAConstants.EQ);
+				initAndNext.append(TLAConstants.KeyWords.TRUE).append(TLAConstants.CR);
+			}
+	
+			initAndNext.append(CLOSING_SEP).append(TLAConstants.CR);
+	
+	        /**********************************************************
+	         *  Now add the next state actions definition             *
+	         **********************************************************/
+			if (cfgBuffer != null) {
+				cfgBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.NEXT).append(" definition");
+				cfgBuffer.append(TLAConstants.CR).append(TLAConstants.KeyWords.NEXT).append(TLAConstants.CR);
+				cfgBuffer.append(nextId).append(TLAConstants.CR);
+			}
+	
+	        MCState nextState;
+	        final boolean isSingleState;
+			if (it.hasNext()) {
+				nextState = it.next();
+				isSingleState = false;
+			} else {
+	            nextState = currentState;
+	            isSingleState = true;
+	        }
+	
+	        /*
+	         * MAK 09/25/2019: Previously, TE.tla was a next-state relation consisting of
+	         * disjuncts of (unnamed) sub-actions:
+	         * 
+	         * Next_123 == (x=1 /\ x'=2) \/ (x=2 /\ x'=3) \/ ... \/ (x=42 /\ x'=42)
+	         * 
+	         * At runtime, TLC created an Action for each sub-action of the next-state
+	         * relation (42 for the example above). For each state generated during
+	         * breadth-first search, all Actions were evaluated, but the assumption was
+	         * that only the one corresponding to the level of the current state would
+	         * generate a valid successor state. However, this is not true if a trace expression This poses two problems:
+	         * 1)  Actions may 
+	         * 
+	         * However, for some next-state relations
+	         * 
+	         * Non-determinism in trace expression
+	         */
+	        final StringBuilder nextDisjunctBuffer = new StringBuilder();
+	        nextDisjunctBuffer.append(nextId).append(TLAConstants.DEFINES_CR);
+	        final String firstIndent;
+			if (leaveStubsForTraceExpression) {
+				nextDisjunctBuffer.append(TLAConstants.TLA_AND).append(' ');
+				firstIndent = " ";
+			} else {
+				firstIndent = TLAConstants.INDENT;
+			}
+	        
+	        final StringBuilder actionConstraintBuffer = new StringBuilder();
+	        actionConstraintBuffer.append(actionConstraintId).append(TLAConstants.DEFINES_CR);
+	        actionConstraintBuffer.append(TLAConstants.BEGIN_TUPLE).append(TLAConstants.CR);
+	
+			if (cfgBuffer != null) {
+				cfgBuffer.append(TLAConstants.COMMENT).append("Action Constraint definition").append(TLAConstants.CR);
+				cfgBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.ACTION_CONSTRAINT).append(TLAConstants.CR);
+				cfgBuffer.append(TLAConstants.COMMENT).append(actionConstraintId).append(TLAConstants.CR);
+			}
+
+	        int subActionIndex = 0;
+			while (nextState != null) {
+				final String nextDisjunct = String.format("%s_sa_%d", nextSubActionBasename, subActionIndex);
+				nextDisjunctBuffer.append((subActionIndex == 0) ? firstIndent : TLAConstants.INDENT);
+				nextDisjunctBuffer.append(TLAConstants.TLA_OR).append(' ').append(nextDisjunct).append(TLAConstants.CR);
+		        actionConstraintBuffer.append(nextDisjunct);
+		        	        	
+		        subActionsAndConstraint.append(TLAConstants.COMMENT).append("TRACE Sub-Action definition ");
+		        subActionsAndConstraint.append(subActionIndex++).append(TLAConstants.CR);
+		        subActionsAndConstraint.append(nextDisjunct).append(TLAConstants.DEFINES_CR);
+	            /*
+	             * Handle Back to state and stuttering.
+	             * 
+	             * nextState is assigned to the state which the "Back to state"
+	             * or "Stuttering" state represents. If nextState is "Back to state i",
+	             * then it is assigned to state i. If nextState is "Stuttering", then
+	             * it is assigned to the current state.
+	             */
+				if (nextState.isBackToState()) {
+					nextState = trace.get(nextState.getStateNumber() - 1);
+				} else if (nextState.isStuttering()) {
+					nextState = currentState;
+				}
+	
+	            /*
+	             * Write the action:
+	             * 
+	             * (/\ var1=(
+	             * expr1
+	             * )
+	             * /\ var2=(
+	             * expr2
+	             * )
+	             * /\ var1'=(
+	             * expr3
+	             * )
+	             * /\ var2'=(
+	             * expr4
+	             * ))
+	             */
+				subActionsAndConstraint.append(TLAConstants.INDENT).append(TLAConstants.L_PAREN).append(TLAConstants.CR);
+	
+	            final MCVariable[] currentStateVars = currentState.getVariables();
+	            final MCVariable[] nextStateVars = nextState.getVariables();
+	
+	            /*
+	             * Iterate through current state variables. This adds:
+	             * 
+	             * /\ var1=(
+	             * expr1
+	             * )
+	             * /\ var2=(
+	             * expr2
+	             * )
+	             * 
+	             */
+				for (int i = 0; i < currentStateVars.length; i++) {
+					final MCVariable currentStateVar = currentStateVars[i];
+					subActionsAndConstraint.append(TLAConstants.INDENT).append(TLAConstants.INDENTED_CONJUNCTIVE);
+					subActionsAndConstraint.append(currentStateVar.getName()).append(TLAConstants.EQ);
+					subActionsAndConstraint.append(TLAConstants.L_PAREN).append(TLAConstants.CR);
+					subActionsAndConstraint.append(currentStateVar.getValueAsStringReIndentedAs(TRI_INDENT + TLAConstants.INDENT));
+					subActionsAndConstraint.append(TLAConstants.CR);
+					subActionsAndConstraint.append(TRI_INDENT).append(TLAConstants.R_PAREN).append(TLAConstants.CR);
+	            }
+	
+	            /*
+	             * If the trace is a single state, make the next state
+	             * action never enabled. The model will deadlock in the initial state.
+	             * This adds:
+	             * 
+	             * /\ FALSE
+	             */
+				if (isSingleState) {
+					subActionsAndConstraint.append(TLAConstants.INDENT).append(TLAConstants.INDENTED_CONJUNCTIVE);
+					subActionsAndConstraint.append("FALSE").append(TLAConstants.CR);
+	            }
+	
+	            /*
+	             * Iterate through next state variables. This adds:
+	             * 
+	             * /\ var1'=(
+	             * expr3
+	             * )
+	             * /\ var2'=(
+	             * expr4
+	             * )
+	             */
+				for (int i = 0; i < currentStateVars.length; i++) {
+	                final MCVariable nextStateVar = nextStateVars[i];
+	                subActionsAndConstraint.append(TLAConstants.INDENT).append(TLAConstants.INDENTED_CONJUNCTIVE);
+	                subActionsAndConstraint.append(nextStateVar.getName()).append(TLAConstants.PRIME);
+	                subActionsAndConstraint.append(TLAConstants.EQ).append(TLAConstants.L_PAREN).append(TLAConstants.CR);
+					subActionsAndConstraint.append(nextStateVar.getValueAsStringReIndentedAs(TRI_INDENT + TLAConstants.INDENT));
+					subActionsAndConstraint.append(TLAConstants.CR);
+					subActionsAndConstraint.append(TRI_INDENT).append(TLAConstants.R_PAREN).append(TLAConstants.CR);
+	            }
+	
+	            /*
+	             * Iterate through the trace explorer expressions if there are any. This adds:
+	             * 
+	             * /\ var3'=(
+	             * texpr1
+	             * )
+	             * /\ var4'=(
+	             * texpr2
+	             * )'
+	             * 
+	             */
+				if (expressionData != null) {
+					for (int i = 0; i < expressionData.length; i++) {
+	                    final TraceExpressionInformationHolder expressionInfo = expressionData[i];
+		                subActionsAndConstraint.append(TLAConstants.INDENT).append(TLAConstants.INDENTED_CONJUNCTIVE);
+	                    subActionsAndConstraint.append(expressionInfo.getVariableName()).append(TLAConstants.PRIME);
+	                    subActionsAndConstraint.append(TLAConstants.EQ).append(TLAConstants.L_PAREN).append(TLAConstants.CR);
+	                    subActionsAndConstraint.append(TRI_INDENT);
+	                    subActionsAndConstraint.append(expressionInfo.getExpression()).append(TLAConstants.CR);
+	                    subActionsAndConstraint.append(TRI_INDENT).append(TLAConstants.R_PAREN);
+	
+						if (expressionInfo.getLevel() < 2) {
+							subActionsAndConstraint.append(TLAConstants.PRIME);
+	                    }
+						subActionsAndConstraint.append(TLAConstants.CR);
+	                }
+	            }
+	
+				subActionsAndConstraint.append(TLAConstants.INDENT).append(TLAConstants.R_PAREN);
+				subActionsAndConstraint.append(TLAConstants.CR).append(TLAConstants.CR);
+	
+				if (it.hasNext()) {
+	                actionConstraintBuffer.append(TLAConstants.COMMA);
+	            }
+				actionConstraintBuffer.append(TLAConstants.CR);
+	
+	            currentState = nextState;
+	
+				if (it.hasNext()) {
+					nextState = it.next();
+				} else {
+					nextState = null;
+				}
+	        }
+	
+	        initAndNext.append(TLAConstants.COMMENT).append("TRACE NEXT definition ");
+	        initAndNext.append(TLAConstants.TraceExplore.TRACE_EXPLORE_NEXT).append(TLAConstants.CR);
+	        initAndNext.append(nextDisjunctBuffer.toString());
+			
+			if (leaveStubsForTraceExpression) {
+				initAndNext.append(TLAConstants.COMMENT).append(TLAConstants.TLA_AND).append(' ');
+				initAndNext.append(TRACE_EXPRESSION_VARIABLE).append(TLAConstants.PRIME).append(TLAConstants.EQ);
+				initAndNext.append(TRACE_EXPRESSION_VARIABLE).append(TLAConstants.CR);
+			}
+	        
+			initAndNext.append(TLAConstants.CR).append(TLAConstants.CR);
+	        
+			
+			subActionsAndConstraint.append(TLAConstants.COMMENT).append("TRACE Action Constraint definition ");
+			subActionsAndConstraint.append(TLAConstants.TraceExplore.TRACE_EXPLORE_ACTION_CONSTRAINT);
+			subActionsAndConstraint.append(TLAConstants.CR).append(actionConstraintBuffer.toString());
+			subActionsAndConstraint.append(TLAConstants.END_TUPLE).append("[TLCGet(\"level\")]");
+
+			subActionsAndConstraint.append(CLOSING_SEP).append(TLAConstants.CR);
+
+			
+	        return new StringBuilder[] { subActionsAndConstraint, initAndNext };
+	    }
+		
+		return null;
+	}
+
+	public static void addTraceFunctionToBuffers(final StringBuilder tlaBuffer, final StringBuilder cfgBuffer,
+			final List<MCState> input) {
+		// Filter stuttering or back2state instances from trace.
+		final List<MCState> trace = input.stream()
+				.filter(state -> !state.isBackToState() && !state.isStuttering())
+				.collect(Collectors.toList());
+		
+		if (trace.isEmpty()) {
+			return;
+	    }
+		
+		// Trace
+		final StringBuilder traceFunctionDef = new StringBuilder();
+		traceFunctionDef.append(TLAConstants.BEGIN_TUPLE).append(TLAConstants.CR);
+		for (int j = 0; j < trace.size(); j++) {
+			final MCState state = trace.get(j);
+
+			traceFunctionDef.append(TLAConstants.L_PAREN).append(state.asSimpleRecord()).append(TLAConstants.R_PAREN);
+
+			if (j < trace.size() - 1) {
+				traceFunctionDef.append(TLAConstants.COMMA).append(TLAConstants.CR);
+			}
+		}
+		traceFunctionDef.append(TLAConstants.CR).append(TLAConstants.END_TUPLE);
+		traceFunctionDef.append(CLOSING_SEP).append(TLAConstants.CR);
+		
+		addArrowAssignmentToBuffers(tlaBuffer, cfgBuffer,
+				new Assignment(TLAConstants.TraceExplore.TRACE, new String[0], traceFunctionDef.toString()),
+				TLAConstants.Schemes.DEFOV_SCHEME);
+	}
+	
+	
+	public SpecTraceExpressionWriter() {
+		super(true);
+	}
+	
+	/**
+	 * This only changes the tla file. This method generates and adds a variable declaration
+	 * for each expression in the list. It also creates an identifier for each
+	 * expression and defines the identifier to be that expression.
+	 * It returns an array of {@link TraceExpressionInformationHolder} where each element
+	 * contains the expression, the identifier, and the variable name.
+	 * 
+	 * If the expressions are x' + y and x > 3, The tla file will contain something like
+	 * 
+	 *\* comment line
+	 * VARIABLES __trace_var_21034978347834, __trace_var_90234782309
+	 * 
+	 * \* comment line
+	 * trace_def_3214234234234 ==
+	 * x' + y
+	 * ----
+	 * 
+	 * \* comment line
+	 * trace_def_2342342342342 ==
+	 * x > 3
+	 * ----
+	 * 
+	 * @param expressions a list of formulas, each one an expression the user wants to have evaluated
+	 * at each state of the trace
+	 * @return array of {@link TraceExpressionInformationHolder} where each element
+	 * contains the expression, the identifier, and the variable name
+	 */
+	public TraceExpressionInformationHolder[] createAndAddVariablesAndDefinitions(final List<Formula> expressions,
+			final String attributeName) {
+		final TraceExpressionInformationHolder[] expressionData
+								= TraceExpressionInformationHolder.createHolders(expressions, attributeName);
+	
+	    addVariablesAndDefinitions(expressionData, attributeName, true);
+	
+	    return expressionData;
+	}
+	
+	@Override
+	public void addPrimer(final String moduleFilename, final String extendedModuleName) {
+		addPrimer(moduleFilename, extendedModuleName, new HashSet<>());
+	}
+	
+	public void addPrimer(final String moduleFilename, final String extendedModuleName, final Set<String> extraExtendedModules) {
+		if (extendedModuleName != null) {
+			extraExtendedModules.add(extendedModuleName);
+		}
+		
+		// Not sure why this is required by TE.tla.
+		extraExtendedModules.add("TLC");
+		
+		// A TE spec has to extend Toolbox to have access to _TETrace and _TEPosition
+		// operators.
+		extraExtendedModules.add("Toolbox");
+		
+		tlaBuffer.append(SpecWriterUtilities.getExtendingModuleContent(moduleFilename,
+				extraExtendedModules.toArray(new String[extraExtendedModules.size()])));
+	}
+
+	/**
+	 * This only changes the tla file. This method adds a variable declaration
+	 * for each element of traceExpressionData and, if the flag addDefinitions is true,
+	 * defines the identifier of each element to be the expression for that element.
+	 * 
+	 * If the expressions are x' + y and x > 3, The tla file will contain something like
+	 * 
+	 *\* comment line
+	 * VARIABLES __trace_var_21034978347834, __trace_var_90234782309
+	 * 
+	 * \* comment line
+	 * trace_def_3214234234234 ==
+	 * x' + y
+	 * ----
+	 * 
+	 * \* comment line
+	 * trace_def_2342342342342 ==
+	 * x > 3
+	 * ----
+	 * 
+	 * @param traceExpressionData information about the trace expressions
+	 * @param attributeName
+	 * @param addDefinitions whether or not to define each identifier as the expression
+	 */
+	public void addVariablesAndDefinitions(final TraceExpressionInformationHolder[] traceExpressionData, final String attributeName,
+			final boolean addDefinitions) {
+		if (traceExpressionData.length == 0) {
+	        return;
+	    }
+	
+	    final StringBuilder variableDecls = new StringBuilder();
+	    final StringBuilder definitions = new StringBuilder();
+		for (int i = 0; i < traceExpressionData.length; i++) {
+	        final TraceExpressionInformationHolder expressionInfo = traceExpressionData[i];
+	
+	        variableDecls.append(expressionInfo.getVariableName());
+	        // we add a comma after every variable except for the last
+	        if (i != traceExpressionData.length - 1)
+	        {
+	            variableDecls.append(TLAConstants.COMMA);
+	        }
+	
+	        if (addDefinitions)
+	        {
+	            // define the identifier corresponding to this expression - looks like:
+	            // \* comment line
+	            // trace_def_213123123123 ==
+	            // expression
+	            // ----
+	            definitions.append(TLAConstants.COMMENT).append("TRACE EXPLORER identifier definition ");
+	            definitions.append(TLAConstants.ATTRIBUTE).append(attributeName).append(TLAConstants.COLON);
+	            definitions.append(i).append(TLAConstants.CR);
+	            definitions.append(expressionInfo.getIdentifier()).append(TLAConstants.DEFINES_CR);
+	            definitions.append(expressionInfo.getExpression()).append(CLOSING_SEP).append(TLAConstants.CR);
+	        }
+	    }
+	
+	    // variable declaration
+	    tlaBuffer.append(TLAConstants.COMMENT).append("TRACE EXPLORER variable declaration ");
+	    tlaBuffer.append(TLAConstants.ATTRIBUTE).append(attributeName).append(TLAConstants.CR);
+	    tlaBuffer.append("VARIABLES ").append(variableDecls.toString()).append(CLOSING_SEP).append(TLAConstants.CR);
+	
+		if (addDefinitions) {
+	        // append the expression definitions
+	        tlaBuffer.append(definitions.toString());
+	    }
+	}
+
+	/**
+	 * Adds the invariant ~(P) where P is the formula describing finalState. The format
+	 * in the tla file is as follows:
+	 * 
+	 * inv_12312321321 ==
+	 * ~(
+	 * P
+	 * )
+	 * ----
+	 * 
+	 * @param finalState
+	 */
+	public void addInvariant(final MCState finalState) {
+	    final String id = SpecWriterUtilities.getValidIdentifier(TLAConstants.Schemes.INVARIANT_SCHEME);
+	    cfgBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.INVARIANT).append(" definition");
+	    cfgBuffer.append(TLAConstants.CR).append(TLAConstants.KeyWords.INVARIANT).append(TLAConstants.CR);
+	    cfgBuffer.append(id).append(TLAConstants.CR);
+	
+	    tlaBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.INVARIANT).append(" definition");
+	    tlaBuffer.append(TLAConstants.CR).append(id).append(TLAConstants.DEFINES_CR);
+	    tlaBuffer.append(TLAConstants.TLA_NOT).append(TLAConstants.L_PAREN).append(TLAConstants.CR);
+	    tlaBuffer.append(getStateConjunction(finalState)).append(TLAConstants.CR).append(TLAConstants.R_PAREN);
+	
+	    tlaBuffer.append(CLOSING_SEP).append(TLAConstants.CR);
+	}
+
+	/**
+	 * Adds the temporal property ~<>[](P) where P is the formula describing finalState.
+	 * The format in the tla file is as follows:
+	 * 
+	 * prop_23112321 ==
+	 * ~<>[](
+	 * P
+	 * )
+	 * ----
+	 * 
+	 * @param finalState
+	 */
+	public void addStutteringProperty(final MCState finalState) {
+	    String id = SpecWriterUtilities.getValidIdentifier(TLAConstants.Schemes.PROP_SCHEME);
+	    cfgBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.PROPERTY).append(" definition");
+	    cfgBuffer.append(TLAConstants.CR).append(TLAConstants.KeyWords.PROPERTY).append(TLAConstants.CR);
+	    cfgBuffer.append(id).append(TLAConstants.CR);
+	
+	    tlaBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.PROPERTY).append(" definition");
+	    tlaBuffer.append(TLAConstants.CR).append(id).append(TLAConstants.DEFINES_CR);
+	    tlaBuffer.append(TLAConstants.TLA_NOT).append(TLAConstants.TLA_EVENTUALLY_ALWAYS);
+	    tlaBuffer.append(TLAConstants.L_PAREN).append(TLAConstants.CR).append(getStateConjunction(finalState));
+	    tlaBuffer.append(TLAConstants.CR).append(TLAConstants.R_PAREN).append(CLOSING_SEP).append(TLAConstants.CR);
+	}
+
+	/**
+	 * Adds the temporal property ~([]<>P /\ []<>Q), where P is the formula describing finalState and 
+	 * Q the formula describing backToState. The formating in the tla file is as follows:
+	 * 
+	 * prop_21321312 ==
+	 * ~(([]<>(
+	 * P
+	 * ))/\([]<>(
+	 * Q
+	 * )))
+	 * ----
+	 * 
+	 * @param finalState
+	 * @param backToState
+	 */
+	public void addBackToStateProperty(final MCState finalState, final MCState backToState) {
+	    final String id = SpecWriterUtilities.getValidIdentifier(TLAConstants.Schemes.PROP_SCHEME);
+	    cfgBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.PROPERTY).append(" definition");
+	    cfgBuffer.append(TLAConstants.CR).append(TLAConstants.KeyWords.PROPERTY).append(TLAConstants.CR);
+	    cfgBuffer.append(id).append(TLAConstants.CR);
+	
+	    tlaBuffer.append(TLAConstants.COMMENT).append(TLAConstants.KeyWords.PROPERTY).append(" definition");
+	    tlaBuffer.append(TLAConstants.CR).append(id).append(TLAConstants.DEFINES_CR);
+	    tlaBuffer.append(TLAConstants.TLA_NOT).append(TLAConstants.L_PAREN).append(TLAConstants.L_PAREN);
+	    tlaBuffer.append(TLAConstants.TLA_INF_OFTEN).append(TLAConstants.L_PAREN).append(TLAConstants.CR);
+	    tlaBuffer.append(getStateConjunction(finalState)).append(TLAConstants.CR).append(TLAConstants.R_PAREN);
+	    tlaBuffer.append(TLAConstants.R_PAREN).append(TLAConstants.TLA_AND).append(TLAConstants.L_PAREN);
+	    tlaBuffer.append(TLAConstants.TLA_INF_OFTEN).append(TLAConstants.L_PAREN).append(TLAConstants.CR);
+	    tlaBuffer.append(getStateConjunction(backToState)).append(TLAConstants.CR).append(TLAConstants.R_PAREN);
+	    tlaBuffer.append(TLAConstants.R_PAREN).append(TLAConstants.R_PAREN).append(CLOSING_SEP).append(TLAConstants.CR);
+	}
+
+	/**
+	 * Writes comments that will be used for associating variable names with expressions
+	 * and will give the level of each expression. In particular, for each expression "expr"
+	 * with level x and variable name ___trace_var_3242348934343 this
+	 * will append the following comment to the tla file:
+	 * 
+	 * \* :x:___trace_var_3242348934343:expr"$!@$!@$!@$!@$!"
+	 * 
+	 * @param traceExpressionData
+	 */
+	public void addInfoComments(final TraceExpressionInformationHolder[] traceExpressionData) {
+		for (final TraceExpressionInformationHolder expressionData : traceExpressionData) {
+	        tlaBuffer.append(TLAConstants.COMMENT).append(TLAConstants.COLON).append(expressionData.getLevel());
+	        tlaBuffer.append(TLAConstants.COLON).append(expressionData.getVariableName()).append(TLAConstants.COLON);
+	        tlaBuffer.append(expressionData.getExpression()).append(TLAConstants.CONSTANT_EXPRESSION_EVAL_IDENTIFIER);
+	        tlaBuffer.append(TLAConstants.CR);
+	    }
+	}
+
+	/**
+	 * @see #addInitNextToBuffers(StringBuilder, StringBuilder, List, TraceExpressionInformationHolder[])
+	 */
+	public String[] addInitNext(final List<MCState> trace, final TraceExpressionInformationHolder[] expressionData) {
+		return addInitNextToBuffers(tlaBuffer, cfgBuffer, trace, expressionData);
+	}
+
+	/**
+	 * @see #addInitNextToBuffers(StringBuilder, StringBuilder, List, TraceExpressionInformationHolder[], String, String, String)
+	 */
+	public void addInitNext(final List<MCState> trace, final TraceExpressionInformationHolder[] expressionData,
+							final String initId, String nextId, final String actionConstraintId) {
+		addInitNextToBuffers(tlaBuffer, cfgBuffer, trace, expressionData, initId, nextId, actionConstraintId);
+	}
+
+	/**
+	 * @see #addInitNextToBuffers(StringBuilder, StringBuilder, List, TraceExpressionInformationHolder[], String, String, String, String, boolean)
+	 */
+	public void addInitNext(final List<MCState> trace, final TraceExpressionInformationHolder[] expressionData,
+							final String initId, String nextId, final String actionConstraintId,
+							final String nextSubActionBasename) {
+		addInitNextToBuffers(tlaBuffer, cfgBuffer, trace, expressionData, initId, nextId, actionConstraintId,
+							 nextSubActionBasename, true);
+	}
+
+	public void addTraceFunction(final List<MCState> input) {
+		addTraceFunctionToBuffers(tlaBuffer, cfgBuffer, input);
+	}
+	
+    /**
+     * Returns a string representing the formula describing the state.
+     * If the state has var1=expr1, var2 = expr2, and var3=expr3, then this returns:
+     * 
+     * var1=(
+     * expr1
+     * )/\
+     * var2=(
+     * expr2
+     * )/\
+     * var3=(
+     * expr3
+     * )
+     * 
+     * 
+     * The expressions expr1, expr2, and expr3 can take up multiple lines.
+     * 
+     * This will return null if the state is stuttering or back to state.
+     * 
+     * @param state
+     * @return
+     */
+	private static String getStateConjunction(final MCState state) {
+		if (state.isBackToState()) {
+			return null;
+		} else if (state.isStuttering()) {
+			return null;
+		} else {
+            final StringBuilder formula = new StringBuilder();
+            final MCVariable[] vars = state.getVariables();
+			for (int i = 0; i < vars.length; i++) {
+				final MCVariable var = vars[i];
+				formula.append(var.getName()).append(TLAConstants.EQ).append(TLAConstants.L_PAREN).append(TLAConstants.CR);
+				formula.append(var.getValueAsString()).append(TLAConstants.CR).append(TLAConstants.R_PAREN);
+
+				// append /\ except for the last variable
+				if (i != (vars.length - 1)) {
+                    formula.append(TLAConstants.TLA_AND).append(TLAConstants.CR);
+                }
+            }
+
+            return formula.toString();
+        }
+    }
+}
diff --git a/tlatools/src/tlc2/output/SpecWriterUtilities.java b/tlatools/src/tlc2/output/SpecWriterUtilities.java
new file mode 100644
index 0000000000000000000000000000000000000000..32229aa9f49405a21bdf10f094480ab9631f0328
--- /dev/null
+++ b/tlatools/src/tlc2/output/SpecWriterUtilities.java
@@ -0,0 +1,349 @@
+package tlc2.output;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.regex.Pattern;
+
+import tla2sany.modanalyzer.SpecObj;
+import tla2sany.semantic.OpDefNode;
+import tlc2.model.Assignment;
+import tlc2.model.Formula;
+import util.StringHelper;
+import util.TLAConstants;
+
+/**
+ * There were a lot of utility methods in the toolbox's ModelWriter class that made what statefulness of that class which
+ * existed, obscured. I broke out the utility methods into their own class on migration and clean-up.
+ */
+public final class SpecWriterUtilities {
+	/*
+     * Constants used for displaying modification history.
+     * It has the syntax:
+     *   modificationHistory +
+     *   (lastModified + date + modifiedBy +
+     *      username + newline)*
+     *      
+     * Note: The StringHelper.newline string wasn't being found on my 64-bit
+     * Windows 7 machine.  So on 8 Dec 2010 I removed it from here, and added
+     * a "\n" before it when writing a new file.
+     */
+    public static String MODIFICATION_HISTORY = /* StringHelper.PLATFORM_NEWLINE + */ "\\* Modification History";
+    public static String LAST_MODIFIED = StringHelper.PLATFORM_NEWLINE + "\\* Last modified ";
+    public static String MODIFIED_BY = " by ";
+
+    /**
+     * @param rightMarginWidth the margin width of the output
+     * @param addModificationHistory whether to add the modification history
+     * @return the content for the end of the module
+     */
+	public static StringBuilder getModuleClosingTag(final int rightMarginWidth, final boolean addModificationHistory) {
+        final StringBuilder buffer = new StringBuilder();
+        buffer.append(StringHelper.copyString("=", rightMarginWidth)).append(StringHelper.PLATFORM_NEWLINE);
+
+        if (addModificationHistory) {
+            buffer.append(MODIFICATION_HISTORY).append(StringHelper.PLATFORM_NEWLINE)
+                .append("\\* Created ").append(new Date()).append(MODIFIED_BY)
+                .append(System.getProperty("user.name")).append(StringHelper.PLATFORM_NEWLINE);
+        }
+        return buffer;
+    }
+
+	/**
+	 * @return the content for the end of the module
+	 */
+	public static StringBuilder getGeneratedTimeStampCommentLine() {
+		final StringBuilder buffer = new StringBuilder();
+		buffer.append(TLAConstants.GENERATION_TIMESTAMP_PREFIX).append(new Date());
+		return buffer;
+	}
+
+    /**
+     * A pattern to match IDs generated by the {@link AbstractSpecWriter#getValidIdentifier(String)} method
+     */
+    public static final Pattern ID_MATCHER
+    	= Pattern.compile("(" + TLAConstants.Schemes.SPEC_SCHEME + "|"
+    						  + TLAConstants.Schemes.INIT_SCHEME + "|"
+    						  + TLAConstants.Schemes.NEXT_SCHEME + "|"
+    						  + TLAConstants.Schemes.CONSTANT_SCHEME + "|"
+    						  + TLAConstants.Schemes.SYMMETRY_SCHEME + "|"
+    						  + TLAConstants.Schemes.DEFOV_SCHEME + "|"
+    						  + TLAConstants.Schemes.CONSTRAINT_SCHEME + "|"
+    						  + TLAConstants.Schemes.ACTIONCONSTRAINT_SCHEME + "|"
+    						  + TLAConstants.Schemes.INVARIANT_SCHEME + "|"
+    						  + TLAConstants.Schemes.PROP_SCHEME + ")_[0-9]{17,}");
+
+    /**
+     * Creates a new valid unqiue identifier from given scheme
+     * @param scheme a naming scheme, one of the {@link TLAConstants.Schemes} constants
+     * @return a valid identifier
+     */
+	public static String getValidIdentifier(final String scheme) {
+		return String.format("%s_%s%s", scheme, System.currentTimeMillis(), 1000 * COUNTER.incrementAndGet());
+	}
+
+    /**
+     * Converts formula list to a string representation
+     * @param formulaList list of assignments
+	 * @param labelingScheme one of the {@link TLAConstants.Schemes} constants
+     * @return
+     */
+	public static List<String[]> createListContent(final List<Formula> formulaList, final String labelingScheme) {
+		ArrayList<String[]> resultContent = new ArrayList<>(formulaList.size());
+		String[] content;
+		String label;
+		for (int i = 0; i < formulaList.size(); i++) {
+			label = getValidIdentifier(labelingScheme);
+			// formulas
+			// to .cfg : <id>
+			// to _MC.tla : <id> == <expression>
+			content = new String[] { label, label + TLAConstants.DEFINES_CR + formulaList.get(i).getFormula(), String.valueOf(i) };
+			resultContent.add(content);
+		}
+		return resultContent;
+	}
+
+    /**
+     * Retrieves the name of the module (filename without extension)
+     * 
+     * @param moduleFilename
+     *            filename of a module
+     * @param checkExistence
+     *            if true, the method returns module name, iff the specified file exists or null, if the specified file
+     *            does not exist, if false - only string manipulations are executed
+     * @return module name
+     */
+	public static String getModuleNameChecked(final String moduleFilename, final boolean checkExistence) {
+		final File f = new File(moduleFilename);
+		final int index = f.getName().lastIndexOf('.');
+		if (checkExistence) {
+			return (f.exists())
+						? (index != -1) ? f.getName().substring(0, index) : f.getName()
+						: null;
+		}
+		return (index != -1) ? f.getName().substring(0, index) : f.getName();
+	}
+
+    /**
+     * Creates a simple content for a new TLA+ module
+     *  
+     * @param moduleFileName, name of the file 
+     * @return the stream with content
+     */
+	public static StringBuilder getExtendingModuleContent(final String moduleFilename, final String... extendedModuleName) {
+		final StringBuilder buffer = new StringBuilder();
+		buffer.append(TLAConstants.SEP).append(' ').append(TLAConstants.KeyWords.MODULE).append(' ');
+		buffer.append(getModuleNameChecked(moduleFilename, false)).append(' ').append(TLAConstants.SEP).append('\n');
+		buffer.append(TLAConstants.KeyWords.EXTENDS).append(' ');
+		buffer.append(String.join(", ", extendedModuleName));
+		buffer.append("\n\n");
+		return buffer;
+	}
+
+	public static List<String[]> createFalseInit(final String var) {
+		final List<String[]> list = new ArrayList<>();
+		final String identifier = getValidIdentifier(TLAConstants.Schemes.INIT_SCHEME);
+		list.add(new String[] { identifier,
+							    (identifier + TLAConstants.DEFINES_CR + "FALSE/\\" + var + TLAConstants.EQ + "0") });
+		return list;
+	}
+
+	public static List<String[]> createFalseNext(final String var) {
+		final List<String[]> list = new ArrayList<>();
+		final String identifier = getValidIdentifier(TLAConstants.Schemes.NEXT_SCHEME);
+		list.add(new String[] { identifier,
+								(identifier + TLAConstants.DEFINES_CR + "FALSE/\\" + var + TLAConstants.PRIME
+											+ TLAConstants.EQ + var) });
+		return list;
+	}
+
+    /**
+     * Converts formula list to a string representation
+     * @param serializedFormulaList, list of strings representing formulas (with enablement flag)
+	 * @param labelingScheme one of the {@link TLAConstants.Schemes} constants
+     * @return
+     */
+	public static List<String[]> createFormulaListContent(final List<String> serializedFormulaList,
+			final String labelingScheme) {
+		List<Formula> formulaList = Formula.deserializeFormulaList(serializedFormulaList);
+		return createFormulaListContentFormula(formulaList, labelingScheme);
+	}
+
+	public static List<String[]> createFormulaListContentFormula(final List<Formula> serializedFormulaList,
+			final String labelingScheme) {
+		return SpecWriterUtilities.createListContent(serializedFormulaList, labelingScheme);
+	}
+	
+	/**
+	 * @param value if null or empty, an empty list will be returned
+	 * @param labelingScheme one of the {@link TLAConstants.Schemes} constants
+	 * @return the content for a single source element
+	 */
+	public static List<String[]> createSourceContent(final String value, final String labelingScheme) {
+		return createSourceContent(value, labelingScheme, true);
+	}
+	
+	/**
+	 * @param value if null or empty, an empty list will be returned
+	 * @param identifierOrLabelingScheme an identifier or one of the
+	 *                                   {@link TLAConstants.Schemes} constants
+	 * @param isScheme                   true if {@code identifierOrLabelingScheme}
+	 *                                   is one of the scheme constants (in which
+	 *                                   case an identifier will be generated based
+	 *                                   off of it.)
+	 * @return the content for a single source element
+	 */
+	public static List<String[]> createSourceContent(final String value, final String identifierOrLabelingScheme,
+			final boolean isScheme) {
+		final ArrayList<String[]> result = new ArrayList<>();
+		if ((value == null) || (value.trim().length() == 0)) {
+			return result;
+		}
+		
+        final String identifier = isScheme ? SpecWriterUtilities.getValidIdentifier(identifierOrLabelingScheme)
+        								   : identifierOrLabelingScheme;
+        final StringBuilder buffer = new StringBuilder();
+
+        buffer.append(identifier).append(TLAConstants.DEFINES_CR);
+        buffer.append(value);
+
+        result.add(new String[] { identifier, buffer.toString() });
+        return result;
+	}
+
+    /**
+     * Create a list of overrides. If the override is not in the spec's root module, then
+     * the config file will have     A <- [M] id . This means that A is defined in module M,
+     * and its definition is being overriden in the spec root module which is dependent upon M.
+     * The following is an example from Leslie Lamport that explains what occurred before changing
+     * the code and what occurs now.
+     * Consider the root module
+
+    ----------------- MODULE TestA --------------------
+    M(a,b) == INSTANCE TestB WITH CB <- a, CD <- b
+    ==================================================
+
+    which imports the module
+
+    ----------------- MODULE TestB --------------------
+    CONSTANTS CB, CD
+
+    Foo(x) == <<x, CB, CD>>
+    ==================================================
+
+    If you go to definition overrides, you'll find the option of
+    overriding M!Foo.  Selecting it, the toolbox asks you to define an operator
+    M!Foo of 3 arguments.  If you do it and run TLC, you get the error
+
+    The configuration file substitutes for Foo with
+    def_ov_12533499062845000 of different number of arguments.
+
+    Here's what's going on.  The INSTANCE statement imports the operator
+    M!Foo into module TestA.  As you may recall, you use that operator
+    in an expression by writing something like
+
+    M(42, "a")!F(-13)
+
+    but in the semantic tree, it looks just as if M!F were any other
+    operator with three arguments.  When TLC sees the override instruction
+
+    Foo <- [TestB]def_ov_12533495599614000
+
+    in the .cfg file, it tries to substitute an operator def_ov_...  with
+    3 arguments for the operator Foo of module TestB that has only a
+    single argument.  Hence, the error.
+
+    ------
+
+    Here's the fix.  Instead of giving the user the option of overriding
+    M!Foo, in the menu, he should simply see Foo and, if he clicks once
+    it, he should see that it's in module TestB. If he chooses to override
+    Foo, he should be asked to define an operator of one argument.
+    
+     * @param overrides
+	 * @param labelingScheme one of the {@link TLAConstants.Schemes} constants
+	 * @param specObj
+     * @return
+     * 
+     * Was throwing null-pointer exception when called with spec unparsed.
+     * Hacked a fix to handle this case.  LL 20 Sep 2009
+     */
+	public static List<String[]> createOverridesContent(final List<Assignment> overrides, final String labelingScheme,
+			final SpecObj specObj) {
+		final ArrayList<String[]> resultContent = new ArrayList<>(overrides.size());
+		String[] content;
+		String id;
+		Assignment formula;
+
+        // getting the opdefnodes is necessary for retrieving the correct label
+        // to appear in the cfg file as explained in the documentation for this method
+		if (specObj == null) {
+			return resultContent;
+		}
+		final OpDefNode[] opDefNodes = specObj.getExternalModuleTable().getRootModule().getOpDefs();
+		final HashMap<String, OpDefNode> nodeTable = new HashMap<>(opDefNodes.length);
+
+		for (int j = 0; j < opDefNodes.length; j++) {
+			final String key = opDefNodes[j].getName().toString();
+			nodeTable.put(key, opDefNodes[j]);
+		}
+
+		for (int i = 0; i < overrides.size(); i++) {
+            id = getValidIdentifier(labelingScheme);
+            // formulas
+            // to .cfg : <id>
+            // to _MC.tla : <id> == <expression>
+            formula = overrides.get(i);
+
+            final OpDefNode defNode = nodeTable.get(formula.getLabel());
+			if (defNode == null) {
+				// should raise an error
+				content = null;
+			} else {
+				final OpDefNode source = defNode.getSource();
+				if (source == defNode) {
+                    // user is overriding a definition in the root module
+					if (formula.isModelValue() && !formula.isSetOfModelValues()) {
+                        // model value
+                        content = new String[] { formula.getLabel() + TLAConstants.EQ + formula.getLabel(), TLAConstants.EMPTY_STRING };
+					} else {
+                        // not a model value
+                        content = new String[] { formula.getLabel() + TLAConstants.ARROW + id,
+                                formula.getParametrizedLabel(id) + TLAConstants.DEFINES_CR + formula.getRight() };
+                    }
+				} else if (source.getSource() == source) {
+					// user is overriding a definition that is not in the root module
+					if (formula.isModelValue() && !formula.isSetOfModelValues()) {
+                        // model value
+                        content = new String[] {
+                                source.getName().toString() + TLAConstants.ARROW + "["
+                                        + source.getOriginallyDefinedInModuleNode().getName().toString() + "]" + id
+                                        + " " + id + TLAConstants.EQ + source.getName().toString(), "CONSTANT " + id };
+					} else {
+                        // not a model value
+                        content = new String[] {
+                                source.getName().toString() + TLAConstants.ARROW + "["
+                                        + source.getOriginallyDefinedInModuleNode().getName().toString() + "]" + id,
+                                formula.getParametrizedLabel(id) + TLAConstants.DEFINES_CR + formula.getRight() };
+                    }
+				} else {
+                    // should raise an error window
+                    content = null;
+                }
+            }
+
+            resultContent.add(content);
+        }
+		
+        return resultContent;
+    }
+
+    /**
+     * Counter to be able to generate unique identifiers
+     */
+    private static final AtomicLong COUNTER = new AtomicLong(1L);
+
+}
diff --git a/tlatools/src/tlc2/output/TLACopier.java b/tlatools/src/tlc2/output/TLACopier.java
new file mode 100644
index 0000000000000000000000000000000000000000..13682602103235961ac6f21b52a93ded74ad5318
--- /dev/null
+++ b/tlatools/src/tlc2/output/TLACopier.java
@@ -0,0 +1,69 @@
+package tlc2.output;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.util.regex.Matcher;
+
+import util.TLAConstants;
+
+/**
+ * This class which copies a TLA file, mutating it appropriately to become a SpecTE TLA file.
+ */
+public class TLACopier extends AbstractTLACopier {
+	private final String initNextDefinitions;
+	
+	private final boolean needExtendTLC;
+	private final boolean needExtendToolbox;
+	
+	public TLACopier(final String originalName, final String newName, final File sourceLocation,
+					 final String initNextDefinitionTLA, final boolean originalExtendsTLC,
+					 final boolean originalExtendsToolbox) {
+		super(originalName, newName, sourceLocation);
+		
+		initNextDefinitions = initNextDefinitionTLA;
+		
+		needExtendTLC = !originalExtendsTLC;
+		needExtendToolbox = !originalExtendsToolbox;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected void copyLine(final BufferedWriter writer, final String originalLine, final int lineNumber)
+			throws IOException {
+		if (!inBody) {
+			final Matcher m = modulePattern.matcher(originalLine);
+			final String lineToWrite;
+
+			if (m.find()) {
+				lineToWrite = m.group(1) + ' ' + newModuleName + ' ' + TLAConstants.SEP;
+				inBody = true;
+			} else {
+				lineToWrite = originalLine;
+			}
+
+			writer.write(lineToWrite + '\n');
+		} else {
+			if (originalLine.trim().startsWith(TLAConstants.KeyWords.EXTENDS)) {
+				String line = originalLine;
+				if (needExtendTLC) {
+					line += ", " + TLAConstants.BuiltInModules.TLC;
+				}
+				if (needExtendToolbox) {
+					line += ", " + TLAConstants.BuiltInModules.TRACE_EXPRESSIONS;
+				}
+				writer.write(line + '\n');
+			} else {
+				final Matcher m = CLOSING_BODY_PATTERN.matcher(originalLine);
+
+				if (m.matches()) {
+					writer.write(initNextDefinitions + '\n');
+				}
+
+				writer.write(originalLine + '\n');
+			}
+		}
+	}
+}
diff --git a/tlatools/src/tlc2/output/TLAMonolithCreator.java b/tlatools/src/tlc2/output/TLAMonolithCreator.java
new file mode 100644
index 0000000000000000000000000000000000000000..3ce15e66acc9a54bc29b3a438d224643f1f11981
--- /dev/null
+++ b/tlatools/src/tlc2/output/TLAMonolithCreator.java
@@ -0,0 +1,288 @@
+package tlc2.output;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.nio.file.CopyOption;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.Stack;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import tla2sany.semantic.StandardModules;
+import tlc2.input.MCParser;
+import tlc2.input.MCParserResults;
+import util.TLAConstants;
+
+public class TLAMonolithCreator extends AbstractTLACopier {
+	private static final String NESTED_MODULE_INDENT = "    ";
+	private static final String LOCAL_INSTANCE_REGEX = "^LOCAL INSTANCE ([^\\s]+)\\s*$";
+	private static final Pattern LOCAL_INSTANCE_PATTERN = Pattern.compile(LOCAL_INSTANCE_REGEX);
+	
+	
+	// these are modules which SANY logs that it has parsed, scrubbed of Standard Modules and in reverse order
+	private final List<File> modulesToEmbed;
+	private final Set<String> moduleNamesBeingEmbedded;
+	// these are the modules which the root ModuleNode or one of its sub-ModuleNodes (or one or their sub-ModuleNodes
+	//		and so on, turtles all the way down) has defined as EXTENDS-ing in their spec
+	private final Set<String> modulesToSpecifyInExtends;
+	// TODO this is insufficient for nestings beyond one level
+	private final List<File> modulesToNest;
+	
+	/**
+	 * This is the constructor for the version which embeds no dependent modules.
+	 * 
+	 * @param entireExtendsList the modules which the root ModuleNode or one of its sub-ModuleNodes (or one or their
+	 * 								sub-ModuleNodes and so on, turtles all the way down) has defined as EXTENDS-ing
+	 * 								in their spec.
+	 */
+	public TLAMonolithCreator(final String rootSpecName, final File sourceLocation, final Set<String> entireExtendsList) {
+		this(rootSpecName, sourceLocation, null, entireExtendsList, null);
+	}
+	
+	/**
+	 * @param rootSpecName
+	 * @param sourceLocation
+	 * @param extendeds these are modules which SANY logs that it has parsed; we expect to receive this in the order
+	 * 								which SANY emits it in logging; if that order changes in the future, the monolith
+	 * 								spec will potentially break due to dependent functions being declared in the
+	 * 								wrong order
+	 * @param entireExtendsList the modules which the root ModuleNode or one of its sub-ModuleNodes (or one or their
+	 * 								sub-ModuleNodes and so on, turtles all the way down) has defined as EXTENDS-ing
+	 * 								in their spec; this will get the non Standard Modules filtered out of it prior to
+	 * 								usage in this class since those will get embedded as a dependent module.
+	 * @param allInstantiatedModules
+	 */
+	public TLAMonolithCreator(final String rootSpecName, final File sourceLocation, final List<File> extendeds,
+							  final Set<String> entireExtendsList, final Set<String> allInstantiatedModules) {
+		super(rootSpecName, ("tmp_" + System.currentTimeMillis() + "_monolith"), sourceLocation);
+		
+		final boolean willEmbedDependents = (extendeds != null);
+		
+		moduleNamesBeingEmbedded = new HashSet<>();
+		modulesToNest = new ArrayList<>();
+		modulesToEmbed = new ArrayList<>();
+		if (willEmbedDependents) {
+			final HashSet<String> instantiatedModules = new HashSet<>(allInstantiatedModules);
+			final Stack<File> embedStack = new Stack<>();
+			for (final File f : extendeds) {
+				final String name = f.getName();
+				final int index = name.toLowerCase().indexOf(TLAConstants.Files.TLA_EXTENSION);
+				final boolean keep;
+				final String moduleName;
+				if (index == -1) {
+					// this should never be the case
+					keep = true;
+					moduleName = name;
+				} else {
+					moduleName = name.substring(0, index);
+	
+					keep = !StandardModules.isDefinedInStandardModule(moduleName);
+				}
+				
+				if (keep) {
+					embedStack.push(f);
+					instantiatedModules.remove(moduleName);
+					moduleNamesBeingEmbedded.add(moduleName);
+				}
+			}
+			
+			while (!embedStack.isEmpty()) {
+				modulesToEmbed.add(embedStack.pop());
+			}
+			
+			for (final String module : instantiatedModules) {
+				if (!StandardModules.isDefinedInStandardModule(module)) {
+					modulesToNest.add(new File(sourceLocation, (module + TLAConstants.Files.TLA_EXTENSION)));
+				}
+			}
+		}
+		
+		modulesToSpecifyInExtends = new HashSet<>(entireExtendsList);
+		if (willEmbedDependents) {
+			StandardModules.filterNonStandardModulesFromSet(modulesToSpecifyInExtends);
+		}
+		// for TLC things
+		modulesToSpecifyInExtends.add(TLAConstants.BuiltInModules.TLC);
+		// for _TE things
+		modulesToSpecifyInExtends.add(TLAConstants.BuiltInModules.TRACE_EXPRESSIONS);
+	}
+	
+	@Override
+	protected void copyLine(final BufferedWriter writer, final String originalLine, final int lineNumber)
+			throws IOException {
+		if (!inBody) {
+			final Matcher m = modulePattern.matcher(originalLine);
+
+			inBody = m.find();
+
+			if (!vetoLocalInstanceLine(originalLine)) {
+				writer.write(originalLine + '\n');
+			}
+		} else {
+			if (originalLine.trim().startsWith(TLAConstants.KeyWords.EXTENDS)) {
+				writer.write(TLAConstants.KeyWords.EXTENDS + " " + String.join(", ", modulesToSpecifyInExtends) + "\n");
+
+				for (final File f : modulesToNest) {
+					insertModuleIntoMonolith(f, writer, true);
+				}
+				
+				for (final File f : modulesToEmbed) {
+					insertModuleIntoMonolith(f, writer, false);
+				}
+				
+				final StringBuilder commentLine = new StringBuilder(TLAConstants.CR);
+				commentLine.append(TLAConstants.COMMENT).append(TLAConstants.CR);
+				commentLine.append(TLAConstants.COMMENT).append(' ');
+				commentLine.append(originalModuleName);
+				commentLine.append(" follows\n");
+				commentLine.append(TLAConstants.COMMENT).append(TLAConstants.CR).append(TLAConstants.CR);
+				writer.write(commentLine.toString());
+			} else {
+				writer.write(originalLine + '\n');
+			}
+		}
+	}
+	
+	@Override
+	protected void copyHasFinished() throws IOException {
+		final Path originalPath = sourceFile.toPath();
+		Files.delete(originalPath);
+		
+		final Path monolithPath = destinationFile.toPath();
+		Files.move(monolithPath, originalPath, new CopyOption[0]);
+	}	
+	
+	private void insertModuleIntoMonolith(final File module, final BufferedWriter monolithWriter,
+										  final boolean nestedModule)
+			throws IOException {
+		final StringBuilder commentLine = new StringBuilder(TLAConstants.CR);
+		final String moduleFilename = module.getName();
+		final int index = moduleFilename.indexOf(TLAConstants.Files.TLA_EXTENSION);
+		final String moduleName;
+		if (index != -1) {
+			moduleName = moduleFilename.substring(0, index);
+		} else {
+			moduleName = moduleFilename;
+		}
+		commentLine.append(TLAConstants.COMMENT).append(TLAConstants.CR);
+		commentLine.append(TLAConstants.COMMENT).append(' ').append(moduleName).append(" follows\n");
+		commentLine.append(TLAConstants.COMMENT).append(TLAConstants.CR).append(TLAConstants.CR);
+		
+		monolithWriter.write(commentLine.toString());
+		
+		final String regex = TLAConstants.MODULE_OPENING_PREFIX_REGEX + moduleName;
+		final Pattern insertingModuleMatcher = Pattern.compile(regex);
+		
+		try (final BufferedReader br = new BufferedReader(new FileReader(module))) {
+			String line;
+			boolean inModuleBody = false;
+			
+			while ((line = br.readLine()) != null) {
+				if (!inModuleBody) {
+					final Matcher m = insertingModuleMatcher.matcher(line);
+
+					inModuleBody = m.find();
+					if (inModuleBody && nestedModule) {
+						monolithWriter.write(NESTED_MODULE_INDENT + line + '\n');
+					}
+				} else {
+					if (!line.trim().startsWith(TLAConstants.KeyWords.EXTENDS)) {
+						final Matcher m = CLOSING_BODY_PATTERN.matcher(line);
+
+						if (m.matches()) {
+							if (nestedModule) {
+								monolithWriter.write(NESTED_MODULE_INDENT + line + '\n');
+							}
+							break;
+						}
+
+						if (!vetoLocalInstanceLine(line)) {
+							if (nestedModule) {
+								monolithWriter.write(NESTED_MODULE_INDENT);
+							}
+							monolithWriter.write(line + '\n');
+						}
+					}
+				}
+			}
+		}
+	}
+	
+	private boolean vetoLocalInstanceLine(final String line) {
+		final Matcher m = LOCAL_INSTANCE_PATTERN.matcher(line);
+		if (m.matches()) {
+			return moduleNamesBeingEmbedded.contains(m.group(1));
+		}
+		return false;
+	}
+	
+	
+	public static void main(final String[] args) {
+		if (args.length == 0) {
+			System.out.println("java tlc2.output.TLAMonolithCreator \\\n"
+									+ "\t[-sourceDir=_directory_containing_spec_tla_] \\\n"
+									+ "\t_specName_");
+			
+			System.exit(-2);
+		}
+		
+		final File sourceDirectory;
+		final String specName;
+		if (args.length == 1) {
+			sourceDirectory = new File(System.getProperty("user.dir"));
+			specName = args[0];
+		} else {
+			sourceDirectory = new File(args[0]);
+			specName = args[1];
+		}
+		final File originalTLA = new File(sourceDirectory, (specName + TLAConstants.Files.TLA_EXTENSION));
+		if (!originalTLA.exists()) {
+			System.out.println("Excepted to find the TLA file but could not: " + originalTLA.getAbsolutePath());
+			
+			System.exit(-3);
+		}
+		
+		final MCParser parser = new MCParser(sourceDirectory, specName, true);
+		final MCParserResults results = parser.parse();
+		
+		final File backupTLA = new File(sourceDirectory, (specName + "_orig" + TLAConstants.Files.TLA_EXTENSION));
+		
+		try {
+			Files.copy(originalTLA.toPath(), backupTLA.toPath(), StandardCopyOption.COPY_ATTRIBUTES);
+		} catch (final IOException ioe) {
+			System.out.println("Exception encountered while making a backup of the original TLA file: "
+									+ ioe.getMessage());
+			
+			System.exit(-1);
+		}
+		
+		try {
+			final ArrayList<File> extendeds = new ArrayList<>();
+			for (final String extended : results.getOriginalExtendedModules()) {
+				extendeds.add(new File(sourceDirectory, (extended + TLAConstants.Files.TLA_EXTENSION)));
+			}
+			
+			final TLAMonolithCreator creator = new TLAMonolithCreator(specName, sourceDirectory, extendeds,
+																	  results.getAllExtendedModules(),
+																	  results.getAllInstantiatedModules());
+			creator.copy();
+			
+			System.out.println("The monolith file is now present at: " + originalTLA.getAbsolutePath());
+		} catch (final IOException ioe) {
+			System.out.println("Exception encountered while making creating the monolith: " + ioe.getMessage());
+			
+			System.exit(-4);
+		} finally {
+			System.out.println("The original TLA file was backed up to: " + backupTLA.getAbsolutePath());
+		}
+	}
+}
diff --git a/tlatools/src/tlc2/output/TeeOutputStream.java b/tlatools/src/tlc2/output/TeeOutputStream.java
new file mode 100644
index 0000000000000000000000000000000000000000..84247e67c25971b58f84c42532a6a4acad379887
--- /dev/null
+++ b/tlatools/src/tlc2/output/TeeOutputStream.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package tlc2.output;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Classic splitter of OutputStream. Named after the unix 'tee' command. It
+ * allows a stream to be branched off so there are now two streams.
+ *
+ * This code is copy-and-pasted from commons-io 2.6
+ */
+public class TeeOutputStream extends FilterOutputStream {
+    /** the second OutputStream to write to */
+    protected OutputStream branch; //TODO consider making this private
+
+    /**
+     * Constructs a TeeOutputStream.
+     * @param out the main OutputStream
+     * @param branch the second OutputStream
+     */
+    public TeeOutputStream(final OutputStream out, final OutputStream branch) {
+        super(out);
+        this.branch = branch;
+    }
+
+    /**
+     * Write the bytes to both streams.
+     * @param b the bytes to write
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public synchronized void write(final byte[] b) throws IOException {
+        out.write(b);
+        this.branch.write(b);
+    }
+
+    /**
+     * Write the specified bytes to both streams.
+     * @param b the bytes to write
+     * @param off The start offset
+     * @param len The number of bytes to write
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public synchronized void write(final byte[] b, final int off, final int len) throws IOException {
+    	out.write(b, off, len);
+        this.branch.write(b, off, len);
+    }
+
+    /**
+     * Write a byte to both streams.
+     * @param b the byte to write
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public synchronized void write(final int b) throws IOException {
+    	out.write(b);
+        this.branch.write(b);
+    }
+
+    /**
+     * Flushes both streams.
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public void flush() throws IOException {
+    	out.flush();
+        this.branch.flush();
+    }
+
+    /**
+     * Closes both output streams.
+     *
+     * If closing the main output stream throws an exception, attempt to close the branch output stream.
+     *
+     * If closing the main and branch output streams both throw exceptions, which exceptions is thrown by this method is
+     * currently unspecified and subject to change.
+     *
+     * @throws IOException
+     *             if an I/O error occurs
+     */
+    @Override
+    public void close() throws IOException {
+        try {
+        	out.close();
+        } finally {
+            this.branch.close();
+        }
+    }
+}
diff --git a/tlatools/src/tlc2/output/messages.properties b/tlatools/src/tlc2/output/messages.properties
index 648e4c06b0491a31f0c33d698b38e77f4ba4e489..e26b31fc964efb984e748d1ef92c66384398d4cc 100644
--- a/tlatools/src/tlc2/output/messages.properties
+++ b/tlatools/src/tlc2/output/messages.properties
@@ -1,53 +1,22 @@
-VersionTag=Version 2.02 of 3 August 2009
-HelpMessage=The model checker (TLC) provides the functionalities of model\n\
-checking or simulation of TLA+ specifications. The syntax for this command is:\n\n\
-java tlc2.TLC [GENERAL-SWITCHES] [MODE-SWITCHES] SPEC\n\n\
-where SPEC is the name of the specification's root module\n\
-and the optional GENERAL-SWITCHES are:\n\
- -checkpoint num: interval between check point (in minutes)\n\
- \tDefaults 30 if not provided.\n\
- -cleanup: clean up the states directory\n\
- -config file: provide the config file.\n\
- \tDefaults to SPEC.cfg if not provided\n\
- -continue: continue running even when invariant is violated\n\
- \tDefaults to stop at the first violation if not specified\n\
- -coverage minutes: interval between collection of coverage information \n\
- \ton the spec in minutes. Defaults to no coverage if not specified\n\
- -deadlock: do not check for deadlock.\n\
- \tDefaults to check deadlock if not specified\n\
- -difftrace: show only the differences between successive states,\n\
- \twhen printing trace. Defaults to print full state descriptions\n\
- -debug: debugging information (not for production use)\n\
- -dump file: dump all the states into file\n\
- -fp num: use the num'th irreducible polynomial from the list \n\
- \tstored in the class FP64.\n\
- -gzip: control if gzip is applied to value input/output stream.\n\
- \tDefaults to off if not specified\n\
- -metadir path: store metadata in the directory at path\n\
- \tDefaults to SPEC-directory/states if not specified\n\
- -recover id: recover from the checkpoint with id\n\
- \tDefaults to scratch run if not specified\n\
- -terse: do not expand values in Print statement\n\
- \tDefaults to expand value if not specified\n\
- -tool: tool mode (put message codes on console)\n\
-  -nowarning: disable all the warnings.\n\
- \tDefaults to report warnings if not specified\n\
- -workers num: the number of TLC worker threads. Defaults to 1.\n\n\
+TLCDescription=\
+The model checker (TLC) provides the functionalities of model checking\n\
+or simulation of TLA+ specifications. It may be invoked from the command\n\
+line, or via the model checking functionality of the Toolbox.\n\n\
 By default, TLC starts in the model checking mode using breadth-first\n\
-approach for the state space exploration. This can be changed using\n\
-the MODE-SWITCHES. In contrast to the GENERAL-SWITCHES these can be used \n\
-if applied in certain combinations only:\n\n\
-{[-dfid num][ -view]|-simulate[ -depth num][ -aril num][ -seed num]}\n\n\
- -modelcheck: run in model checking mode using breadth-first approach for the\n\
- \tstate space exploration (default)\n\
- -dfid num: run in model checking mode and use depth-first iterative deepening\n\
- \twith initial depth num\n\
- -view: apply VIEW (if provided) when printing out states.\n\
- -simulate: run in simulation mode\n\
- -depth num: specify the depth of random simulation\n\
- \tDefaults to 100 if not specified\n\
- -seed num: provide the seed for random simulation\n\
- \tDefaults to a random seed if not specified)\n\
- -aril num: Adjust the seed for random simulation\n\
- \tDefaults to 0 if not specified\n\
- 
\ No newline at end of file
+approach for the state space exploration.
+TraceExplorerDescription=\
+TraceExplorer performs the parsing / consuming of the TLC model checking\n\
+'tool mode' output. With this parsed output, it allows the user to do\n\
+three actions, at this time:\n\
+\to pretty print the error states in a fashion similar to what would\n\
+\t    be seen in the Toolbox\n\
+\to generate a SpecTE tla/cfg file pair which allows a user to then\n\
+\t    work with their model so that it is at the error state\n\
+\to evalute trace expressions at each error state; this action also\n\
+\t    also generates the SpecTE tla/cfg pair if it hasn't already\n\
+\t    been done\n\n\
+TraceExplorer also allows the user to evaluate any single expression\n\
+via the model checker.\n\n\
+If a SpecName is not specified, it is expected that tool output will\n\
+be arriving on stdin; in this case, any specification of -source will\n\
+be ignored.
diff --git a/tlatools/src/tlc2/overrides/Evaluation.java b/tlatools/src/tlc2/overrides/Evaluation.java
new file mode 100644
index 0000000000000000000000000000000000000000..2422f496837c47d71a92c0ff080cc7cb24e193ea
--- /dev/null
+++ b/tlatools/src/tlc2/overrides/Evaluation.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.overrides;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @see EvaluatingValue.
+ */
+@Retention(RUNTIME)
+@Target(METHOD)
+public @interface Evaluation {
+
+	/**
+	 * @return The identifier of a TLA+ state or action predicate. 
+	 */
+	String definition();
+
+	/**
+	 * @return The name of the TLA+ module declaring the definition above.
+	 */
+	String module();
+
+	/**
+	 * @return The minimum level that will be assigned to the OpDefNode that
+	 *         represents the EvaluatingValue in the semantic graph. Unless
+	 *         the actual level checking in Spec.getLevelBound assigns a
+	 *         greater value, the OpDefNode is a constant-level expression if
+	 *         0 causing it to be eagerly evaluated in 
+	 *         SpecProcessor.processConstantDefns.
+	 * @see tla2sany.semantic.LevelNode.getLevel()
+	 * @see tlc2.tool.impl.Spec.getLevelBound(SemanticNode, Context)
+	 * @see tlc2.value.impl.EvaluatingValue
+	 * @see tlc2.tool.impl.SpecProcessor.processConstantDefns()
+	 */
+	int minLevel() default 0;
+	
+	/**
+	 * @return true if a warning should be printed when a EV cannot be mapped to the
+	 *         given TLA+ definition in module.
+	 * @see Evaluation#definition()
+	 * @see Evaluation#module()
+	 */
+	boolean warn() default true;
+}
diff --git a/tlatools/src/tlc2/overrides/ITLCOverrides.java b/tlatools/src/tlc2/overrides/ITLCOverrides.java
new file mode 100644
index 0000000000000000000000000000000000000000..3ac6fb6f0870c8a98ffa204edf71918ea30efa6e
--- /dev/null
+++ b/tlatools/src/tlc2/overrides/ITLCOverrides.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.overrides;
+
+// This is provisional and might change or disappear in future version.
+public interface ITLCOverrides {
+
+	Class[] get();
+
+}
diff --git a/tlatools/src/tlc2/overrides/TLAPlusOperator.java b/tlatools/src/tlc2/overrides/TLAPlusOperator.java
new file mode 100644
index 0000000000000000000000000000000000000000..780c0f8dfa50f1d9b6a4094415a2db02ff8a6565
--- /dev/null
+++ b/tlatools/src/tlc2/overrides/TLAPlusOperator.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.overrides;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @see MethodValue.
+ */
+@Retention(RUNTIME)
+@Target(METHOD)
+public @interface TLAPlusOperator {
+
+	/**
+	 * @return The identifier of a TLA+ operator. 
+	 */
+	String identifier();
+
+	/**
+	 * @return The name of the TLA+ module declaring the definition above.
+	 */
+	String module();
+
+	/**
+	 * @see tlc2.overrides.Evaluation.minLevel()
+	 */
+	int minLevel() default 0;
+	
+	/**
+	 * @return tlc2.overrides.Evaluation.warn()
+	 */
+	boolean warn() default true;
+}
diff --git a/tlatools/src/tlc2/tool/AbstractChecker.java b/tlatools/src/tlc2/tool/AbstractChecker.java
index 692192452bd8883cd191719e39414e5cdc69d94e..0c1c885c517194afa09d6c041d08b9eb6eb70748 100644
--- a/tlatools/src/tlc2/tool/AbstractChecker.java
+++ b/tlatools/src/tlc2/tool/AbstractChecker.java
@@ -12,6 +12,7 @@ import tlc2.output.EC;
 import tlc2.output.MP;
 import tlc2.output.OutputCollector;
 import tlc2.tool.coverage.CostModelCreator;
+import tlc2.tool.impl.FastTool;
 import tlc2.tool.liveness.AddAndCheckLiveCheck;
 import tlc2.tool.liveness.ILiveCheck;
 import tlc2.tool.liveness.LiveCheck;
@@ -104,6 +105,9 @@ public abstract class AbstractChecker
         		// raise warning...
 				MP.printWarning(EC.TLC_FEATURE_UNSUPPORTED_LIVENESS_SYMMETRY);
         	}
+        	if (tool.hasStateOrActionConstraints()) {
+				MP.printWarning(EC.TLC_FEATURE_LIVENESS_CONSTRAINTS);
+        	}
             // Initialization for liveness checking:
             report("initializing liveness checking");
 			IBucketStatistics stats = new DummyBucketStatistics();
diff --git a/tlatools/src/tlc2/tool/CheckImpl.java b/tlatools/src/tlc2/tool/CheckImpl.java
index 608724c3f7acacb4938efabebc491de30e9e3429..9b5b91f5a3e74b9b9343fdcf8aa35b915f78731c 100644
--- a/tlatools/src/tlc2/tool/CheckImpl.java
+++ b/tlatools/src/tlc2/tool/CheckImpl.java
@@ -40,7 +40,7 @@ public abstract class CheckImpl extends ModelChecker {
     this.depth = depth;
     this.curState = null;
     this.coverSet = FPSetFactory.getFPSet();
-    this.coverSet.init(TLCGlobals.getNumWorkers(), this.metadir, tool.getRootFile()+"_cs");
+    this.coverSet.init(TLCGlobals.getNumWorkers(), this.metadir, tool.getRootName()+"_cs");
     this.stateEnum = null;
   }
 
diff --git a/tlatools/src/tlc2/tool/CheckImplFile.java b/tlatools/src/tlc2/tool/CheckImplFile.java
index 14589f908cc7e51e2d995faabecb1de88c7ac29a..b813a91d12f3d2e2031b6c2a2b2939555b32c12f 100644
--- a/tlatools/src/tlc2/tool/CheckImplFile.java
+++ b/tlatools/src/tlc2/tool/CheckImplFile.java
@@ -19,10 +19,11 @@ import tlc2.TLCGlobals;
 import tlc2.output.EC;
 import tlc2.output.MP;
 import tlc2.tool.fp.FPSetConfiguration;
-import tlc2.tool.impl.Tool;
+import tlc2.tool.impl.FastTool;
 import tlc2.util.FP64;
 import util.Assert;
 import util.FileUtil;
+import util.TLAConstants;
 import util.ToolIO;
 import util.UniqueString;
 
@@ -179,9 +180,11 @@ public class CheckImplFile extends CheckImpl
             index++;
             if (index < args.length) {
                 configFile = args[index++];
-                int len = configFile.length();
-                if (configFile.startsWith(".cfg", len-4)) {
-                    configFile = configFile.substring(0, len-4);
+                if (configFile.endsWith(TLAConstants.Files.CONFIG_EXTENSION))
+                {
+                    configFile
+                    	= configFile.substring(0,
+                    			(configFile.length() - TLAConstants.Files.CONFIG_EXTENSION.length()));
                 }
             }
             else {
@@ -285,9 +288,8 @@ public class CheckImplFile extends CheckImpl
                 return;
             }
             mainFile = args[index++];
-            int len = mainFile.length();
-            if (mainFile.startsWith(".tla", len-4)) {
-                mainFile = mainFile.substring(0, len-4);
+            if (mainFile.endsWith(TLAConstants.Files.TLA_EXTENSION)) {
+                mainFile = mainFile.substring(0, (mainFile.length() - TLAConstants.Files.TLA_EXTENSION.length()));
             }
         }
     }
@@ -312,7 +314,7 @@ public class CheckImplFile extends CheckImpl
       FP64.Init(0);
       
       // Start the checker:
-      final ITool tool = new Tool(mainFile, configFile);
+      final ITool tool = new FastTool(mainFile, configFile);
       CheckImplFile checker = new CheckImplFile(tool, metadir, deadlock,
 						depth, fromChkpt, traceFile, new FPSetConfiguration());
       checker.init();
diff --git a/tlatools/src/tlc2/tool/ConcurrentTLCTrace.java b/tlatools/src/tlc2/tool/ConcurrentTLCTrace.java
index cd2a95a479d2459c8e71bc74798e778625f2cf0e..32127c1b07035d2e0d88460f6d9e7c7341961f2e 100644
--- a/tlatools/src/tlc2/tool/ConcurrentTLCTrace.java
+++ b/tlatools/src/tlc2/tool/ConcurrentTLCTrace.java
@@ -59,10 +59,12 @@ public class ConcurrentTLCTrace extends TLCTrace {
 	/**
 	 * @see ConcurrentTLCTrace#getLevel()
 	 */
+	@Override
 	public final int getLevelForReporting() throws IOException {
 		return getLevel();
 	}
 
+	@Override
 	public synchronized final int getLevel() throws IOException {
 		int maxLevel = 1; // With a single, init state the level/progress/diameter is 1, not 0!
 		for (Worker worker : workers) {
@@ -71,7 +73,14 @@ public class ConcurrentTLCTrace extends TLCTrace {
 		return maxLevel;
 	}
 
-	private TLCStateInfo[] getTrace(final TLCState state) throws IOException {
+	/**
+	 * @see TLCTrace#getTrace(LongVec)
+	 */
+	public TLCStateInfo[] getTrace(final TLCState state) throws IOException {
+		if (state.isInitial()) {
+			return new TLCStateInfo[] {new TLCStateInfo(state)};
+		}
+		
 		final LongVec fps = new LongVec();
 
 		// Starting at the given start fingerprint (which is the end of the
diff --git a/tlatools/src/tlc2/tool/DFIDModelChecker.java b/tlatools/src/tlc2/tool/DFIDModelChecker.java
index 8b0f2d1e7eec8fb16a694ff22d39b708df6b1871..404fc7b6b66873cd7bc9a3377afb7595a256bff1 100644
--- a/tlatools/src/tlc2/tool/DFIDModelChecker.java
+++ b/tlatools/src/tlc2/tool/DFIDModelChecker.java
@@ -14,6 +14,7 @@ import tlc2.output.EC;
 import tlc2.output.MP;
 import tlc2.tool.fp.dfid.FPIntSet;
 import tlc2.tool.fp.dfid.MemFPIntSet;
+import tlc2.tool.impl.CallStackTool;
 import tlc2.tool.liveness.LiveException;
 import tlc2.util.IStateWriter;
 import tlc2.util.IdThread;
@@ -99,14 +100,13 @@ public class DFIDModelChecker extends AbstractChecker
             }
 
             // Replay the error with the error stack recorded:
-            this.tool.setCallStack();
             try
             {
                 this.numOfGenStates.set(0);
-                this.doInit(true);
+                this.doInit(new CallStackTool(this.tool), true);
             } catch (Throwable e1)
             {
-                result = MP.printError(EC.TLC_NESTED_EXPRESSION, this.tool.getCallStack().toString());
+                result = MP.printError(EC.TLC_NESTED_EXPRESSION, this.tool.toString());
             }
             this.printSummary(false);
             this.cleanup(false);
@@ -165,14 +165,14 @@ public class DFIDModelChecker extends AbstractChecker
                     } else if (this.keepCallStack)
                     {
                         // Replay the error with the error stack recorded:
-                        this.tool.setCallStack();
+                    	final CallStackTool cTool = new CallStackTool(this.tool);
                         try
                         {
-                            this.doNext(this.predErrState, this.predErrState.fingerPrint(), true,
+							this.doNext(cTool, this.predErrState, this.predErrState.fingerPrint(), true,
                                     new StateVec(1), new LongVec());
                         } catch (Throwable e)
                         {
-                            MP.printError(EC.TLC_NESTED_EXPRESSION, this.tool.getCallStack().toString());
+                            MP.printError(EC.TLC_NESTED_EXPRESSION, cTool.toString());
                         }
                     }
                     break;
@@ -256,13 +256,16 @@ public class DFIDModelChecker extends AbstractChecker
 
     /* Compute the set of initial states.  */
     // SZ Feb 23, 2009: added ignore cancel flag
-    public final int doInit(boolean ignoreCancel) throws Throwable
+    public final int doInit(boolean ignoreCancel) throws Throwable {
+    	return doInit(this.tool, ignoreCancel);
+    }
+    private final int doInit(final ITool tool, boolean ignoreCancel) throws Throwable
     {
         TLCState curState = null;
         try
         {
             // Generate the initial states:
-            StateVec states = this.tool.getInitStates();
+            StateVec states = tool.getInitStates();
             this.numOfGenStates.set(states.size());
             final long l = this.numOfGenStates.get();
             //TODO casting to int is potentially dangerous
@@ -273,11 +276,11 @@ public class DFIDModelChecker extends AbstractChecker
             {
                 curState = states.elementAt(i);
                 // Check if the state is a legal state
-                if (!this.tool.isGoodState(curState))
+                if (!tool.isGoodState(curState))
                 {
                     return MP.printError(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_INITIAL, curState.toString());
                 }
-                boolean inModel = this.tool.isInModel(curState);
+                boolean inModel = tool.isInModel(curState);
                 int status = FPIntSet.NEW;
                 if (inModel)
                 {
@@ -301,24 +304,24 @@ public class DFIDModelChecker extends AbstractChecker
                 // Check properties of the state:
                 if (status == FPIntSet.NEW)
                 {
-                    for (int j = 0; j < this.tool.getInvariants().length; j++)
+                    for (int j = 0; j < tool.getInvariants().length; j++)
                     {
-                        if (!this.tool.isValid(this.tool.getInvariants()[j], curState))
+                        if (!tool.isValid(tool.getInvariants()[j], curState))
                         {
                             // We get here because of invariant violation:
-                            MP.printError(EC.TLC_INVARIANT_VIOLATED_INITIAL, new String[] { this.tool.getInvNames()[j],
+                            MP.printError(EC.TLC_INVARIANT_VIOLATED_INITIAL, new String[] { tool.getInvNames()[j],
                                     curState.toString() });
                             if (!TLCGlobals.continuation)
                                 return EC.TLC_INVARIANT_VIOLATED_INITIAL;
                         }
                     }
-                    for (int j = 0; j < this.tool.getImpliedInits().length; j++)
+                    for (int j = 0; j < tool.getImpliedInits().length; j++)
                     {
-                        if (!this.tool.isValid(this.tool.getImpliedInits()[j], curState))
+                        if (!tool.isValid(tool.getImpliedInits()[j], curState))
                         {
                             // We get here because of implied-inits violation:
                             return MP.printError(EC.TLC_PROPERTY_VIOLATED_INITIAL, new String[] {
-                                    this.tool.getImpliedInitNames()[j], curState.toString() });
+                                    tool.getImpliedInitNames()[j], curState.toString() });
                         }
                     }
                 }
@@ -355,6 +358,10 @@ public class DFIDModelChecker extends AbstractChecker
      * successor of curState.
      */
     public final boolean doNext(TLCState curState, long cfp, boolean isLeaf, StateVec states,
+            LongVec fps) throws Throwable {
+    	return doNext(this.tool, curState, cfp, isLeaf, states, fps);
+    }
+    public final boolean doNext(final ITool tool, TLCState curState, long cfp, boolean isLeaf, StateVec states,
             LongVec fps) throws Throwable
     {
         boolean deadLocked = true;
@@ -371,9 +378,9 @@ public class DFIDModelChecker extends AbstractChecker
             int k = 0;
             boolean allSuccDone = true;
             boolean allSuccNonLeaf = true;
-            for (int i = 0; i < this.tool.getActions().length; i++)
+            for (int i = 0; i < tool.getActions().length; i++)
             {
-                StateVec nextStates = this.tool.getNextStates(this.tool.getActions()[i], curState);
+                StateVec nextStates = tool.getNextStates(tool.getActions()[i], curState);
                 int sz = nextStates.size();
                 this.numOfGenStates.getAndAdd(sz);
                 deadLocked = deadLocked && (sz == 0);
@@ -382,19 +389,19 @@ public class DFIDModelChecker extends AbstractChecker
                 {
                     succState = nextStates.elementAt(j);
                     // Check if the state is a legal state.
-                    if (!this.tool.isGoodState(succState))
+                    if (!tool.isGoodState(succState))
                     {
 						synchronized (this) {
                             final int errorCode = EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT;
 							if (this.setErrState(curState, succState, false, errorCode)) {
 								final Set<OpDeclNode> unassigned = succState.getUnassigned();
 								String[] parameters;
-								if (this.tool.getActions().length == 1) {
+								if (tool.getActions().length == 1) {
 									parameters = new String[] { unassigned.size() > 1 ? "s are" : " is",
 											unassigned.stream().map(n -> n.getName().toString())
 													.collect(Collectors.joining(", ")) };
 								} else {
-									parameters = new String[] { this.tool.getActions()[i].getName().toString(),
+									parameters = new String[] { tool.getActions()[i].getName().toString(),
 											unassigned.size() > 1 ? "s are" : " is",
 											unassigned.stream().map(n -> n.getName().toString())
 													.collect(Collectors.joining(", ")) };
@@ -405,7 +412,7 @@ public class DFIDModelChecker extends AbstractChecker
                         return allSuccNonLeaf;
                     }
 
-                    boolean inModel = (this.tool.isInModel(succState) && this.tool.isInActions(curState, succState));
+                    boolean inModel = (tool.isInModel(succState) && tool.isInActions(curState, succState));
                     int status = FPIntSet.NEW;
                     if (inModel)
                     {
@@ -436,10 +443,10 @@ public class DFIDModelChecker extends AbstractChecker
                     {
                         try
                         {
-                            int len = this.tool.getInvariants().length;
+                            int len = tool.getInvariants().length;
                             for (k = 0; k < len; k++)
                             {
-                                if (!tool.isValid(this.tool.getInvariants()[k], succState))
+                                if (!tool.isValid(tool.getInvariants()[k], succState))
                                 {
                                     // We get here because of invariant violation:
                                     synchronized (this)
@@ -447,14 +454,14 @@ public class DFIDModelChecker extends AbstractChecker
                                         if (TLCGlobals.continuation)
                                         {
                                             this.printTrace(EC.TLC_INVARIANT_VIOLATED_BEHAVIOR,
-                                                    new String[] { this.tool.getInvNames()[k] }, curState, succState);
+                                                    new String[] { tool.getInvNames()[k] }, curState, succState);
                                             break;
                                         } else
                                         {
                                             if (this.setErrState(curState, succState, false, EC.TLC_INVARIANT_VIOLATED_BEHAVIOR))
                                             {
                                                 this.printTrace(EC.TLC_INVARIANT_VIOLATED_BEHAVIOR,
-                                                        new String[] { this.tool.getInvNames()[k] }, curState,
+                                                        new String[] { tool.getInvNames()[k] }, curState,
                                                         succState);
                                                 this.notify();
                                             }
@@ -470,7 +477,7 @@ public class DFIDModelChecker extends AbstractChecker
                         	synchronized (this) {
 		                        if (this.setErrState(curState, succState, true, EC.TLC_INVARIANT_EVALUATION_FAILED))
 		                        {
-		                            this.printTrace(EC.TLC_INVARIANT_EVALUATION_FAILED, new String[] { this.tool
+		                            this.printTrace(EC.TLC_INVARIANT_EVALUATION_FAILED, new String[] { tool
 		                                    .getInvNames()[k] }, curState, succState);
 		                            this.notify();
 		                        }
@@ -482,10 +489,10 @@ public class DFIDModelChecker extends AbstractChecker
                     // even if succState is not new.
                     try
                     {
-                        int len = this.tool.getImpliedActions().length;
+                        int len = tool.getImpliedActions().length;
                         for (k = 0; k < len; k++)
                         {
-                            if (!tool.isValid(this.tool.getImpliedActions()[k], curState, succState))
+                            if (!tool.isValid(tool.getImpliedActions()[k], curState, succState))
                             {
                                 // We get here because of implied-action violation:
                                 synchronized (this)
@@ -494,7 +501,7 @@ public class DFIDModelChecker extends AbstractChecker
                                     {
                                         this
                                                 .printTrace(EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR,
-                                                        new String[] { this.tool.getImpliedActNames()[k] }, curState,
+                                                        new String[] { tool.getImpliedActNames()[k] }, curState,
                                                         succState);
                                         break;
                                     } else
@@ -502,7 +509,7 @@ public class DFIDModelChecker extends AbstractChecker
                                         if (this.setErrState(curState, succState, false, EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR))
                                         {
                                             this.printTrace(EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR,
-                                                    new String[] { this.tool.getImpliedActNames()[k] }, curState,
+                                                    new String[] { tool.getImpliedActNames()[k] }, curState,
                                                     succState);
                                             this.notify();
                                         }
@@ -518,7 +525,7 @@ public class DFIDModelChecker extends AbstractChecker
                     	synchronized (this) {
 		                    if (this.setErrState(curState, succState, true, EC.TLC_ACTION_PROPERTY_EVALUATION_FAILED))
 		                    {
-		                        this.printTrace(EC.TLC_ACTION_PROPERTY_EVALUATION_FAILED, new String[] { this.tool
+		                        this.printTrace(EC.TLC_ACTION_PROPERTY_EVALUATION_FAILED, new String[] { tool
 		                                .getImpliedActNames()[k] }, curState, succState);
 		                        this.notify();
 		                    }
diff --git a/tlatools/src/tlc2/tool/INextStateFunctor.java b/tlatools/src/tlc2/tool/INextStateFunctor.java
new file mode 100644
index 0000000000000000000000000000000000000000..4412d89f06590b411d1fda2be78a2ea8abda8e99
--- /dev/null
+++ b/tlatools/src/tlc2/tool/INextStateFunctor.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool;
+
+public interface INextStateFunctor extends IStateFunctor {
+
+	Object addElement(final TLCState s, final Action a, final TLCState t);
+	
+	public static class InvariantViolatedException extends RuntimeException {
+		
+	}
+}
diff --git a/tlatools/src/tlc2/tool/ITool.java b/tlatools/src/tlc2/tool/ITool.java
index 8c09e43110c7da49051b1374d04d6f11cc742ea8..604a3829381ffc1b1de28bbb43828f37792a5f70 100644
--- a/tlatools/src/tlc2/tool/ITool.java
+++ b/tlatools/src/tlc2/tool/ITool.java
@@ -46,10 +46,6 @@ import util.FilenameToStream;
 
 public interface ITool extends TraceApp {
 
-	void setCallStack();
-
-	CallStack getCallStack();
-
 	/**
 	   * This method returns the set of all possible actions of the
 	   * spec, and sets the actions field of this object. In fact, we
@@ -78,6 +74,8 @@ public interface ITool extends TraceApp {
 	   * in the given state.
 	   */
 	StateVec getNextStates(Action action, TLCState state);
+	
+	boolean getNextStates(final INextStateFunctor functor, final TLCState state);
 
 	IValue eval(SemanticNode expr, Context c, TLCState s0);
 
@@ -98,6 +96,8 @@ public interface ITool extends TraceApp {
 	/* This method determines if a pair of states satisfy the action constraints. */
 	boolean isInActions(TLCState s1, TLCState s2) throws EvalException;
 
+	boolean hasStateOrActionConstraints();
+
 	/**
 	   * This method determines if an action is enabled in the given state.
 	   * More precisely, it determines if (act.pred /\ (sub' # sub)) is
@@ -165,6 +165,15 @@ public interface ITool extends TraceApp {
 
 	String[] getImpliedActNames();
 
+	/**
+	 * @return The name of the root module.
+	 */
+	String getRootName();
+	
+	/**
+	 * @return The file name of the root module which might contain the
+	 *         full or relative path information.
+	 */
 	String getRootFile();
 
 	ModuleNode getRootModule();
diff --git a/tlatools/src/tlc2/tool/ModelChecker.java b/tlatools/src/tlc2/tool/ModelChecker.java
index ac740d5573214ed9eb32742e083d459e6a7db67c..22f3c315b00a83c8092bb79d721d01b4cef390f7 100644
--- a/tlatools/src/tlc2/tool/ModelChecker.java
+++ b/tlatools/src/tlc2/tool/ModelChecker.java
@@ -23,6 +23,7 @@ import tlc2.output.OutputCollector;
 import tlc2.tool.fp.FPSet;
 import tlc2.tool.fp.FPSetConfiguration;
 import tlc2.tool.fp.FPSetFactory;
+import tlc2.tool.impl.CallStackTool;
 import tlc2.tool.liveness.LiveCheck;
 import tlc2.tool.queue.DiskByteArrayQueue;
 import tlc2.tool.queue.DiskStateQueue;
@@ -34,6 +35,7 @@ import util.Assert;
 import util.DebugPrinter;
 import util.FileUtil;
 import util.FilenameToStream;
+import util.TLAFlightRecorder;
 import util.UniqueString;
 
 /** 
@@ -74,12 +76,26 @@ public class ModelChecker extends AbstractChecker
             final Future<FPSet> future, long startTime) throws EvalException, IOException, InterruptedException, ExecutionException {
     	this(tool, metadir, stateWriter, deadlock, fromChkpt, startTime);
     	this.theFPSet = future.get();
+
+        // Initialize all the workers:
+        this.workers = new Worker[TLCGlobals.getNumWorkers()];
+        for (int i = 0; i < this.workers.length; i++)
+        {
+            this.workers[i] = this.trace.addWorker(new Worker(i, this, this.metadir, this.tool.getRootName()));
+        }
     }
     
     public ModelChecker(ITool tool, String metadir, final IStateWriter stateWriter, boolean deadlock, String fromChkpt,
             final FPSetConfiguration fpSetConfig, long startTime) throws EvalException, IOException {
     	this(tool, metadir, stateWriter, deadlock, fromChkpt, startTime);
-    	this.theFPSet = FPSetFactory.getFPSet(fpSetConfig).init(TLCGlobals.getNumWorkers(), metadir, tool.getRootFile());
+    	this.theFPSet = FPSetFactory.getFPSet(fpSetConfig).init(TLCGlobals.getNumWorkers(), metadir, tool.getRootName());
+
+        // Initialize all the workers:
+        this.workers = new Worker[TLCGlobals.getNumWorkers()];
+        for (int i = 0; i < this.workers.length; i++)
+        {
+            this.workers[i] = this.trace.addWorker(new Worker(i, this, this.metadir, this.tool.getRootName()));
+        }
     }
     
     /**
@@ -99,14 +115,7 @@ public class ModelChecker extends AbstractChecker
         // this.theStateQueue = new MemStateQueue(this.metadir);
 
         // Finally, initialize the trace file:
-        this.trace = new ConcurrentTLCTrace(this.metadir, this.tool.getRootFile(), this.tool);
-
-        // Initialize all the workers:
-        this.workers = new Worker[TLCGlobals.getNumWorkers()];
-        for (int i = 0; i < this.workers.length; i++)
-        {
-            this.workers[i] = this.trace.addWorker(new Worker(i, this, this.metadir, this.tool.getRootFile()));
-        }
+        this.trace = new ConcurrentTLCTrace(this.metadir, this.tool.getRootName(), this.tool);
     }
 
     /**
@@ -176,17 +185,17 @@ public class ModelChecker extends AbstractChecker
                 }
 
                 // Replay the error with the error stack recorded:
-                this.tool.setCallStack();
+                final CallStackTool cTool = new CallStackTool(this.tool);
                 try
                 {
                     numberOfInitialStates = 0;
                     // SZ Feb 23, 2009: ignore cancel on error reporting
-                    this.doInit(true);
+					this.doInit(cTool, true);
                 } catch (FingerprintException fe){
                     result = MP.printError(EC.TLC_FINGERPRINT_EXCEPTION, new String[]{fe.getTrace(), fe.getRootCause().getMessage()});
                 } catch (Throwable e1) {
                     // Assert.printStack(e);
-                    result = MP.printError(EC.TLC_NESTED_EXPRESSION, this.tool.getCallStack().toString());
+                    result = MP.printError(EC.TLC_NESTED_EXPRESSION, cTool.toString());
                 }
                 this.printSummary(false, startTime);
                 this.cleanup(false);
@@ -263,21 +272,21 @@ public class ModelChecker extends AbstractChecker
             } else if (this.keepCallStack)
             {
                 // Replay the error with the error stack recorded:
-                this.tool.setCallStack();
+            	final CallStackTool cTool = new CallStackTool(this.tool);
                 try
                 {
 					// Not adding newly created Worker to trace#addWorker because it is not supposed
 					// to rewrite the trace file but to reconstruct actual states referenced by
 					// their fingerprints in the trace.
-					this.doNext(this.predErrState, this.checkLiveness ? new SetOfStates() : null,
-							new Worker(4223, this, this.metadir, tool.getRootFile()));
+					this.doNext(cTool, this.predErrState, this.checkLiveness ? new SetOfStates() : null,
+							new Worker(4223, this, this.metadir, tool.getRootName()));
                 } catch (FingerprintException e)
                 {
                     result = MP.printError(EC.TLC_FINGERPRINT_EXCEPTION, new String[]{e.getTrace(), e.getRootCause().getMessage()});
                 } catch (Throwable e)
                 {
                     // Assert.printStack(e);
-                    result = MP.printError(EC.TLC_NESTED_EXPRESSION, this.tool.getCallStack().toString());
+                    result = MP.printError(EC.TLC_NESTED_EXPRESSION, cTool.toString());
                 }
             }
         } catch (Exception e)
@@ -343,7 +352,12 @@ public class ModelChecker extends AbstractChecker
      * @return status, if false, the processing should be stopped
      * @throws Throwable
      */
-    public final int doInit(boolean ignoreCancel) throws Throwable
+    @Override
+    public final int doInit(boolean ignoreCancel) throws Throwable {
+    	return doInit(this.tool, ignoreCancel);
+    }
+    
+    private final int doInit(final ITool tool, boolean ignoreCancel) throws Throwable
     {
 		// Generate the initial states.
         //
@@ -358,12 +372,12 @@ public class ModelChecker extends AbstractChecker
 			// Rerunning state space exploration to reconstruct the error stack to determine
 			// what caused Tool to fail to evaluate the init predicate expressions. Thus,
 			// re-check all invariants even if state is already known (= part of theFPSet).
-        	functor = new DoInitFunctor(ignoreCancel);
+        	functor = new DoInitFunctor(tool, ignoreCancel);
         } else {
-        	functor = new DoInitFunctor();
+        	functor = new DoInitFunctor(tool);
         }
 		try {
-			this.tool.getInitStates(functor);
+			tool.getInitStates(functor);
 		} catch (DoInitFunctor.InvariantViolatedException ive) {
 			this.errState = functor.errState;
 			return functor.returnValue;
@@ -393,27 +407,16 @@ public class ModelChecker extends AbstractChecker
      * 
      * This method is called from the workers on every step
      */
-    public final boolean doNext(TLCState curState, final SetOfStates liveNextStates, final Worker worker) throws Throwable
+    private final boolean doNext(final ITool tool, TLCState curState, final SetOfStates liveNextStates, final Worker worker) throws Throwable
     {
         boolean deadLocked = true;
         TLCState succState = null;
         try
         {
-            for (int i = 0; i < this.tool.getActions().length; i++)
+            for (int i = 0; i < tool.getActions().length; i++)
             {
-				//TODO Implement IStateFunctor pattern for getNextStates() too
-				// to reduce memory and runtime overhead of allocating and
-				// looping StateVec. However - contrary to doInit() - doNext()
-				// is incompatible to the functor when liveness checking is
-				// turned on. Liveness checking does not support adding
-				// nextStates one-by-one but expects to be given the whole set
-				// of nextStates in a single invocation
-				// (LiveCheck#addNextState(..). If this limitation is ever
-				// removed, the functor pattern could be applied to doNext too.
-				// Other problems are access to worker and curState. A stateless functor has no
-				// access to curState and worker except when it uses thread local storage.
-				final Action action = this.tool.getActions()[i];
-				final StateVec nextStates = this.tool.getNextStates(action, curState);
+				final Action action = tool.getActions()[i];
+				final StateVec nextStates = tool.getNextStates(action, curState);
 				final int sz = nextStates.size();
 				worker.incrementStatesGenerated(sz);
 				deadLocked = deadLocked && (sz == 0);
@@ -422,30 +425,30 @@ public class ModelChecker extends AbstractChecker
                 {
 					succState = nextStates.elementAt(j);
 					// Check if succState is a legal state.
-                    if (!this.tool.isGoodState(succState))
+                    if (!tool.isGoodState(succState))
                     {
                     	return doNextSetErr(curState, succState, action);
 					}
 
-					final boolean inModel = (this.tool.isInModel(succState) && this.tool.isInActions(curState, succState));
-					boolean seen = false;
+					final boolean inModel = (tool.isInModel(succState) && tool.isInActions(curState, succState));
+					boolean unseen = true;
                     if (inModel)
                     {
-						seen = isSeenState(curState, worker, succState, liveNextStates, action);
+						unseen = !isSeenState(curState, succState, action, worker, liveNextStates);
 					}
-					// Check if succState violates any invariant:
-                    if (!seen)
+					// Check if an unseen succState violates any invariant:
+                    if (unseen)
                     {
-                    	if (doNextCheckInvariants(curState, succState, inModel, seen)) {
+                    	if (doNextCheckInvariants(tool, curState, succState)) {
                     		return true;
                     	}
 					}
                     // Check if the state violates any implied action. We need to do it
                     // even if succState is not new.
-                    if (doNextCheckImplied(curState, succState, inModel, seen)) {
+                    if (doNextCheckImplied(tool, curState, succState)) {
                     	return true;
                     }
-                    if (inModel && !seen) {
+                    if (inModel && unseen) {
 						// The state is inModel, unseen and neither invariants
 						// nor implied actions are violated. It is thus eligible
 						// for further processing by other workers.
@@ -468,8 +471,8 @@ public class ModelChecker extends AbstractChecker
 		}
     }
 
-	private final boolean isSeenState(final TLCState curState, final Worker worker, final TLCState succState,
-			final SetOfStates liveNextStates, final Action action) throws IOException {
+	private final boolean isSeenState(final TLCState curState, final TLCState succState,
+			final Action action, final Worker worker, final SetOfStates liveNextStates) throws IOException {
 		final long fp = succState.fingerPrint();
 		final boolean seen = this.theFPSet.put(fp);
 		// Write out succState when needed:
@@ -497,51 +500,51 @@ public class ModelChecker extends AbstractChecker
 		return seen;
 	}
 
-	private final boolean doNextCheckInvariants(final TLCState curState, final TLCState succState, final boolean inModel, final boolean seen) throws IOException, WorkerException, Exception {
+	private final boolean doNextCheckInvariants(final ITool tool, final TLCState curState, final TLCState succState) throws IOException, WorkerException, Exception {
         int k = 0;
 		try
         {
-			for (k = 0; k < this.tool.getInvariants().length; k++)
+			for (k = 0; k < tool.getInvariants().length; k++)
             {
-                if (!tool.isValid(this.tool.getInvariants()[k], succState))
+                if (!tool.isValid(tool.getInvariants()[k], succState))
                 {
                     // We get here because of invariant violation:
                 	if (TLCGlobals.continuation) {
                         synchronized (this)
                         {
 							MP.printError(EC.TLC_INVARIANT_VIOLATED_BEHAVIOR,
-									this.tool.getInvNames()[k]);
+									tool.getInvNames()[k]);
 							this.trace.printTrace(curState, succState);
 							return false;
                         }
                 	} else {
 						return doNextSetErr(curState, succState, false,
-								EC.TLC_INVARIANT_VIOLATED_BEHAVIOR, this.tool.getInvNames()[k]);
+								EC.TLC_INVARIANT_VIOLATED_BEHAVIOR, tool.getInvNames()[k]);
                 	}
 				}
 			}
         } catch (Exception e)
         {
 			doNextEvalFailed(curState, succState, EC.TLC_INVARIANT_EVALUATION_FAILED,
-					this.tool.getInvNames()[k], e);
+					tool.getInvNames()[k], e);
 		}
 		return false;
 	}
 
-	private final boolean doNextCheckImplied(final TLCState curState, final TLCState succState, final boolean inModel, boolean seen) throws IOException, WorkerException, Exception {
+	private final boolean doNextCheckImplied(final ITool tool, final TLCState curState, final TLCState succState) throws IOException, WorkerException, Exception {
 		int k = 0;
         try
         {
-			for (k = 0; k < this.tool.getImpliedActions().length; k++)
+			for (k = 0; k < tool.getImpliedActions().length; k++)
             {
-                if (!tool.isValid(this.tool.getImpliedActions()[k], curState, succState))
+                if (!tool.isValid(tool.getImpliedActions()[k], curState, succState))
                 {
                     // We get here because of implied-action violation:
                     if (TLCGlobals.continuation)
                     {
                         synchronized (this)
                         {
-                            MP.printError(EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR, this.tool
+                            MP.printError(EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR, tool
                                     .getImpliedActNames()[k]);
 							this.trace.printTrace(curState, succState);
 							return false;
@@ -549,19 +552,19 @@ public class ModelChecker extends AbstractChecker
                     } else {
 						return doNextSetErr(curState, succState, false,
 								EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR,
-								this.tool.getImpliedActNames()[k]);
+								tool.getImpliedActNames()[k]);
                 	}
 				}
 			}
         } catch (Exception e)
         {
 			doNextEvalFailed(curState, succState, EC.TLC_ACTION_PROPERTY_EVALUATION_FAILED,
-					this.tool.getImpliedActNames()[k], e);
+					tool.getImpliedActNames()[k], e);
 		}
         return false;
 	}
 
-	private final boolean doNextSetErr(TLCState curState, TLCState succState, boolean keep, int ec, String param) throws IOException, WorkerException {
+	final boolean doNextSetErr(TLCState curState, TLCState succState, boolean keep, int ec, String param) throws IOException, WorkerException {
 		synchronized (this)
 		{
 		    if (this.setErrState(curState, succState, keep, ec))
@@ -579,7 +582,7 @@ public class ModelChecker extends AbstractChecker
 		return true;
 	}
 
-	private final boolean doNextSetErr(TLCState curState, TLCState succState, Action action) throws IOException, WorkerException {
+	final boolean doNextSetErr(TLCState curState, TLCState succState, Action action) throws IOException, WorkerException {
 		synchronized (this) {
 			final int errorCode = EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT;
 			if (this.setErrState(curState, succState, false, errorCode))
@@ -605,7 +608,7 @@ public class ModelChecker extends AbstractChecker
 		}
 	}
 
-	private final void doNextEvalFailed(TLCState curState, TLCState succState, int ec, String param, Exception e)
+	final void doNextEvalFailed(TLCState curState, TLCState succState, int ec, String param, Exception e)
 			throws IOException, WorkerException, Exception {
 		synchronized (this) {
 		    if (this.setErrState(curState, succState, true, ec))
@@ -619,7 +622,7 @@ public class ModelChecker extends AbstractChecker
 		}
 	}
 
-	private final void doNextFailed(TLCState curState, TLCState succState, Throwable e)
+	final void doNextFailed(TLCState curState, TLCState succState, Throwable e)
 			throws IOException, WorkerException, Throwable {
 		// Assert.printStack(e);
 		final boolean keep = ((e instanceof StackOverflowError) || (e instanceof OutOfMemoryError)
@@ -840,7 +843,7 @@ public class ModelChecker extends AbstractChecker
          */
         if (TLCGlobals.tool)
         {	
-        	printProgresStats(startTime);
+        	printProgresStats(startTime, true);
         }
 
         MP.printMessage(EC.TLC_STATS, new String[] { String.valueOf(getStatesGenerated()),
@@ -865,7 +868,7 @@ public class ModelChecker extends AbstractChecker
         }
     }
     
-    private final void printProgresStats(final long startTime) throws IOException {
+    private final void printProgresStats(final long startTime, final boolean isFinal) throws IOException {
         final long fpSetSize = this.theFPSet.size();
         
         // print progress showing states per minute metric (spm)
@@ -891,6 +894,9 @@ public class ModelChecker extends AbstractChecker
                 MP.format(this.theStateQueue.size()),
                 MP.format(statesPerMinute),
                 MP.format(distinctStatesPerMinute) });
+		
+		TLAFlightRecorder.progress(isFinal, this.trace.getLevelForReporting(), l, fpSetSize, this.theStateQueue.size(),
+				statesPerMinute, distinctStatesPerMinute);
     }
 
     public static final void reportSuccess(final FPSet anFpSet, final long numOfGenStates) throws IOException
@@ -944,7 +950,7 @@ public class ModelChecker extends AbstractChecker
     {
         final int level = this.trace.getLevel();
         
-    	printProgresStats(-1);
+    	printProgresStats(-1, false);
         
         if (level > depth)
         {
@@ -1077,13 +1083,15 @@ public class ModelChecker extends AbstractChecker
 		private int returnValue = EC.NO_ERROR;
 		
 		private final boolean forceChecks;
+		private final ITool tool;
 		
-		public DoInitFunctor() {
-			this(false);
+		public DoInitFunctor(ITool tool) {
+			this(tool, false);
 		}
 		
-		public DoInitFunctor(boolean forceChecks) {
+		public DoInitFunctor(ITool tool, boolean forceChecks) {
 			this.forceChecks = forceChecks;
+			this.tool = tool;
 		}
 
 		/* (non-Javadoc)
diff --git a/tlatools/src/tlc2/tool/SimulationWorker.java b/tlatools/src/tlc2/tool/SimulationWorker.java
index cd30ab8cd3692009fcd9f90a4af9ca9e9df67924..64a4940fcebd3df054ebb73628cf3758986bb43e 100644
--- a/tlatools/src/tlc2/tool/SimulationWorker.java
+++ b/tlatools/src/tlc2/tool/SimulationWorker.java
@@ -32,6 +32,7 @@ import java.util.concurrent.atomic.LongAdder;
 
 import tlc2.output.EC;
 import tlc2.tool.liveness.ILiveCheck;
+import tlc2.util.IdThread;
 import tlc2.util.RandomGenerator;
 import util.FileUtil;
 
@@ -55,7 +56,7 @@ import util.FileUtil;
  * OK result onto its result queue. This acts as a way to signal external
  * clients that this thread has terminated.
  */
-public class SimulationWorker extends Thread {
+public class SimulationWorker extends IdThread {
 	
 	// This worker's local source of randomness.
 	final RandomGenerator localRng;
@@ -65,9 +66,6 @@ public class SimulationWorker extends Thread {
 
 	// Stores a trace generated by this worker.
 	StateVec stateTrace;
-
-	// A unique id for this worker thread.
-	private int id;
 	
 	// The set of initial states for the spec. 
 	private final StateVec initStates;
@@ -186,7 +184,7 @@ public class SimulationWorker extends Thread {
 	public SimulationWorker(int id, ITool tool, StateVec initStates, BlockingQueue<SimulationWorkerResult> resultQueue,
 			long seed, long maxTraceDepth, long maxTraceNum, boolean checkDeadlock, String traceFile,
 			ILiveCheck liveCheck, LongAdder numOfGenStates, LongAdder numOfGenTraces) {
-		this.id = id;
+		super(id);
 		this.localRng = new RandomGenerator(seed);
 		this.tool = tool;
 		this.maxTraceDepth = maxTraceDepth;
@@ -222,21 +220,21 @@ public class SimulationWorker extends Thread {
 				// If we have an error result, place it on the output queue.
 				if (res.isPresent()) {
 					final SimulationWorkerError err = res.get();
-					resultQueue.put(SimulationWorkerResult.Error(this.id, err));
+					resultQueue.put(SimulationWorkerResult.Error(this.myGetId(), err));
 				}
 
 				// Abide by the maximum trace generation count.
 				if (traceCnt >= maxTraceNum) {
-					resultQueue.put(SimulationWorkerResult.OK(this.id));
+					resultQueue.put(SimulationWorkerResult.OK(this.myGetId()));
 					return;
 				}
 			} catch (final InterruptedException e) {
 				// Gracefully terminate if we were interrupted.
-				resultQueue.offer(SimulationWorkerResult.OK(this.id));
+				resultQueue.offer(SimulationWorkerResult.OK(this.myGetId()));
 				return;
 			} catch (final Exception e) {
 				final SimulationWorkerError err = new SimulationWorkerError(0, null, this.curState, this.stateTrace, e);
-				resultQueue.offer(SimulationWorkerResult.Error(this.id, err));
+				resultQueue.offer(SimulationWorkerResult.Error(this.myGetId(), err));
 				return;
 			}	
 		}
@@ -304,6 +302,7 @@ public class SimulationWorker extends Thread {
 
 		// a) Randomly select a state from the set of init states.
 		curState = randomState(this.localRng, initStates);
+		setCurrentState(curState);
 		
 		boolean inConstraints = tool.isInModel(curState);
 
@@ -380,7 +379,9 @@ public class SimulationWorker extends Thread {
 			// iteration of the loop.
 			final TLCState s1 = randomState(localRng, nextStates);
 			inConstraints = (tool.isInModel(s1) && tool.isInActions(curState, s1));
+			s1.setPredecessor(curState);
 			curState = s1;
+			setCurrentState(curState);
 		}
 
 		// Check for interruption once more before entering liveness checking.
@@ -394,7 +395,7 @@ public class SimulationWorker extends Thread {
 		// format of TLA module, so that it can be read by TLC again.
 		if (traceFile != null) {
 			// Make sure each worker outputs to its own set of trace files.
-			final String fileName = traceFile + "_" + String.valueOf(this.id) + "_" + this.traceCnt;
+			final String fileName = traceFile + "_" + String.valueOf(this.myGetId()) + "_" + this.traceCnt;
 			// TODO is it ok here?
 			final PrintWriter pw = new PrintWriter(FileUtil.newBFOS(fileName));
 			pw.println("---------------- MODULE " + fileName + " -----------------");
diff --git a/tlatools/src/tlc2/tool/Simulator.java b/tlatools/src/tlc2/tool/Simulator.java
index e149a48520657302dcf5076c91c0c1677d25911a..0baef09710317f640e81946e5691400daf6041fe 100644
--- a/tlatools/src/tlc2/tool/Simulator.java
+++ b/tlatools/src/tlc2/tool/Simulator.java
@@ -22,7 +22,7 @@ import tlc2.output.StatePrinter;
 import tlc2.tool.SimulationWorker.SimulationWorkerError;
 import tlc2.tool.SimulationWorker.SimulationWorkerResult;
 import tlc2.tool.coverage.CostModelCreator;
-import tlc2.tool.impl.Tool;
+import tlc2.tool.impl.FastTool;
 import tlc2.tool.liveness.ILiveCheck;
 import tlc2.tool.liveness.LiveCheck;
 import tlc2.tool.liveness.LiveCheck1;
@@ -54,7 +54,7 @@ public class Simulator {
 		// SZ Mar 5, 2009: removed it again because of the bug in simulator
 		// ToolIO.setUserDir(specDir);
 
-		this.tool = new Tool(specDir, specFile, configFile, resolver);
+		this.tool = new FastTool(specDir, specFile, configFile, resolver);
 
 		this.checkDeadlock = deadlock;
 		this.checkLiveness = !this.tool.livenessIsTrue();
@@ -354,13 +354,50 @@ public class Simulator {
 			MP.printMessage(EC.TLC_ERROR_STATE);
 			StatePrinter.printState(state);
 		} else {
+			if (!stateTrace.isLastElement(state)) {
+				// MAK 09/24/2019: this method is called with state being the stateTrace's
+				// last element or not.
+				stateTrace.addElement(state);
+			}
+			
 			MP.printError(EC.TLC_BEHAVIOR_UP_TO_THIS_POINT);
+			// MAK 09/24/2019: For space reasons, TLCState does not store the state's action.
+			// This is why the loop below creates TLCStateInfo instances out of the pair cur
+			// -> last to print the action's name as part of the error trace. This is
+			// especially useful for Error-Trace Explorer in the Toolbox.
 			TLCState lastState = null;
+			TLCStateInfo sinfo;
+			int cnt = 1;
 			for (int i = 0; i < stateTrace.size(); i++) {
-				StatePrinter.printState(stateTrace.elementAt(i), lastState, i + 1);
-				lastState = stateTrace.elementAt(i);
+				final TLCState curState = stateTrace.elementAt(i);
+				if (lastState != null) {
+					sinfo = this.tool.getState(curState, lastState);
+				} else {
+					sinfo = new TLCStateInfo(curState, "<Initial predicate>");
+				}
+				
+				// MAK 09/25/2019: It is possible for
+				// tlc2.tool.SimulationWorker.simulateRandomTrace() to produce traces with
+				// *non-terminal* stuttering steps, i.e. it might produce traces such
+				// as s0,s1,s1,s2,s3,s3,s3,...sN* (where sN* represents an infinite suffix of
+				// "terminal" stuttering steps). In other words, it produces traces s.t.
+				// a trace can contain finite (sub-)sequence of stuttering steps.
+				// The reason is that simulateRandomTrace with non-zero probability selects
+				// a stuttering steps as the current state's successor. Guarding against it
+				// would require to fingerprint states (i.e. check equality) for each successor
+				// state selected which is considered too expensive.
+				// A trace with finite stuttering can be reduced to a shorter - hence
+				// better readable - trace with only infinite stuttering. This check makes sure
+				// we get rid of the confusing Toolbox behavior that a trace with finite
+				// stuttering is implicitly reduced by breadth-first-search when trace
+				// expressions are evaluated. 
+				if (lastState == null || curState.fingerPrint() != lastState.fingerPrint()) {
+					StatePrinter.printState(sinfo, lastState, cnt++);
+				} else {
+					assert Boolean.TRUE;
+				}
+				lastState = curState;
 			}
-			StatePrinter.printState(state, null, stateTrace.size() + 1);
 		}
 	}
 
diff --git a/tlatools/src/tlc2/tool/StateVec.java b/tlatools/src/tlc2/tool/StateVec.java
index 617136b5dac4e114131f2e6fa7a857d0b92f2a51..3d2af0859bee1b6d92a5033bae1a080441884d36 100644
--- a/tlatools/src/tlc2/tool/StateVec.java
+++ b/tlatools/src/tlc2/tool/StateVec.java
@@ -15,7 +15,7 @@ import util.Assert;
  * updates are used for improved performance and reduced
  * allocation.
  */
-public final class StateVec implements IStateFunctor {
+public final class StateVec implements IStateFunctor, INextStateFunctor {
   private TLCState v[];
   private int size;
 
@@ -46,6 +46,10 @@ public final class StateVec implements IStateFunctor {
 
   public final int size() { return this.size; }
 
+  public boolean isEmpty() {
+	return this.size == 0;
+  }
+
   public final void grow(int add) {
     int oldLen = this.v.length;
     if (oldLen >= TLCGlobals.setBound) {
@@ -61,6 +65,13 @@ public final class StateVec implements IStateFunctor {
 
   public final TLCState elementAt(int i) { return this.v[i]; }
 
+  public boolean isLastElement(final TLCState state) {
+	  if (isEmpty()) {
+		  return false;
+	  }
+	  return this.elementAt(size() - 1) == state;
+  }
+  
   public final void clear() {
     this.size = 0;
   }
@@ -74,6 +85,11 @@ public final class StateVec implements IStateFunctor {
     return this;
   }
   
+  @Override
+  public final StateVec addElement(TLCState predecessor, Action action, TLCState state) {
+	  return addElement(state);
+  }
+ 
   public final StateVec addElements(StateVec s1) {
     StateVec s0 = this;
 
@@ -150,4 +166,12 @@ public final class StateVec implements IStateFunctor {
     return sb.toString();
   }
 
+  public final boolean contains(TLCState state) {
+	for (int i = 0; i < size; i++) {
+		if (this.v[i].fingerPrint() == state.fingerPrint()) {
+			return true;
+		}
+	}
+	return false;
+  }
 }
diff --git a/tlatools/src/tlc2/tool/TLCState.java b/tlatools/src/tlc2/tool/TLCState.java
index cd1f86de4700ec9c402b54943269146f53f9e616..1730ee61c50f9c73ffffc96d5aab9954199f54b2 100644
--- a/tlatools/src/tlc2/tool/TLCState.java
+++ b/tlatools/src/tlc2/tool/TLCState.java
@@ -23,7 +23,13 @@ import util.UniqueString;
 public abstract class TLCState implements Cloneable, Serializable {
   public short workerId = Short.MAX_VALUE; // Must be set to a non-negative number. Valid worker ids \in [0,Short.MAX_VALUE] and start at 0.
   public long uid = -1;   // Must be set to a non-negative number
-  private int level = 1;
+  // The level of an initial state is initialized with 1 to assert that
+  // TLCGet("level") in the first evaluation of the next-state relation equals 1.
+  // The successor states of initial states have level 2.  During the evaluation
+  // of the initial *predicate* - which generates the initial states - the level
+  // is defined to be zero.
+  public static final int INIT_LEVEL = 1;
+  private int level = INIT_LEVEL;
   
   // Set by subclasses. Cannot set until we know what the variables are.
   public static TLCState Empty = null;
@@ -85,6 +91,10 @@ public abstract class TLCState implements Cloneable, Serializable {
     }
     return valMap;
   }
+  
+  public final OpDeclNode[] getVars() {
+	  return vars;
+  }
 
   public final void setPredecessor(final TLCState predecessor) {
 	  if (predecessor.getLevel() == Integer.MAX_VALUE) {
@@ -98,7 +108,7 @@ public abstract class TLCState implements Cloneable, Serializable {
   }
   
   public final boolean isInitial() {
-	return this.level == 1;
+	return this.level == INIT_LEVEL;
   }
   
   /* Returns a string representation of this state.  */
diff --git a/tlatools/src/tlc2/tool/TLCTrace.java b/tlatools/src/tlc2/tool/TLCTrace.java
index 691bd258e07504440a225ba66f061d495f794a4b..c482e557721b5861ecd506a6ee4eb5ea1b0ce452 100644
--- a/tlatools/src/tlc2/tool/TLCTrace.java
+++ b/tlatools/src/tlc2/tool/TLCTrace.java
@@ -263,6 +263,17 @@ public class TLCTrace {
 		return getTrace(fps);
 	}
 
+	/**
+	 * This method is *not* safe to call multiple times iff the spec being checked
+	 * consumed randomness, ie. TLC!RandomElement or through the Randomization
+	 * module. In other words, such specs are incompatible with TLC's -continue
+	 * mode.
+	 * <p>
+	 * To implement this correctly, state space exploration would either have to
+	 * halt while the fingerprints are resolved to TLCStates below or ITool has
+	 * to offer additional API s.t. the seed of RandomEnumerableValues gets
+	 * passed as part of the method call.
+	 */
 	protected final TLCStateInfo[] getTrace(LongVec fps) {
 		// Re-Initialize the rng with the seed value recorded and used during the model
 		// checking phase. Otherwise, we won't be able to reconstruct the error trace
diff --git a/tlatools/src/tlc2/tool/Worker.java b/tlatools/src/tlc2/tool/Worker.java
index 1bd32d89b7e7f823814c7a233872a072f7647948..c06f9afa0756acd639a22f9c15cf3b8612ef72af 100644
--- a/tlatools/src/tlc2/tool/Worker.java
+++ b/tlatools/src/tlc2/tool/Worker.java
@@ -10,8 +10,11 @@ import java.io.DataOutputStream;
 import java.io.File;
 import java.io.IOException;
 
+import tlc2.TLCGlobals;
 import tlc2.output.EC;
 import tlc2.output.MP;
+import tlc2.tool.fp.FPSet;
+import tlc2.tool.impl.FastTool;
 import tlc2.tool.queue.IStateQueue;
 import tlc2.util.BufferedRandomAccessFile;
 import tlc2.util.IStateWriter;
@@ -19,10 +22,13 @@ import tlc2.util.IdThread;
 import tlc2.util.SetOfStates;
 import tlc2.util.statistics.FixedSizedBucketStatistics;
 import tlc2.util.statistics.IBucketStatistics;
+import util.Assert.TLCRuntimeException;
 import util.FileUtil;
+import util.WrongInvocationException;
 
-public final class Worker extends IdThread implements IWorker {
+public final class Worker extends IdThread implements IWorker, INextStateFunctor {
 
+	protected static final boolean coverage = TLCGlobals.isCoverageEnabled();
 	private static final int INITIAL_CAPACITY = 16;
 	
 	/**
@@ -31,10 +37,14 @@ public final class Worker extends IdThread implements IWorker {
 	 * We expect to get linear speedup with respect to the number of processors.
 	 */
 	private final ModelChecker tlc;
+	private final FastTool tool;
 	private final IStateQueue squeue;
+	private final FPSet theFPSet;
+	private final IStateWriter allStateWriter;
 	private final IBucketStatistics outDegree;
 	private final String filename;
 	private final BufferedRandomAccessFile raf;
+	private final boolean checkDeadlock;
 
 	private long lastPtr;
 	private long statesGenerated;
@@ -47,7 +57,12 @@ public final class Worker extends IdThread implements IWorker {
 		// SZ 12.04.2009: added thread name
 		this.setName("TLC Worker " + id);
 		this.tlc = (ModelChecker) tlc;
+		this.checkLiveness = this.tlc.checkLiveness;
+		this.checkDeadlock = this.tlc.checkDeadlock;
+		this.tool = (FastTool) this.tlc.tool;
 		this.squeue = this.tlc.theStateQueue;
+		this.theFPSet = this.tlc.theFPSet;
+		this.allStateWriter = this.tlc.allStateWriter;
 		this.outDegree = new FixedSizedBucketStatistics(this.getName(), 32); // maximum outdegree of 32 appears sufficient for now.
 		this.setName("TLCWorkerThread-" + String.format("%03d", id));
 
@@ -61,7 +76,6 @@ public final class Worker extends IdThread implements IWorker {
    * updates the state set and state queue.
 	 */
 	public void run() {
-		final boolean checkLiveness = this.tlc.checkLiveness;
 		TLCState curState = null;
 		try {
 			while (true) {
@@ -76,17 +90,28 @@ public final class Worker extends IdThread implements IWorker {
 				}
 				setCurrentState(curState);
 				
-				SetOfStates setOfStates = null;
-				if (checkLiveness) {
+				if (this.checkLiveness) {
+					// Allocate iff liveness is checked.
 					setOfStates = createSetOfStates();
 				}
 				
-				if (this.tlc.doNext(curState, setOfStates, this)) {
-					return;
+				final long preNext = this.statesGenerated;
+				try {
+					this.tool.getNextStates(this, curState);
+				} catch (TLCRuntimeException e) {
+					// The next-state relation couldn't be evaluated.
+					this.tlc.doNextFailed(curState, null, e);
+				}
+				
+				if (this.checkDeadlock && preNext == this.statesGenerated) {
+					// A deadlock is defined as a state without (seen or unseen) successor
+					// states. In other words, evaluating the next-state relation for a state
+					// yields no states.
+	                this.tlc.doNextSetErr(curState, null, false, EC.TLC_DEADLOCK_REACHED, null);
 				}
 				
 	            // Finally, add curState into the behavior graph for liveness checking:
-	            if (checkLiveness)
+	            if (this.checkLiveness)
 	            {
 					doNextCheckLiveness(curState, setOfStates);
 	            }
@@ -113,6 +138,10 @@ public final class Worker extends IdThread implements IWorker {
 	
 	private int multiplier = 1;
 
+	private SetOfStates setOfStates;
+
+	private final boolean checkLiveness;
+
 	private final void doNextCheckLiveness(TLCState curState, SetOfStates liveNextStates) throws IOException {
 		final long curStateFP = curState.fingerPrint();
 
@@ -207,6 +236,10 @@ public final class Worker extends IdThread implements IWorker {
 
 	// Read from previously written (see writeState) trace file.
 	public final synchronized ConcurrentTLCTrace.Record readStateRecord(final long ptr) throws IOException {
+		// Remember current tip of the file before we rewind.
+		this.raf.mark();
+		
+		// rewind to position we want to read from.
 		this.raf.seek(ptr);
 		
 		final long prev = this.raf.readLongNat();
@@ -218,6 +251,11 @@ public final class Worker extends IdThread implements IWorker {
 		final long fp = this.raf.readLong();
 		assert tlc.theFPSet.contains(fp);
 		
+		// forward/go back back to tip of file.
+		// This is only necessary iff TLC runs with '-continue'. In other words, state
+		// space exploration continues after an error trace has been written.
+		this.raf.seek(this.raf.getMark());
+		
 		return new ConcurrentTLCTrace.Record(prev, worker, fp);
 	}
 	
@@ -281,4 +319,146 @@ public final class Worker extends IdThread implements IWorker {
 			this.enumRaf.close();
 		}
 	}
+	
+	//**************************************************************//
+
+	@Override
+	public final Object addElement(final TLCState state) {
+		throw new WrongInvocationException("tlc2.tool.Worker.addElement(TLCState) should not be called");
+	}
+
+	@Override
+	public final Object addElement(final TLCState curState, final Action action, final TLCState succState) {
+	    if (coverage) { action.cm.incInvocations(); }
+		this.statesGenerated++;
+		
+		try {
+			if (!this.tool.isGoodState(succState)) {
+				this.tlc.doNextSetErr(curState, succState, action);
+				throw new InvariantViolatedException();
+			}
+			
+			// Check if state is excluded by a state or action constraint.
+			final boolean inModel = (this.tool.isInModel(succState) && this.tool.isInActions(curState, succState));
+			
+			// Check if state is new or has been seen earlier.
+			boolean unseen = true;
+			if (inModel) {
+				unseen = !isSeenState(curState, succState, action);
+			}
+			
+			// Check if succState violates any invariant:
+			if (unseen) {
+				if (this.doNextCheckInvariants(curState, succState)) {
+					throw new InvariantViolatedException();
+				}
+			}
+			
+			// Check if the state violates any implied action. We need to do it
+			// even if succState is not new.
+			if (this.doNextCheckImplied(curState, succState)) {
+				throw new InvariantViolatedException();
+			}
+			
+			if (inModel && unseen) {
+				// The state is inModel, unseen and neither invariants
+				// nor implied actions are violated. It is thus eligible
+				// for further processing by other workers.
+				this.squeue.sEnqueue(succState);
+			}
+			return this;
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	private final boolean isSeenState(final TLCState curState, final TLCState succState, final Action action)
+			throws IOException {
+		final long fp = succState.fingerPrint();
+		final boolean seen = this.theFPSet.put(fp);
+		// Write out succState when needed:
+		this.allStateWriter.writeState(curState, succState, !seen, action);
+		if (!seen) {
+			// Write succState to trace only if it satisfies the
+			// model constraints. Do not enqueue it yet, but wait
+			// for implied actions and invariants to be checked.
+			// Those checks - if violated - will cause model checking
+			// to terminate. Thus we cannot let concurrent workers start
+			// exploring this new state. Conversely, the state has to
+			// be in the trace in case either invariant or implied action
+			// checks want to print the trace.
+			this.writeState(curState, fp, succState);
+			if (coverage) {	action.cm.incSecondary(); }
+		}
+		// For liveness checking:
+		if (this.checkLiveness)
+		{
+			this.setOfStates.put(fp, succState);
+		}
+		return seen;
+	}
+
+	private final boolean doNextCheckInvariants(final TLCState curState, final TLCState succState) throws IOException, WorkerException, Exception {
+        int k = 0;
+		try
+        {
+			for (k = 0; k < this.tool.getInvariants().length; k++)
+            {
+                if (!tool.isValid(this.tool.getInvariants()[k], succState))
+                {
+                    // We get here because of invariant violation:
+                	if (TLCGlobals.continuation) {
+                        synchronized (this.tlc)
+                        {
+							MP.printError(EC.TLC_INVARIANT_VIOLATED_BEHAVIOR,
+									this.tool.getInvNames()[k]);
+							this.tlc.trace.printTrace(curState, succState);
+							return false;
+                        }
+                	} else {
+						return this.tlc.doNextSetErr(curState, succState, false,
+								EC.TLC_INVARIANT_VIOLATED_BEHAVIOR, this.tool.getInvNames()[k]);
+                	}
+				}
+			}
+        } catch (Exception e)
+        {
+			this.tlc.doNextEvalFailed(curState, succState, EC.TLC_INVARIANT_EVALUATION_FAILED,
+					this.tool.getInvNames()[k], e);
+		}
+		return false;
+	}
+
+	private final boolean doNextCheckImplied(final TLCState curState, final TLCState succState) throws IOException, WorkerException, Exception {
+		int k = 0;
+        try
+        {
+			for (k = 0; k < this.tool.getImpliedActions().length; k++)
+            {
+                if (!tool.isValid(this.tool.getImpliedActions()[k], curState, succState))
+                {
+                    // We get here because of implied-action violation:
+                    if (TLCGlobals.continuation)
+                    {
+                        synchronized (this.tlc)
+                        {
+                            MP.printError(EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR, this.tool
+                                    .getImpliedActNames()[k]);
+                            this.tlc.trace.printTrace(curState, succState);
+							return false;
+                       }
+                    } else {
+						return this.tlc.doNextSetErr(curState, succState, false,
+								EC.TLC_ACTION_PROPERTY_VIOLATED_BEHAVIOR,
+								this.tool.getImpliedActNames()[k]);
+                	}
+				}
+			}
+        } catch (Exception e)
+        {
+        	this.tlc.doNextEvalFailed(curState, succState, EC.TLC_ACTION_PROPERTY_EVALUATION_FAILED,
+					this.tool.getImpliedActNames()[k], e);
+		}
+        return false;
+	}
 }
diff --git a/tlatools/src/tlc2/tool/coverage/ActionWrapper.java b/tlatools/src/tlc2/tool/coverage/ActionWrapper.java
index 4ffe571fd28cc7b9967d3b577992c4ff04153de0..ead40c50e5947345682f5c02c0a32472b4e85edf 100644
--- a/tlatools/src/tlc2/tool/coverage/ActionWrapper.java
+++ b/tlatools/src/tlc2/tool/coverage/ActionWrapper.java
@@ -25,6 +25,7 @@
  ******************************************************************************/
 package tlc2.tool.coverage;
 
+import tla2sany.semantic.LetInNode;
 import tla2sany.semantic.SemanticNode;
 import tla2sany.semantic.SubstInNode;
 import tla2sany.st.Location;
@@ -104,11 +105,16 @@ public final class ActionWrapper extends CostModelNode {
 	 */
 	@Override
 	public final CostModel get(final SemanticNode eon) {
+		// returns this instance in case no match is found in children. As a result, the
+		// CostModel will be incorrect which is not as severe as running into an NPE.
 		if (eon instanceof SubstInNode) {
 			final SubstInNode sin = (SubstInNode) eon;
-			return this.children.get(sin.getBody());
+			return this.children.getOrDefault(sin.getBody(), this);
+		} else if (eon instanceof LetInNode) {
+			final LetInNode lin = (LetInNode) eon;
+			return this.children.getOrDefault(lin.getBody(), this);
 		}
-		return this.children.get(eon);
+		return this.children.getOrDefault(eon, this);
 	}
 
 	/* (non-Javadoc)
@@ -146,8 +152,10 @@ public final class ActionWrapper extends CostModelNode {
 		}
 
 		// An action has single child which is the OpApplNodeWrapper with the OpApplNode
-		// for this OpDefNode unless the action's pred is a substitution.
-		assert !(this.action.pred instanceof SubstInNode) ? this.children.size() == 1 : !this.children.isEmpty();
+		// for this OpDefNode unless the action's pred is a substitution or a let/in expr.
+		assert !(this.action.pred instanceof SubstInNode || this.action.pred instanceof LetInNode)
+				? this.children.size() == 1
+				: !this.children.isEmpty();
 		// Let children report.
 		// Could disable here if decided to implement action-only coverage at the TLC
 		// level (see org.lamport.tla.toolbox.tool.tlc.model.Model.Coverage).
diff --git a/tlatools/src/tlc2/tool/coverage/CostModel.java b/tlatools/src/tlc2/tool/coverage/CostModel.java
index 43f66a09c590296e0b19e9564a9b1fc7fdc4b0c6..cdfbaf6c7415447c394315e1e87ceb71909e78c5 100644
--- a/tlatools/src/tlc2/tool/coverage/CostModel.java
+++ b/tlatools/src/tlc2/tool/coverage/CostModel.java
@@ -32,50 +32,55 @@ public interface CostModel {
 	CostModel DO_NOT_RECORD = new CostModel() {
 
 		@Override
-		public CostModel report() {
+		public final CostModel report() {
 			// no-op
 			return this;
 		}
 
 		@Override
-		public CostModel get(final SemanticNode sn) {
+		public final CostModel get(final SemanticNode sn) {
 			return this;
 		}
 		
 		@Override
-		public CostModel getRoot() {
+		public final CostModel getRoot() {
 			return this;
 		}
 
 		@Override
-		public CostModel incInvocations() {
+		public final CostModel incInvocations() {
 			// no-op
 			return this;
 		}
 
 		@Override
-		public CostModel incInvocations(final long value) {
+		public final CostModel incInvocations(final long value) {
 			// no-op
 			return this;
 		}
 
 		@Override
-		public CostModel incSecondary() {
+		public final CostModel incSecondary() {
 			// no-op
 			return this;
 		}
 
 		@Override
-		public CostModel incSecondary(long value) {
+		public final CostModel incSecondary(long value) {
 			// no-op
 			return null;
 		}
 
 		@Override
-		public CostModel getAndIncrement(SemanticNode eon) {
+		public final CostModel getAndIncrement(SemanticNode eon) {
 			// no-op
 			return this;
 		}
+		
+		@Override
+		public final String toString() {
+			return "DO_NOT_RECORD";
+		}
 	};
 
 	CostModel incInvocations();
diff --git a/tlatools/src/tlc2/tool/coverage/CostModelCreator.java b/tlatools/src/tlc2/tool/coverage/CostModelCreator.java
index ff2c11d4c55efc0a2809deda4be329fb2af5b452..7e60b8ac951cc5897cd858aeea01732cb8f133cf 100644
--- a/tlatools/src/tlc2/tool/coverage/CostModelCreator.java
+++ b/tlatools/src/tlc2/tool/coverage/CostModelCreator.java
@@ -41,6 +41,7 @@ import tla2sany.explorer.ExploreNode;
 import tla2sany.explorer.ExplorerVisitor;
 import tla2sany.semantic.ExprNode;
 import tla2sany.semantic.ExprOrOpArgNode;
+import tla2sany.semantic.LetInNode;
 import tla2sany.semantic.OpApplNode;
 import tla2sany.semantic.OpDefNode;
 import tla2sany.semantic.SemanticNode;
@@ -150,8 +151,10 @@ public class CostModelCreator extends ExplorerVisitor {
 
 	private final Deque<CostModelNode> stack = new ArrayDeque<>();
 	private final Map<ExprOrOpArgNode, Subst> substs = new HashMap<>();
-	private final Map<OpApplNode, OpApplNodeWrapper> node2Wrapper = new HashMap<>();
+	private final Map<OpApplNode, Set<OpApplNodeWrapper>> node2Wrapper = new HashMap<>();
 	private final Set<OpDefNode> opDefNodes = new HashSet<>();
+	// Set of OpDefNodes occurring in LetIns and their OpApplNodes.
+	private final Map<ExprNode, ExprNode> letIns = new HashMap<>();
 	// OpAppNode does not implement equals/hashCode which causes problem when added
 	// to sets or maps. E.g. for a test, an OpApplNode instance belonging to
 	// Sequences.tla showed up in coverage output.
@@ -184,6 +187,7 @@ public class CostModelCreator extends ExplorerVisitor {
 		this.substs.clear();
 		this.node2Wrapper.clear();
 		this.opDefNodes.clear();
+		this.letIns.clear();
 		this.stack.clear();
 		this.ctx = Context.Empty;
 		
@@ -214,6 +218,27 @@ public class CostModelCreator extends ExplorerVisitor {
 				oan.setPrimed();
 			}
 			
+			// A (recursive) function definition nested in LetIn:
+			//   LET F[n \in S] == e
+			//   IN F[...]
+			// with e either built from F or not.
+			if (letIns.containsKey(opApplNode)) {
+				// At the visit of the LETIN node in the walk over the semantic graph we stored
+				// the mapping from the LET part to the IN part in this.lets (see LetInNode below).
+				// Here, we add the LET parts(s) to the lets of the IN part if it is found on
+				// the stack (this is more involved because we have to find the OANWrappers and
+				// not just the OANs). 
+				final ExprNode in = letIns.get(opApplNode);
+				for (CostModelNode cmn : stack) {
+					final SemanticNode node = cmn.getNode();
+					if (node == in && cmn instanceof OpApplNodeWrapper) {
+						// addLets instead of addChild because lets can be added multiple times
+						// whereas addChild asserts a child to be added only once.
+						((OpApplNodeWrapper) cmn).addLets(oan);
+					}
+				}
+			}
+			
 			// CONSTANT operators (including definition overrides...)
 			final SymbolNode operator = opApplNode.getOperator();
 			final Object val = tool.lookup(operator);
@@ -231,33 +256,71 @@ public class CostModelCreator extends ExplorerVisitor {
 				final OpDefNode odn = (OpDefNode) operator;
 				if (odn.getInRecursive()) {
 					final OpApplNodeWrapper recursive = (OpApplNodeWrapper) stack.stream()
-							.filter(w -> w.getNode() != null && ((OpApplNode) w.getNode()).getOperator() == odn).findFirst()
-							.orElse(null);
+							.filter(w -> w.getNode() != null && w.getNode() instanceof OpApplNode
+									&& ((OpApplNode) w.getNode()).getOperator() == odn)
+							.findFirst().orElse(null);
 					if (recursive != null) {
 						oan.setRecursive(recursive);
 					}
 				}
 			}
-			
+
 			// Higher-order operators/Operators as arguments (LAMBDA, ...)
-			if (tool != null && operator instanceof OpDefNode && opApplNode.hasOpcode(0)) {
-				// 1) Maintain Context as done by Tool...
+			//
+			// line X: Foo(Op(_), S) == \A s \in S: Op(s)
+			// line ?: ...
+			// line Y: Bar == Foo(LAMBDA e: e..., {1,2,3})
+			//
+			// This is the most involved part of CMC: The task is to make the OANW
+			// corresponding to the RHS of the LAMBDA expression on line Y a child of Op(s)
+			// on line X. However, the graph exploration is DFS which means that we haven't
+			// seen the LAMBDA on line Y when we are at the Op(s) on line X and we've
+			// (mostly) forgotten about Op(s) when we see the LAMBDA. ToolImpl - as part of
+			// its DFS over the semantic graph - passes a context along which gets extended
+			// or *branched*. Here, we cannot pass a Context along the decent but instead
+			// keep a single, global context. 
+			//
+			// The global context does not create a problem with regards to correctness, but
+			// can lead to long context chains for larger specifications. Therefore, only
+			// extend the context when opApplNode.argsContainOpArgNodes() is true, i.e. when
+			// one or more arguments of an operator are also operators (such as a LAMBDA).
+			// Without this safeguard, the time to create the CostModel for the SchedMono
+			// specification took approximately 60 seconds. With the safeguard, it is down
+			// to a second or two.
+			//
+			// To summarize, this is a clutch that has been hacked to work good enough!
+			// 
+			// if-branches 1., 2., and 3. below are evaluated in three distinct
+			// invocation of outer preVisit for different ExploreNodes.
+			if (tool != null && operator instanceof OpDefNode && opApplNode.hasOpcode(0)
+					&& opApplNode.argsContainOpArgNodes()) {
+				// 1) Maintain Context for all OpApplNode iff one or more of its args are of
+				// type OpArgNode. This is more restrictive than Tool.
 				final OpDefNode odn = (OpDefNode) operator;
-				this.ctx = tool.getOpContext(odn, opApplNode.getArgs(), ctx, false);
+				if (odn.hasOpcode(0) && !odn.isStandardModule()) {
+					this.ctx = tool.getOpContext(odn, opApplNode.getArgs(), ctx, false);
+				}
 			}
 			final Object lookup = this.ctx.lookup(opApplNode.getOperator());
 			if (lookup instanceof OpDefNode) {
-				// 2) Context has an entry for the given body. Remember for later.
+				// 2) Context has an entry for the given body where body is 'LAMBDA e: e...' and
+				// oan is 'Op(s)'. Remember for later.
 				final ExprNode body = ((OpDefNode) lookup).getBody();
 				if (body instanceof OpApplNode) {
-					this.node2Wrapper.put((OpApplNode) body, oan);
+					// Design choice:
+					// Might as well store the mapping from body to oan via
+					// body#setToolObject(tla2sany.semantic.FrontEnd.getToolId(), oan) instead of in
+					// node2Wrapper. However, node2Wrapper can be gc'ed after the CostModel has been
+					// created and before state space exploration.
+					this.node2Wrapper.computeIfAbsent((OpApplNode) body, key -> new HashSet<>()).add(oan);
 				}
 			}
 			if (this.node2Wrapper.containsKey(opApplNode)) {
-				// 3) Now its later. Connect w and oan. 
-				final OpApplNodeWrapper w = this.node2Wrapper.get(opApplNode);
-				w.addChild(oan);
+				// 3) Now it's later. Connect w and oan where
+				// w is 'Op(s)' and oan is 'LAMBDA e: e...'
+				this.node2Wrapper.get(opApplNode).forEach(w -> w.addChild(oan));
 			}
+			// End of Higher-order operators/Operators as arguments (LAMBDA, ...) 
 			
 			// Substitutions
 			if (this.substs.containsKey(exploreNode)) {
@@ -275,6 +338,11 @@ public class CostModelCreator extends ExplorerVisitor {
 			for (Subst subst : substs) {
 				this.substs.put(subst.getExpr(), subst);
 			}
+		} else if (exploreNode instanceof LetInNode) {
+			final LetInNode lin = (LetInNode) exploreNode;
+			for (OpDefNode opDefNode : lin.getLets()) {
+				letIns.put(opDefNode.getBody(), lin.getBody());
+			}
 		} else if (exploreNode instanceof OpDefNode) {
 			//TODO Might suffice to just keep RECURSIVE ones.
 			opDefNodes.add((OpDefNode) exploreNode);
@@ -325,6 +393,16 @@ public class CostModelCreator extends ExplorerVisitor {
 		for (Action invariant : tool.getInvariants()) {
 			invariant.cm = collector.getCM(invariant, Relation.PROP);
 		}
+		
+        // https://github.com/tlaplus/tlaplus/issues/413#issuecomment-577304602
+        if (Boolean.getBoolean(CostModelCreator.class.getName() + ".implied")) {
+    		for (Action impliedInits : tool.getImpliedInits()) {
+    			impliedInits.cm = collector.getCM(impliedInits, Relation.PROP);
+    		}
+    		for (Action impliedActions : tool.getImpliedActions()) {
+    			impliedActions.cm = collector.getCM(impliedActions, Relation.PROP);
+    		}
+        }
 	}
 	
 	public static void report(final ITool tool, final long startTime) {
@@ -362,8 +440,18 @@ public class CostModelCreator extends ExplorerVisitor {
         for (Action invariant : tool.getInvariants()) {
         	//TODO May need to be ordered similar to next-state actions above.
         	invariant.cm.report();
-		}
+		}	
         
+        // https://github.com/tlaplus/tlaplus/issues/413#issuecomment-577304602
+        if (Boolean.getBoolean(CostModelCreator.class.getName() + ".implied")) {
+    		for (Action impliedInits : tool.getImpliedInits()) {
+    			impliedInits.cm.report();
+    		}
+    		for (Action impliedActions : tool.getImpliedActions()) {
+    			impliedActions.cm.report();
+    		}
+        }
+       
 		// Notify users about the performance overhead related to coverage collection
 		// after N minutes of model checking. The assumption is that a user has little
 		// interest in coverage for a large (long-running) model anyway.  In the future
diff --git a/tlatools/src/tlc2/tool/coverage/OpApplNodeWrapper.java b/tlatools/src/tlc2/tool/coverage/OpApplNodeWrapper.java
index f2c0e0ee8511713b175ff4149250642583e2593f..99e205f66bd852c92316a79586894d78d34c8f57 100644
--- a/tlatools/src/tlc2/tool/coverage/OpApplNodeWrapper.java
+++ b/tlatools/src/tlc2/tool/coverage/OpApplNodeWrapper.java
@@ -26,6 +26,8 @@
 package tlc2.tool.coverage;
 
 import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
 import java.util.Set;
 
 import tla2sany.semantic.OpApplNode;
@@ -54,6 +56,7 @@ public class OpApplNodeWrapper extends CostModelNode implements Comparable<OpApp
 	private boolean primed = false;
 	private int level;
 	private OpApplNodeWrapper recursive;
+	protected final Map<SemanticNode, CostModelNode> lets = new LinkedHashMap<>();
 
 	OpApplNodeWrapper(OpApplNode node, CostModelNode root) {
 		super();
@@ -134,6 +137,11 @@ public class OpApplNodeWrapper extends CostModelNode implements Comparable<OpApp
 	}
 
 	// ---------------- Parent <> Child ---------------- //
+	
+	public OpApplNodeWrapper addLets(OpApplNodeWrapper lets) {
+		this.lets.put(lets.getNode(), lets);
+		return this;
+	}
 
 	public OpApplNodeWrapper setRecursive(OpApplNodeWrapper recursive) {
 		assert this.recursive == null;
@@ -167,6 +175,13 @@ public class OpApplNodeWrapper extends CostModelNode implements Comparable<OpApp
 			}
 		}
 		
+		if (lets != null) {
+			child = lets.get(eon);
+			if (child != null) {
+				return child;
+			}
+		}
+		
 		// TODO Not all places in Tool lookup the correct CM yet. This should only be an
 		// engineering effort though.
 		if (seen.add(eon.myUID)) {
diff --git a/tlatools/src/tlc2/tool/distributed/RMIFilenameToStreamResolver.java b/tlatools/src/tlc2/tool/distributed/RMIFilenameToStreamResolver.java
index f2160bcac1874f4537a2b74e88f136604bef932f..be69d22bde492547e6a0faf7544aac68da2aea73 100644
--- a/tlatools/src/tlc2/tool/distributed/RMIFilenameToStreamResolver.java
+++ b/tlatools/src/tlc2/tool/distributed/RMIFilenameToStreamResolver.java
@@ -52,7 +52,7 @@ public class RMIFilenameToStreamResolver implements FilenameToStream {
 
 		// read the file from the server
 		// strip off path
-		final String name = new File(filename).getName();
+		final String name = new TLAFile(filename, this).getName();
 
 		File file = fileCache.get(name);
 		// not in cache
@@ -102,7 +102,7 @@ public class RMIFilenameToStreamResolver implements FilenameToStream {
 	}
 
 	private File writeToNewTempFile(String name, byte[] bs) {
-		final File f = new File(rndPrefix + File.separator + name);
+		final File f = new TLAFile(rndPrefix + File.separator + name, this);
 		f.deleteOnExit();
 
 		FileOutputStream outputStream = null;
diff --git a/tlatools/src/tlc2/tool/distributed/TLCApp.java b/tlatools/src/tlc2/tool/distributed/TLCApp.java
index f880583ce064312d6189d6a19ab8f3bf65a12edb..7e2bce787f2552c5c06000015e48b267431e916e 100644
--- a/tlatools/src/tlc2/tool/distributed/TLCApp.java
+++ b/tlatools/src/tlc2/tool/distributed/TLCApp.java
@@ -20,10 +20,12 @@ import tlc2.tool.TLCStateInfo;
 import tlc2.tool.WorkerException;
 import tlc2.tool.fp.FPSet;
 import tlc2.tool.fp.FPSetConfiguration;
-import tlc2.tool.impl.Tool;
+import tlc2.tool.impl.CallStackTool;
+import tlc2.tool.impl.FastTool;
 import tlc2.util.FP64;
 import util.FileUtil;
 import util.FilenameToStream;
+import util.TLAConstants;
 import util.ToolIO;
 import util.UniqueString;
 
@@ -65,7 +67,7 @@ public class TLCApp extends DistApp {
 		
 		this.checkDeadlock = deadlock.booleanValue();
 		this.preprocess = true;
-		this.tool = new Tool(specDir, specFile, configFile, fts);
+		this.tool = new FastTool(specDir, specFile, configFile, fts);
 
 		this.impliedInits = this.tool.getImpliedInits();
 		this.invariants = this.tool.getInvariants();
@@ -259,16 +261,14 @@ public class TLCApp extends DistApp {
 	 * @see tlc2.tool.distributed.DistApp#setCallStack()
 	 */
 	public final void setCallStack() {
-		this.tool.setCallStack();
+		this.tool = new CallStackTool(this.tool);
 	}
 
 	/* (non-Javadoc)
 	 * @see tlc2.tool.distributed.DistApp#printCallStack()
 	 */
 	public final String printCallStack() {
-		// SZ Jul 10, 2009: check if this is ok
-		// changed the method signature
-		return this.tool.getCallStack().toString();
+		return this.tool.toString();
 	}
 
 	@SuppressWarnings("deprecation")
@@ -287,9 +287,9 @@ public class TLCApp extends DistApp {
 				index++;
 				if (index < args.length) {
 					configFile = args[index];
-					int len = configFile.length();
-					if (configFile.startsWith(".cfg", len - 4)) {
-						configFile = configFile.substring(0, len - 4);
+					if (configFile.endsWith(TLAConstants.Files.CONFIG_EXTENSION)) {
+						configFile = configFile.substring(0,
+								(configFile.length() - TLAConstants.Files.CONFIG_EXTENSION.length()));
 					}
 					index++;
 				} else {
@@ -494,9 +494,8 @@ public class TLCApp extends DistApp {
 					return null;
 				}
 				specFile = args[index++];
-				int len = specFile.length();
-				if (specFile.startsWith(".tla", len - 4)) {
-					specFile = specFile.substring(0, len - 4);
+				if (specFile.endsWith(TLAConstants.Files.TLA_EXTENSION)) {
+					specFile = specFile.substring(0, (specFile.length() - TLAConstants.Files.TLA_EXTENSION.length()));
 				}
 			}
 		}
@@ -511,8 +510,8 @@ public class TLCApp extends DistApp {
 				TLCGlobals.chkptDuration = 0; // never use checkpoints with distributed TLC (highly inefficient)
 				FP64.Init(fpIndex);
 				FilenameToStream resolver = new InJarFilenameToStream(ModelInJar.PATH);
-				return new TLCApp("MC", "MC", deadlock, fromChkpt,
-						fpSetConfig, resolver);
+				return new TLCApp(TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, TLAConstants.Files.MODEL_CHECK_FILE_BASENAME,
+						deadlock, fromChkpt, fpSetConfig, resolver);
 			}
 			
 			printErrorMsg("Error: Missing input TLA+ module.");
diff --git a/tlatools/src/tlc2/tool/impl/ActionItemList.java b/tlatools/src/tlc2/tool/impl/ActionItemList.java
index 904f172f8f13b5a8bc91654d30ce29fc8d553716..f4a9df648c812e95d054cdb8ada0f7f6234835cd 100644
--- a/tlatools/src/tlc2/tool/impl/ActionItemList.java
+++ b/tlatools/src/tlc2/tool/impl/ActionItemList.java
@@ -5,6 +5,7 @@ package tlc2.tool.impl;
 
 import tla2sany.semantic.SemanticNode;
 import tlc2.TLCGlobals;
+import tlc2.tool.Action;
 import tlc2.tool.IActionItemList;
 import tlc2.tool.coverage.CostModel;
 import tlc2.util.Context;
@@ -53,6 +54,10 @@ class ActionItemList implements IActionItemList {
     return new ActionItemList(pred, con, kind, this, coverage ? cm.get(pred) : cm);
   }
 
+  public ActionItemList cons(final Action act, final int kind) {
+	return new ActionItemList(act.pred, act.con, kind, this, coverage ? act.cm.get(pred) : act.cm);
+  }
+
   public final boolean isEmpty() { return this == Empty; }
   
 }
diff --git a/tlatools/src/tlc2/tool/impl/CallStackTool.java b/tlatools/src/tlc2/tool/impl/CallStackTool.java
new file mode 100644
index 0000000000000000000000000000000000000000..14ad1102dec57d93a2e857617cddab8cf638ec0f
--- /dev/null
+++ b/tlatools/src/tlc2/tool/impl/CallStackTool.java
@@ -0,0 +1,242 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool.impl;
+
+import tla2sany.semantic.OpApplNode;
+import tla2sany.semantic.SemanticNode;
+import tlc2.tool.Action;
+import tlc2.tool.CallStack;
+import tlc2.tool.EvalException;
+import tlc2.tool.IActionItemList;
+import tlc2.tool.INextStateFunctor;
+import tlc2.tool.IStateFunctor;
+import tlc2.tool.ITool;
+import tlc2.tool.TLCState;
+import tlc2.tool.coverage.CostModel;
+import tlc2.util.Context;
+import tlc2.value.impl.FcnLambdaValue;
+import tlc2.value.impl.OpLambdaValue;
+import tlc2.value.impl.SetPredValue;
+import tlc2.value.impl.Value;
+import util.Assert.TLCRuntimeException;
+
+public final class CallStackTool extends Tool {
+
+	private final CallStack callStack = new CallStack();
+
+	public CallStackTool(ITool other) {
+		super((Tool) other);
+	}
+
+	@Override
+	public final String toString() {
+		return this.callStack.toString();
+	}
+
+	@Override
+	protected final void getInitStates(final SemanticNode init, final ActionItemList acts, final Context c,
+			final TLCState ps, final IStateFunctor states, final CostModel cm) {
+		this.callStack.push(init);
+		try {
+			super.getInitStates(init, acts, c, ps, states, cm);
+		} catch (TLCRuntimeException | EvalException e) {
+			// Freeze the callStack to ignore subsequent pop operations. This is
+			// necessary to ignore the callStack#pop calls in the finally blocks when the
+			// Java call stack gets unwounded.
+			this.callStack.freeze();
+			throw e;
+		} finally {
+			this.callStack.pop();
+		}
+	}
+
+	protected void getInitStatesAppl(final OpApplNode init, final ActionItemList acts, final Context c,
+			final TLCState ps, final IStateFunctor states, final CostModel cm) {
+		this.callStack.push(init);
+		try {
+			super.getInitStatesAppl(init, acts, c, ps, states, cm);
+		} catch (TLCRuntimeException | EvalException e) {
+			// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context,
+			// TLCState, IStateFunctor)
+			this.callStack.freeze();
+			throw e;
+		} finally {
+			this.callStack.pop();
+		}
+	}
+
+	@Override
+	protected final TLCState getNextStates(final Action action, final SemanticNode pred, final ActionItemList acts,
+			final Context c, final TLCState s0, final TLCState s1, final INextStateFunctor nss, final CostModel cm) {
+		this.callStack.push(pred);
+		try {
+			return getNextStatesImpl(action, pred, acts, c, s0, s1, nss, cm);
+		} catch (TLCRuntimeException | EvalException e) {
+			// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context,
+			// TLCState, IStateFunctor)
+			this.callStack.freeze();
+			throw e;
+		} finally {
+			this.callStack.pop();
+		}
+	}
+
+	@Override
+	protected final TLCState getNextStatesAppl(final Action action, final OpApplNode pred, final ActionItemList acts,
+			final Context c, final TLCState s0, final TLCState s1, final INextStateFunctor nss, final CostModel cm) {
+		this.callStack.push(pred);
+		try {
+			return getNextStatesApplImpl(action, pred, acts, c, s0, s1, nss, cm);
+		} catch (TLCRuntimeException | EvalException e) {
+			// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context,
+			// TLCState, IStateFunctor)
+			this.callStack.freeze();
+			throw e;
+		} finally {
+			this.callStack.pop();
+		}
+	}
+
+	@Override
+	public final Value eval(final SemanticNode expr, final Context c, final TLCState s0, final TLCState s1,
+			final int control, final CostModel cm) {
+		this.callStack.push(expr);
+		try {
+			// Replace stale ITool instances with this instance.
+			final Value value = evalImpl(expr, c, s0, s1, control, cm);
+			if (value instanceof SetPredValue) {
+				return new SetPredValue((SetPredValue) value, this);
+			} else if (value instanceof FcnLambdaValue) {
+				return new FcnLambdaValue((FcnLambdaValue) value, this);
+			} else if (value instanceof OpLambdaValue) {
+				return new OpLambdaValue((OpLambdaValue) value, this);
+			}
+			return value;
+		} catch (TLCRuntimeException | EvalException e) {
+			// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context,
+			// TLCState, IStateFunctor)
+			this.callStack.freeze();
+			throw e;
+		} finally {
+			this.callStack.pop();
+		}
+	}
+
+	@Override
+	protected final Value evalAppl(final OpApplNode expr, final Context c, final TLCState s0, final TLCState s1,
+			final int control, final CostModel cm) {
+		this.callStack.push(expr);
+		try {
+			// Replace stale ITool instances with this instance.
+			final Value value = evalApplImpl(expr, c, s0, s1, control, cm);
+			if (value instanceof SetPredValue) {
+				return new SetPredValue((SetPredValue) value, this);
+			} else if (value instanceof FcnLambdaValue) {
+				return new FcnLambdaValue((FcnLambdaValue) value, this);
+			} else if (value instanceof OpLambdaValue) {
+				return new OpLambdaValue((OpLambdaValue) value, this);
+			}
+			return value;
+		} catch (TLCRuntimeException | EvalException e) {
+			// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context,
+			// TLCState, IStateFunctor)
+			this.callStack.freeze();
+			throw e;
+		} finally {
+			this.callStack.pop();
+		}
+	}
+
+	@Override
+	public final TLCState enabled(final SemanticNode pred, final IActionItemList acts, final Context c,
+			final TLCState s0, final TLCState s1, final CostModel cm) {
+		this.callStack.push(pred);
+		try {
+			return enabledImpl(pred, (ActionItemList) acts, c, s0, s1, cm);
+		} catch (TLCRuntimeException | EvalException e) {
+			// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context,
+			// TLCState, IStateFunctor)
+			this.callStack.freeze();
+			throw e;
+		} finally {
+			this.callStack.pop();
+		}
+	}
+
+	@Override
+	protected final TLCState enabledAppl(final OpApplNode pred, final ActionItemList acts, final Context c,
+			final TLCState s0, final TLCState s1, CostModel cm) {
+		this.callStack.push(pred);
+		try {
+			return enabledApplImpl(pred, acts, c, s0, s1, cm);
+		} catch (TLCRuntimeException | EvalException e) {
+			// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context,
+			// TLCState, IStateFunctor)
+			this.callStack.freeze();
+			throw e;
+		} finally {
+			this.callStack.pop();
+		}
+	}
+
+	@Override
+	protected final TLCState processUnchanged(final Action action, final SemanticNode expr, final ActionItemList acts,
+			final Context c, final TLCState s0, final TLCState s1, final INextStateFunctor nss, CostModel cm) {
+		this.callStack.push(expr);
+		try {
+			return processUnchangedImpl(action, expr, acts, c, s0, s1, nss, cm);
+		} catch (TLCRuntimeException | EvalException e) {
+			// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context,
+			// TLCState, IStateFunctor)
+			this.callStack.freeze();
+			throw e;
+		} finally {
+			this.callStack.pop();
+		}
+	}
+
+	@Override
+	protected final TLCState enabledUnchanged(final SemanticNode expr, final ActionItemList acts, final Context c,
+			final TLCState s0, final TLCState s1, final CostModel cm) {
+		this.callStack.push(expr);
+		try {
+			return enabledUnchangedImpl(expr, acts, c, s0, s1, cm);
+		} catch (TLCRuntimeException | EvalException e) {
+			// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context,
+			// TLCState, IStateFunctor)
+			this.callStack.freeze();
+			throw e;
+		} finally {
+			this.callStack.pop();
+		}
+	}
+
+	@Override
+	protected final Value setSource(final SemanticNode expr, final Value value) {
+		value.setSource(expr);
+		return value;
+	}
+}
diff --git a/tlatools/src/tlc2/tool/impl/Evaluator.java b/tlatools/src/tlc2/tool/impl/Evaluator.java
new file mode 100644
index 0000000000000000000000000000000000000000..a4f9a54d9e0187d0bfca69a956065a14dabd6f30
--- /dev/null
+++ b/tlatools/src/tlc2/tool/impl/Evaluator.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool.impl;
+
+import tla2sany.semantic.ExprOrOpArgNode;
+import tlc2.tool.TLCState;
+import tlc2.tool.coverage.CostModel;
+import tlc2.util.Context;
+import tlc2.value.impl.Value;
+
+public interface Evaluator {
+
+	Value eval(Tool tool, ExprOrOpArgNode[] args, Context c, TLCState s0, TLCState s1, int control, CostModel cm);
+
+}
diff --git a/tlatools/src/tlc2/tool/impl/FastTool.java b/tlatools/src/tlc2/tool/impl/FastTool.java
new file mode 100644
index 0000000000000000000000000000000000000000..89b71cf2b584b808e2d0e393b0ea0a5d9fc4c5f7
--- /dev/null
+++ b/tlatools/src/tlc2/tool/impl/FastTool.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool.impl;
+
+import tla2sany.semantic.OpApplNode;
+import tla2sany.semantic.SemanticNode;
+import tlc2.tool.Action;
+import tlc2.tool.IActionItemList;
+import tlc2.tool.INextStateFunctor;
+import tlc2.tool.TLCState;
+import tlc2.tool.coverage.CostModel;
+import tlc2.util.Context;
+import tlc2.util.ExpectInlined;
+import tlc2.value.impl.Value;
+import util.FilenameToStream;
+
+public final class FastTool extends Tool {
+
+	public FastTool(String mainFile, String configFile) {
+		super(mainFile, configFile);
+	}
+
+	public FastTool(String mainFile, String configFile, FilenameToStream resolver) {
+		super(mainFile, configFile, resolver);
+	}
+
+	public FastTool(String specDir, String specFile, String configFile, FilenameToStream fts) {
+		super(specDir, specFile, configFile, fts);
+	}
+
+	// The methods below are supposed to be inlined during execution for performance
+	// reasons, collapsing this class effectively into Tool. Later and in case of a
+	// violation, the FastTool instance will be exchanged for the CallStackTool
+	// instance that properly records error for the purpose of error reporting.
+	@ExpectInlined
+	@Override
+	protected final TLCState getNextStates(final Action action, final SemanticNode pred, final ActionItemList acts,
+			final Context c, final TLCState s0, final TLCState s1, final INextStateFunctor nss, final CostModel cm) {
+		return getNextStatesImpl(action, pred, acts, c, s0, s1, nss, cm);
+	}
+
+	@ExpectInlined
+	@Override
+	protected final TLCState getNextStatesAppl(final Action action, final OpApplNode pred, final ActionItemList acts,
+			final Context c, final TLCState s0, final TLCState s1, final INextStateFunctor nss, final CostModel cm) {
+		return getNextStatesApplImpl(action, pred, acts, c, s0, s1, nss, cm);
+	}
+
+	@ExpectInlined
+	@Override
+	protected final TLCState processUnchanged(final Action action, final SemanticNode expr, final ActionItemList acts,
+			final Context c, final TLCState s0, final TLCState s1, final INextStateFunctor nss, final CostModel cm) {
+		return processUnchangedImpl(action, expr, acts, c, s0, s1, nss, cm);
+	}
+
+	@ExpectInlined
+	@Override
+	public final Value eval(final SemanticNode expr, final Context c, final TLCState s0, final TLCState s1,
+			final int control, final CostModel cm) {
+		return evalImpl(expr, c, s0, s1, control, cm);
+	}
+
+	@ExpectInlined
+	@Override
+	protected final Value evalAppl(final OpApplNode expr, final Context c, final TLCState s0, final TLCState s1,
+			final int control, final CostModel cm) {
+		return evalApplImpl(expr, c, s0, s1, control, cm);
+	}
+
+	@ExpectInlined
+	@Override
+	protected final Value setSource(final SemanticNode expr, final Value value) {
+		return value;
+	}
+
+	@ExpectInlined
+	@Override
+	public final TLCState enabled(final SemanticNode pred, final IActionItemList acts, final Context c,
+			final TLCState s0, final TLCState s1, final CostModel cm) {
+		return enabledImpl(pred, (ActionItemList) acts, c, s0, s1, cm); // TODO This cast sucks performance-wise.
+	}
+
+	@ExpectInlined
+	@Override
+	protected final TLCState enabledAppl(final OpApplNode pred, final ActionItemList acts, final Context c,
+			final TLCState s0, final TLCState s1, final CostModel cm) {
+		return enabledApplImpl(pred, acts, c, s0, s1, cm);
+	}
+
+	@ExpectInlined
+	@Override
+	protected final TLCState enabledUnchanged(final SemanticNode expr, final ActionItemList acts, final Context c,
+			final TLCState s0, final TLCState s1, final CostModel cm) {
+		return enabledUnchangedImpl(expr, acts, c, s0, s1, cm);
+	}
+}
diff --git a/tlatools/src/tlc2/tool/impl/ModelConfig.java b/tlatools/src/tlc2/tool/impl/ModelConfig.java
index af920417521a86ae40899fb2b9c52bcab47f9e65..0504769e9e80f010ce7767f4cc1e117ef5c1b9f7 100644
--- a/tlatools/src/tlc2/tool/impl/ModelConfig.java
+++ b/tlatools/src/tlc2/tool/impl/ModelConfig.java
@@ -30,32 +30,41 @@ import tlc2.value.impl.ValueVec;
 import util.FileUtil;
 import util.FilenameToStream;
 import util.SimpleFilenameToStream;
+import util.TLAConstants;
 
 /** 
  * Stores information from user's model configuration file.
+ * 
+ * TODO we should move from Hashtable to HashMap (we should probably also stop using our own collection implmentations
+ * 			like {@link Vect}.)
+ * TODO we're storing a heterogeneous mishmash in the values of configTbl - sometimes a Vect, sometimes a String, sometime
+ * 			that Vect has only String instances, sometimes is has a String instance and Value subclasses, ... it would
+ * 			be nice were the design cleaner.
+ * 
  * @author Yuan Yu, Leslie Lamport
  */
-public class ModelConfig implements ValueConstants, Serializable
-{
+public class ModelConfig implements ValueConstants, Serializable {
     // keywords of the configuration file
-    private static final String Constant = "CONSTANT";
-    private static final String Constants = "CONSTANTS";
+    private static final String Constant = TLAConstants.KeyWords.CONSTANT;
+    private static final String Constants = TLAConstants.KeyWords.CONSTANTS;
     private static final String Constraint = "CONSTRAINT";
     private static final String Constraints = "CONSTRAINTS";
-    private static final String ActionConstraint = "ACTION_CONSTRAINT";
-    private static final String ActionConstraints = "ACTION_CONSTRAINTS";
-    private static final String Invariant = "INVARIANT";
-    private static final String Invariants = "INVARIANTS";
-    private static final String Init = "INIT";
-    private static final String Next = "NEXT";
+    private static final String ActionConstraint = TLAConstants.KeyWords.ACTION_CONSTRAINT;
+    private static final String ActionConstraints = ActionConstraint + 'S';
+    private static final String Invariant = TLAConstants.KeyWords.INVARIANT;
+    private static final String Invariants = Invariant + 'S';
+    private static final String Init = TLAConstants.KeyWords.INIT;
+    private static final String Next = TLAConstants.KeyWords.NEXT;
     private static final String View = "VIEW";
-    private static final String Symmetry = "SYMMETRY";
-    private static final String Spec = "SPECIFICATION";
-    private static final String Prop = "PROPERTY";
+    private static final String Symmetry = TLAConstants.KeyWords.SYMMETRY;
+    private static final String Spec = TLAConstants.KeyWords.SPECIFICATION;
+    private static final String Prop = TLAConstants.KeyWords.PROPERTY;
     private static final String Props = "PROPERTIES";
     private static final String Type = "TYPE";
     private static final String TypeConstraint = "TYPE_CONSTRAINT";
 
+    private static final long serialVersionUID = 1L;
+
     /**
      * All keywords used in the configuration file
      */
@@ -64,7 +73,8 @@ public class ModelConfig implements ValueConstants, Serializable
             TypeConstraint };
 
     private Hashtable configTbl;
-    private Hashtable overrides;
+    private Hashtable<String, String> overrides;
+    private Hashtable<String, String> overridesReverseMap;
     private Hashtable modConstants;
     private Hashtable modOverrides;
     private String configFileName;
@@ -118,6 +128,7 @@ public class ModelConfig implements ValueConstants, Serializable
         this.modConstants = new Hashtable<>();
         this.modOverrides = new Hashtable<>();
         this.overrides = new Hashtable<>();
+        this.overridesReverseMap = new Hashtable<>();
     }
 
     /**
@@ -308,7 +319,9 @@ public class ModelConfig implements ValueConstants, Serializable
                                     throw new ConfigFileException(EC.CFG_EXPECT_ID, new String[] {
                                             String.valueOf(scs.getBeginLine()), "<-" });
                                 }
-                                this.overrides.put(line.elementAt(0), tt.image);
+                                final String string = (String)line.elementAt(0);
+                                this.overrides.put(string, tt.image);
+                                this.overridesReverseMap.put(tt.image, string);
                             }
                         } else
                         {
@@ -490,10 +503,14 @@ public class ModelConfig implements ValueConstants, Serializable
         return this.modConstants;
     }
 
-    public synchronized final Hashtable getOverrides()
+    public synchronized final Hashtable<String, String> getOverrides()
     {
         return this.overrides;
     }
+    
+    public synchronized final String getOverridenSpecNameForConfigName(final String configName) {
+    	return this.overridesReverseMap.get(configName);
+    }
 
     public synchronized final Hashtable getModOverrides()
     {
@@ -524,6 +541,12 @@ public class ModelConfig implements ValueConstants, Serializable
     {
         return (String) this.configTbl.get(View);
     }
+    
+    public synchronized final boolean configDefinesSpecification() {
+    	final String spec = getSpec();
+    	
+    	return ((spec != null) && (spec.trim().length() > 0));
+    }
 
     public synchronized final String getSymmetry()
     {
diff --git a/tlatools/src/tlc2/tool/impl/OpDefEvaluator.java b/tlatools/src/tlc2/tool/impl/OpDefEvaluator.java
new file mode 100644
index 0000000000000000000000000000000000000000..38d56f884fe143ca604322d6f3ff849528e84009
--- /dev/null
+++ b/tlatools/src/tlc2/tool/impl/OpDefEvaluator.java
@@ -0,0 +1,11 @@
+package tlc2.tool.impl;
+
+import tla2sany.semantic.SemanticNode;
+import tlc2.tool.TLCState;
+import tlc2.tool.coverage.CostModel;
+import tlc2.util.Context;
+import tlc2.value.IValue;
+
+public interface OpDefEvaluator {
+	IValue eval(SemanticNode body, Context empty, TLCState empty2, CostModel doNotRecord);
+}
diff --git a/tlatools/src/tlc2/tool/impl/Spec.java b/tlatools/src/tlc2/tool/impl/Spec.java
index dd9d7c60f80f9c6bcd442e64aaaaf7730160dbe6..e3b13d034e80db1a62850354ab7cb97ad8007218 100644
--- a/tlatools/src/tlc2/tool/impl/Spec.java
+++ b/tlatools/src/tlc2/tool/impl/Spec.java
@@ -14,19 +14,15 @@ import java.util.List;
 import java.util.Set;
 
 import tla2sany.modanalyzer.ParseUnit;
-import tla2sany.modanalyzer.SpecObj;
 import tla2sany.semantic.APSubstInNode;
 import tla2sany.semantic.ExprNode;
 import tla2sany.semantic.ExprOrOpArgNode;
-import tla2sany.semantic.ExternalModuleTable;
 import tla2sany.semantic.FormalParamNode;
 import tla2sany.semantic.FrontEnd;
 import tla2sany.semantic.LabelNode;
 import tla2sany.semantic.LetInNode;
 import tla2sany.semantic.ModuleNode;
 import tla2sany.semantic.OpApplNode;
-import tla2sany.semantic.OpArgNode;
-import tla2sany.semantic.OpDeclNode;
 import tla2sany.semantic.OpDefNode;
 import tla2sany.semantic.SemanticNode;
 import tla2sany.semantic.Subst;
@@ -40,21 +36,25 @@ import tlc2.tool.BuiltInOPs;
 import tlc2.tool.Defns;
 import tlc2.tool.TLCState;
 import tlc2.tool.ToolGlobals;
-import tlc2.tool.coverage.CostModel;
 import tlc2.util.Context;
 import tlc2.util.ObjLongTable;
 import tlc2.util.Vect;
-import tlc2.value.IValue;
 import tlc2.value.ValueConstants;
-import tlc2.value.impl.IntValue;
 import tlc2.value.impl.LazyValue;
 import tlc2.value.impl.ModelValue;
 import util.Assert;
 import util.FilenameToStream;
+import util.TLAConstants;
 import util.UniqueString;
 
-abstract class Spec implements ValueConstants, ToolGlobals, Serializable
-{
+// Note that we use all of the {@code default} defined functionality in our
+//		implemented interface {@link SymbolNodeValueLookupProvider} (and our
+//		lack of implementation of {@link OpDefEvaluator} is why this class
+//		is marked {@code abstract}.)
+abstract class Spec
+		implements ValueConstants, ToolGlobals, Serializable, OpDefEvaluator, SymbolNodeValueLookupProvider {
+	private static final long serialVersionUID = 1L;
+
 	/**
 	 * @see See note on performance in CostModelCreator.
 	 */
@@ -65,42 +65,21 @@ abstract class Spec implements ValueConstants, ToolGlobals, Serializable
 	protected final String specDir; // The spec directory.
     protected final String rootFile; // The root file of this spec.
     protected final String configFile; // The model config file.
-    protected final ModelConfig config; // The model configuration.
-    protected final ExternalModuleTable moduleTbl; // The external modules reachable from root
-    protected final ModuleNode rootModule; // The root module.
     protected final Set<OpDefNode> processedDefs ; 
-    protected final SpecObj specObj;
       // The set of OpDefNodes on which processSpec has been called.
       // Added by LL & YY on 25 June 2014 to eliminate infinite
       // loop when a recursively defined operator is used as an
       // operator argument in its own definition.
     protected final Defns defns; // Global definitions reachable from root
 	protected final Defns unprocessedDefns;
-    // SZ 10.04.2009: changed the name of the variable to reflect its nature
-    protected final OpDeclNode[] variablesNodes; // The state variables.
     protected final TLAClass tlaClass; // TLA built-in classes.
-    protected final Vect<Action> initPredVec; // The initial state predicate.
-    protected final Action nextPred; // The next state predicate.
-    protected final Action[] temporals; // Fairness specifications...
-    protected final String[] temporalNames; // ... and their names
-    protected final Action[] impliedTemporals; // Liveness conds to check...
-    protected final String[] impliedTemporalNames; // ... and their names
-    protected final Action[] invariants; // Invariants to be checked...
-    protected final String[] invNames; // ... and their names
-    protected final Action[] impliedInits; // Implied-inits to be checked...
-    protected final String[] impliedInitNames; // ... and their names
-    protected final Action[] impliedActions; // Implied-actions to be checked...
-    protected final String[] impliedActNames; // ... and their names
-    protected final ExprNode[] modelConstraints; // Model constraints
-    protected final ExprNode[] actionConstraints; // Action constraints
-    protected final ExprNode[] assumptions; // Assumpt	ions
-    protected final boolean[] assumptionIsAxiom; // assumptionIsAxiom[i] is true iff assumptions[i]
-                                           // is an AXIOM.  Added 26 May 2010 by LL
     private final FilenameToStream resolver; // takes care of path to stream resolution
 
+    protected final ModelConfig config; // The model configuration.
+    private final SpecProcessor specProcessor;
+
     // SZ Feb 20, 2009: added support to name resolver, to be able to run outside of the tool
-    public Spec(String specDir, String specFile, String configFile, FilenameToStream resolver)
-    {
+	public Spec(final String specDir, final String specFile, final String configFile, final FilenameToStream resolver) {
         this.specDir = specDir;
         this.rootFile = specFile;
         this.defns = new Defns();
@@ -111,98 +90,34 @@ abstract class Spec implements ValueConstants, ToolGlobals, Serializable
         // SZ Mar 9, 2009: added initialization of the modelValue class
         ModelValue.init();
         this.configFile = configFile;
-        this.config = new ModelConfig(configFile + ".cfg", resolver);
+        this.config = new ModelConfig(configFile + TLAConstants.Files.CONFIG_EXTENSION, resolver);
         this.config.parse();
         ModelValue.setValues(); // called after seeing all model values
 
-		// SpecProcessor has be factored out to be able to assign the variables below as
-		// final. SpecProcessor duplicates most of the variables here but I don't have
-		// time to clean it up.
-		final SpecProcessor processor = new SpecProcessor(rootFile, resolver, toolId, defns, config, this, tlaClass);
-        this.rootModule = processor.getRootModule();
-        this.moduleTbl = processor.getModuleTbl();
-        this.variablesNodes = processor.getVariablesNodes();
-        this.initPredVec = processor.getInitPred();
-        this.nextPred = processor.getNextPred();
-        this.temporals = processor.getTemporal();
-        this.temporalNames = processor.getTemporalNames();
-        this.impliedTemporals = processor.getImpliedTemporals();
-        this.impliedTemporalNames = processor.getImpliedTemporalNames();
-        this.invariants = processor.getInvariants();
-        this.invNames = processor.getInvariantsNames();
-        this.impliedInits = processor.getImpliedInits();
-        this.impliedInitNames = processor.getImpliedInitNames();
-        this.impliedActions = processor.getImpliedActions();
-        this.impliedActNames = processor.getImpliedActionNames();
-        this.modelConstraints = processor.getModelConstraints();
-        this.actionConstraints = processor.getActionConstraints();
-        this.assumptions = processor.getAssumptions();
-        this.assumptionIsAxiom = processor.getAssumptionIsAxiom();
-        this.specObj = processor.getSpecObj();
+        specProcessor = new SpecProcessor(getRootName(), resolver, toolId, defns, config, this, this, tlaClass);
         
-        this.unprocessedDefns = processor.getUnprocessedDefns();
+        this.unprocessedDefns = specProcessor.getUnprocessedDefns();
     }
     
-    protected Spec(Spec other) {
+    protected Spec(final Spec other) {
     	this.specDir = other.specDir;
     	this.rootFile = other.rootFile;
     	this.configFile = other.configFile;
-    	this.config = other.config;
-    	this.moduleTbl = other.moduleTbl;
-    	this.rootModule = other.rootModule;
     	this.processedDefs = other.processedDefs;
     	this.defns = other.defns;
-    	this.variablesNodes = other.variablesNodes;
     	this.tlaClass = other.tlaClass;
-        this.initPredVec = other.initPredVec;
-    	this.nextPred = other.nextPred;
-    	this.temporals = other.temporals;
-    	this.temporalNames = other.temporalNames;
-    	this.impliedTemporals = other.impliedTemporals;
-    	this.impliedTemporalNames = other.impliedTemporalNames;
-    	this.invariants = other.invariants;
-    	this.invNames = other.invNames;
-    	this.impliedInits = other.impliedInits;
-        this.impliedInitNames = other.impliedInitNames;
-        this.impliedActions = other.impliedActions;
-        this.impliedActNames = other.impliedActNames;
-        this.modelConstraints = other.modelConstraints;
-        this.actionConstraints = other.actionConstraints;
-        this.assumptions = other.assumptions;
-        this.assumptionIsAxiom = other.assumptionIsAxiom;
         this.resolver = other.resolver;
-        this.specObj = other.specObj;
         this.unprocessedDefns = other.unprocessedDefns;
+    	this.config = other.config;
+        this.specProcessor = other.specProcessor;
     }
-
-    /* Return the variable if expr is a state variable. Otherwise, null. */
-    public final SymbolNode getVar(SemanticNode expr, Context c, boolean cutoff)
-    {
-        if (expr instanceof OpApplNode)
-        {
-            SymbolNode opNode = ((OpApplNode) expr).getOperator();
-
-            if (opNode.getArity() == 0)
-            {
-                boolean isVarDecl = (opNode.getKind() == VariableDeclKind);
-                Object val = this.lookup(opNode, c, cutoff && isVarDecl);
-
-                if (val instanceof LazyValue)
-                {
-                    LazyValue lval = (LazyValue) val;
-                    return this.getVar(lval.expr, lval.con, cutoff);
-                }
-                if (val instanceof OpDefNode)
-                {
-                    return this.getVar(((OpDefNode) val).getBody(), c, cutoff);
-                }
-                if (isVarDecl)
-                {
-                    return opNode;
-                }
-            }
-        }
-        return null;
+    
+    public ModelConfig getModelConfig() {
+    	return config;
+    }
+    
+    public SpecProcessor getSpecProcessor() {
+    	return specProcessor;
     }
 
     /* Return the variable if expr is a primed state variable. Otherwise, null. */
@@ -215,13 +130,13 @@ abstract class Spec implements ValueConstants, ToolGlobals, Serializable
 
             if (BuiltInOPs.getOpCode(opNode.getName()) == OPCODE_prime)
             {
-                return this.getVar(expr1.getArgs()[0], c, cutoff);
+                return this.getVar(expr1.getArgs()[0], c, cutoff, toolId);
             }
 
             if (opNode.getArity() == 0)
             {
                 boolean isVarDecl = (opNode.getKind() == VariableDeclKind);
-                Object val = this.lookup(opNode, c, cutoff && isVarDecl);
+                Object val = this.lookup(opNode, c, cutoff && isVarDecl, toolId);
 
                 if (val instanceof LazyValue)
                 {
@@ -240,30 +155,26 @@ abstract class Spec implements ValueConstants, ToolGlobals, Serializable
     /** 
      * Get model constraints.  
      */
-    public final ExprNode[] getModelConstraints()
-    {
-        return this.modelConstraints;
-    }
+	public final ExprNode[] getModelConstraints() {
+		return specProcessor.getModelConstraints();
+	}
 
     /**
      * Get action constraints.  
      */
-    public final ExprNode[] getActionConstraints()
-    {
-        return this.actionConstraints;
-    }
+	public final ExprNode[] getActionConstraints() {
+		return specProcessor.getActionConstraints();
+	}
 
     /* Get the initial state predicate of the specification.  */
-    public final Vect<Action> getInitStateSpec()
-    {
-        return this.initPredVec;
-    }
+	public final Vect<Action> getInitStateSpec() {
+		return specProcessor.getInitPred();
+	}
 
     /* Get the action (next state) predicate of the specification. */
-    public final Action getNextStateSpec()
-    {
-        return this.nextPred;
-    }
+	public final Action getNextStateSpec() {
+		return specProcessor.getNextPred();
+	}
 
     /** 
      * Get the view mapping for the specification. 
@@ -344,76 +255,67 @@ abstract class Spec implements ValueConstants, ToolGlobals, Serializable
         return def.getBody();
     }
 
-    public final boolean livenessIsTrue()
-    {
-        return this.impliedTemporals.length == 0;
-    }
+	public final boolean livenessIsTrue() {
+		return getImpliedTemporals().length == 0;
+	}
 
     /* Get the fairness condition of the specification.  */
     public final Action[] getTemporals()
     {
-        return this.temporals;
+        return specProcessor.getTemporal();
     }
 
     public final String[] getTemporalNames()
     {
-        return this.temporalNames;
+        return specProcessor.getTemporalNames();
     }
 
     /* Get the liveness checks of the specification.  */
-    public final Action[] getImpliedTemporals()
-    {
-        return this.impliedTemporals;
-    }
+	public final Action[] getImpliedTemporals() {
+		return specProcessor.getImpliedTemporals();
+	}
 
-    public final String[] getImpliedTemporalNames()
-    {
-        return this.impliedTemporalNames;
-    }
+	public final String[] getImpliedTemporalNames() {
+		return specProcessor.getImpliedTemporalNames();
+	}
 
     /* Get the invariants of the specification. */
-    public final Action[] getInvariants()
-    {
-        return this.invariants;
-    }
+	public final Action[] getInvariants() {
+		return specProcessor.getInvariants();
+	}
 
-    public final String[] getInvNames()
-    {
-        return this.invNames;
-    }
+	public final String[] getInvNames() {
+		return specProcessor.getInvariantsNames();
+	}
 
     /* Get the implied-inits of the specification. */
-    public final Action[] getImpliedInits()
-    {
-        return this.impliedInits;
-    }
+	public final Action[] getImpliedInits() {
+		return specProcessor.getImpliedInits();
+	}
 
-    public final String[] getImpliedInitNames()
-    {
-        return this.impliedInitNames;
-    }
+	public final String[] getImpliedInitNames() {
+		return specProcessor.getImpliedInitNames();
+	}
 
     /* Get the implied-actions of the specification. */
-    public final Action[] getImpliedActions()
-    {
-        return this.impliedActions;
-    }
+	public final Action[] getImpliedActions() {
+		return specProcessor.getImpliedActions();
+	}
 
-    public final String[] getImpliedActNames()
-    {
-        return this.impliedActNames;
-    }
+	public final String[] getImpliedActNames() {
+		return specProcessor.getImpliedActionNames();
+	}
 
     /* Get the assumptions of the specification. */
-    public final ExprNode[] getAssumptions()
-    {
-        return this.assumptions;
-    }
+	public final ExprNode[] getAssumptions() {
+		return specProcessor.getAssumptions();
+	}
     
     /* Get the assumptionIsAxiom field */
     public final boolean[] getAssumptionIsAxiom() {
-        return this.assumptionIsAxiom;
+        return specProcessor.getAssumptionIsAxiom();
     }
+    
     /**
      * This method gets the value of a symbol from the environment. We
      * look up in the context c, its tool object, and the state s.
@@ -447,7 +349,7 @@ abstract class Spec implements ValueConstants, ToolGlobals, Serializable
      */
     public final Object lookup(SymbolNode opNode, Context c, TLCState s, boolean cutoff)
     {
-    	Object result = lookup(opNode, c, cutoff);
+    	Object result = lookup(opNode, c, cutoff, toolId);
     	if (result != opNode) {
     		return result;
     	}
@@ -458,73 +360,8 @@ abstract class Spec implements ValueConstants, ToolGlobals, Serializable
         return opNode;
     }
 
-    public final Object lookup(SymbolNode opNode, Context c, boolean cutoff)
-    {
-        boolean isVarDecl = (opNode.getKind() == VariableDeclKind);
-        Object result = c.lookup(opNode, cutoff && isVarDecl);
-        if (result != null) {
-        	return result;
-        }
-
-        result = opNode.getToolObject(toolId);
-        if (result != null) {
-        	return result;
-        }
-
-        if (opNode.getKind() == UserDefinedOpKind)
-        {
-            // Changed by LL on 10 Apr 2011 from
-            //
-            //    result = ((OpDefNode) opNode).getBody().getToolObject(toolId);
-            //
-            // to the following
-            ExprNode body = ((OpDefNode) opNode).getBody();
-            result = body.getToolObject(toolId);
-            while ((result == null) && (body.getKind() == SubstInKind)) {
-                body = ((SubstInNode) body).getBody();
-                result = body.getToolObject(toolId);
-            }
-            // end change
-
-            if (result != null) {
-            	return result;
-            }
-        }
-        return opNode;
-    }
     public final Object lookup(final SymbolNode opNode) {
-    	return lookup(opNode, Context.Empty, false);
-    }
-    public final Object getVal(ExprOrOpArgNode expr, Context c, final boolean cachable)
-    {
-    	return getVal(expr, c, cachable, CostModel.DO_NOT_RECORD);
-    }
-
-    public final Object getVal(ExprOrOpArgNode expr, Context c, final boolean cachable, CostModel cm)
-    {
-        if (expr instanceof ExprNode)
-        {
-            return new LazyValue(expr, c, cachable, cm);
-        }
-        SymbolNode opNode = ((OpArgNode) expr).getOp();
-        return this.lookup(opNode, c, false);
-    }
-    public final Context getOpContext(OpDefNode opDef, ExprOrOpArgNode[] args, Context c, boolean cachable)
-    {
-    	return getOpContext(opDef, args, c, cachable, CostModel.DO_NOT_RECORD);
-    }
-
-    public final Context getOpContext(OpDefNode opDef, ExprOrOpArgNode[] args, Context c, boolean cachable, final CostModel cm)
-    {
-        FormalParamNode[] formals = opDef.getParams();
-        int alen = args.length;
-        Context c1 = c;
-        for (int i = 0; i < alen; i++)
-        {
-            Object aval = this.getVal(args[i], c, cachable, cm);
-            c1 = c1.cons(formals[i], aval);
-        }
-        return c1;
+    	return lookup(opNode, Context.Empty, false, toolId);
     }
 
     /**
@@ -544,11 +381,12 @@ abstract class Spec implements ValueConstants, ToolGlobals, Serializable
         Context c1 = c;
         for (int i = 0; i < alen; i++)
         {
-            Object aval = this.getVal(args[i], c, cachable);
+            Object aval = this.getVal(args[i], c, cachable, toolId);
             c1 = c1.cons(formals[i], aval);
         }
         return c1;
     }
+    
     /**
      * Return a table containing the locations of subexpression in the
      * spec of forms x' = e and x' \in e. Warning: Current implementation
@@ -589,7 +427,7 @@ abstract class Spec implements ValueConstants, ToolGlobals, Serializable
             for (int i = 0; i < subs.length; i++)
             {
                 Subst sub = subs[i];
-                c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true));
+                c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true, toolId));
             }
             this.collectPrimedLocs(pred1.getBody(), c, tbl);
             return;
@@ -603,7 +441,7 @@ abstract class Spec implements ValueConstants, ToolGlobals, Serializable
             for (int i = 0; i < subs.length; i++)
             {
                 Subst sub = subs[i];
-                c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true));
+                c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true, toolId));
             }
             this.collectPrimedLocs(pred1.getBody(), c, tbl);
             return;
@@ -690,7 +528,7 @@ abstract class Spec implements ValueConstants, ToolGlobals, Serializable
         default: {
             if (opcode == 0)
             {
-                Object val = this.lookup(opNode, c, false);
+                Object val = this.lookup(opNode, c, false, toolId);
 
                 if (val instanceof OpDefNode)
                 {
@@ -700,7 +538,7 @@ abstract class Spec implements ValueConstants, ToolGlobals, Serializable
                     if (opDef.getInRecursive()) {
                         return ;
                     }
-                    Context c1 = this.getOpContext(opDef, args, c, true);
+                    Context c1 = this.getOpContext(opDef, args, c, true, toolId);
                     this.collectPrimedLocs(opDef.getBody(), c1, tbl);
                 } else if (val instanceof LazyValue)
                 {
@@ -749,7 +587,7 @@ abstract class Spec implements ValueConstants, ToolGlobals, Serializable
             if (opcode == 0 && args.length == 0)
             {
                 // a 0-arity operator:
-                Object val = this.lookup(opNode, c, false);
+                Object val = this.lookup(opNode, c, false, toolId);
                 if (val instanceof OpDefNode)
                 {
                     this.collectUnchangedLocs(((OpDefNode) val).getBody(), c, tbl);
@@ -760,155 +598,21 @@ abstract class Spec implements ValueConstants, ToolGlobals, Serializable
         return;
     }
 
-    /**
-     * This method only returns an approximation of the level of the
-     * expression.  The "real" level is at most the return value. Adding
-     * <name, ValOne> to the context means that there is no need to
-     * compute level for name.
-     *
-     * Note that this method does not work if called on a part of an
-     * EXCEPT expression.
-     */
-    public final int getLevelBound(SemanticNode expr, Context c)
-    {
-        switch (expr.getKind()) {
-        case OpApplKind: {
-            OpApplNode expr1 = (OpApplNode) expr;
-            return this.getLevelBoundAppl(expr1, c);
-        }
-        case LetInKind: {
-            LetInNode expr1 = (LetInNode) expr;
-            OpDefNode[] letDefs = expr1.getLets();
-            int letLen = letDefs.length;
-            Context c1 = c;
-            int level = 0;
-            for (int i = 0; i < letLen; i++)
-            {
-                OpDefNode opDef = letDefs[i];
-                level = Math.max(level, this.getLevelBound(opDef.getBody(), c1));
-                c1 = c1.cons(opDef, IntValue.ValOne);
-            }
-            return Math.max(level, this.getLevelBound(expr1.getBody(), c1));
-        }
-        case SubstInKind: {
-            SubstInNode expr1 = (SubstInNode) expr;
-            Subst[] subs = expr1.getSubsts();
-            int slen = subs.length;
-            Context c1 = c;
-            for (int i = 0; i < slen; i++)
-            {
-                Subst sub = subs[i];
-                c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true));
-            }
-            return this.getLevelBound(expr1.getBody(), c1);
-        }
-
-        // Added by LL on 13 Nov 2009 to handle theorem and assumption names.
-        case APSubstInKind: {
-            APSubstInNode expr1 = (APSubstInNode) expr;
-            Subst[] subs = expr1.getSubsts();
-            int slen = subs.length;
-            Context c1 = c;
-            for (int i = 0; i < slen; i++)
-            {
-                Subst sub = subs[i];
-                c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true));
-            }
-            return this.getLevelBound(expr1.getBody(), c1);
-        }
-
-
-            /***********************************************************************
-            * LabelKind case added by LL on 13 Jun 2007.                           *
-            ***********************************************************************/
-        case LabelKind: {
-            LabelNode expr1 = (LabelNode) expr;
-            return this.getLevelBound(expr1.getBody(), c);
-        }
-        default: {
-            return 0;
-        }
-        }
-    }
-
-    private final int getLevelBoundAppl(OpApplNode expr, Context c)
-    {
-        SymbolNode opNode = expr.getOperator();
-        UniqueString opName = opNode.getName();
-        int opcode = BuiltInOPs.getOpCode(opName);
-
-        if (BuiltInOPs.isTemporal(opcode))
-        {
-            return 3; // Conservative estimate
-        }
-
-        if (BuiltInOPs.isAction(opcode))
-        {
-            return 2; // Conservative estimate
-        }
-
-        if (opcode == OPCODE_enabled)
-        {
-            return 1; // Conservative estimate
-        }
-
-        int level = 0;
-        ExprNode[] bnds = expr.getBdedQuantBounds();
-        for (int i = 0; i < bnds.length; i++)
-        {
-            level = Math.max(level, this.getLevelBound(bnds[i], c));
-        }
-
-        if (opcode == OPCODE_rfs)
-        {
-            // For recursive function, don't compute level of the function body
-            // again in the recursive call.
-            SymbolNode fname = expr.getUnbdedQuantSymbols()[0];
-            c = c.cons(fname, IntValue.ValOne);
-        }
-
-        ExprOrOpArgNode[] args = expr.getArgs();
-        int alen = args.length;
-        for (int i = 0; i < alen; i++)
-        {
-            if (args[i] != null)
-            {
-                level = Math.max(level, this.getLevelBound(args[i], c));
-            }
-        }
-
-        if (opcode == 0)
-        {
-            // This operator is a user-defined operator.
-            if (opName.getVarLoc() >= 0)
-                return 1;
-
-            Object val = this.lookup(opNode, c, false);
-            if (val instanceof OpDefNode)
-            {
-                OpDefNode opDef = (OpDefNode) val;
-                c = c.cons(opNode, IntValue.ValOne);
-                level = Math.max(level, this.getLevelBound(opDef.getBody(), c));
-            } else if (val instanceof LazyValue)
-            {
-                LazyValue lv = (LazyValue) val;
-                level = Math.max(level, this.getLevelBound(lv.expr, lv.con));
-            }
-        }
-        return level;
-    }
-
     public FilenameToStream getResolver()
     {
         return resolver;
     }
     
+    public String getRootName() {
+    	return new File(this.rootFile).getName();
+    }
+    
     public String getRootFile() {
     	return this.rootFile;
     }
 
     public ModuleNode getRootModule() {
-        return this.rootModule;
+        return this.getSpecProcessor().getRootModule();
     }
 
     public String getConfigFile() {
@@ -923,12 +627,10 @@ abstract class Spec implements ValueConstants, ToolGlobals, Serializable
     	return toolId;
     }
 
-	abstract IValue eval(SemanticNode body, Context empty, TLCState empty2, CostModel doNotRecord);
-
 	public List<File> getModuleFiles(final FilenameToStream resolver) {
 		final List<File> result = new ArrayList<File>();
 	
-		final Enumeration<ParseUnit> parseUnitContext = this.specObj.parseUnitContext.elements();
+		final Enumeration<ParseUnit> parseUnitContext = specProcessor.getSpecObj().parseUnitContext.elements();
 		while (parseUnitContext.hasMoreElements()) {
 			ParseUnit pu = (ParseUnit) parseUnitContext.nextElement();
 			File resolve = resolver.resolve(pu.getFileName(), false);
diff --git a/tlatools/src/tlc2/tool/impl/SpecProcessor.java b/tlatools/src/tlc2/tool/impl/SpecProcessor.java
index 4c135a163046fa83fd9bfd260a8ec09f8e613a45..71955b61de1b2d4e265abc39301ea9d2d5d445ca 100644
--- a/tlatools/src/tlc2/tool/impl/SpecProcessor.java
+++ b/tlatools/src/tlc2/tool/impl/SpecProcessor.java
@@ -64,16 +64,16 @@ import tlc2.TLCGlobals;
 import tlc2.module.BuiltInModuleHelper;
 import tlc2.output.EC;
 import tlc2.output.MP;
+import tlc2.overrides.Evaluation;
+import tlc2.overrides.ITLCOverrides;
+import tlc2.overrides.TLAPlusOperator;
 import tlc2.tool.Action;
 import tlc2.tool.BuiltInOPs;
 import tlc2.tool.Defns;
-import tlc2.tool.EvalControl;
 import tlc2.tool.EvalException;
 import tlc2.tool.Specs;
-import tlc2.tool.TLCState;
 import tlc2.tool.TLCStateMut;
 import tlc2.tool.ToolGlobals;
-import tlc2.tool.coverage.CostModel;
 import tlc2.util.Context;
 import tlc2.util.List;
 import tlc2.util.Vect;
@@ -81,6 +81,7 @@ import tlc2.value.IBoolValue;
 import tlc2.value.IValue;
 import tlc2.value.ValueConstants;
 import tlc2.value.impl.BoolValue;
+import tlc2.value.impl.EvaluatingValue;
 import tlc2.value.impl.IntValue;
 import tlc2.value.impl.LazyValue;
 import tlc2.value.impl.MethodValue;
@@ -100,7 +101,8 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
     private final int toolId;
     private final Defns defns; // Global definitions reachable from root
     private final ModelConfig config; // The model configuration.
-    private final Spec spec;
+    private final OpDefEvaluator opDefEvaluator;
+    private final SymbolNodeValueLookupProvider symbolNodeValueLookupProvider;
     private final TLAClass tlaClass;
 
     private OpDeclNode[] variablesNodes; // The state variables.
@@ -139,27 +141,32 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
     private Vect<Action> impliedTemporalVec = new Vect<>();
     private Vect<String> impliedTemporalNameVec = new Vect<>();
     
-    SpecProcessor(String rootFile, FilenameToStream resolver, int toolId, Defns defns, ModelConfig config,
-			Spec spec, TLAClass tlaClass) {
+	public SpecProcessor(final String rootFile, final FilenameToStream resolver, final int toolId, final Defns defns,
+			final ModelConfig config, final SymbolNodeValueLookupProvider snvlp, final OpDefEvaluator ode,
+			final TLAClass tlaClass) {
 		super();
 		this.rootFile = rootFile;
 		this.resolver = resolver;
 		this.toolId = toolId;
 		this.defns = defns;
 		this.config = config;
-		this.spec = spec;
 		this.tlaClass = tlaClass;
 		this.processedDefs = new HashSet<OpDefNode>();
         this.initPredVec = new Vect<>(5);
+        
+        opDefEvaluator = ode;
+        symbolNodeValueLookupProvider = snvlp;
 
 		// Parse and process this spec.
 		// It takes care of all overrides.
 		processSpec();
 
 		snapshot = defns.snapshot();
-		
-		// Pre-evaluate all the definitions in the spec that are constants.
-		processConstantDefns();
+
+		if (opDefEvaluator != null) {
+			// Pre-evaluate all the definitions in the spec that are constants.
+			processConstantDefns();
+		}
 
 	      // Finally, process the config file.
 		processConfig();
@@ -205,7 +212,11 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
       for (int i = 0; i < consts.length; i++) {
         Object val = consts[i].getToolObject(toolId);
         if (val != null && val instanceof IValue) {
-          ((IValue)val).deepNormalize();
+		  // We do not wrap this value in a WorkerValue, because we assume that explicit
+		  // initialization does not pose a problem here. This is based on the observation,
+          // that val is either an atom (IValue#isAtom) or a set (of sets) of atoms (primarily
+          // ModelValues).
+	      ((IValue)val).initialize();
           // System.err.println(consts[i].getName() + ": " + val);
         } // The following else clause was added by LL on 17 March 2012.
         else if (val != null && val instanceof OpDefNode) {
@@ -219,12 +230,12 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
 
           if (opDef.getArity() == 0) {
             try {
-              IValue defVal = spec.eval(opDef.getBody(), Context.Empty, TLCState.Empty, CostModel.DO_NOT_RECORD);
-              defVal.deepNormalize();
-              consts[i].setToolObject(toolId, defVal);
+            	Object defVal = WorkerValue.demux(opDefEvaluator, consts[i], opDef);
+                opDef.setToolObject(toolId, defVal);
             } catch (Assert.TLCRuntimeException | EvalException e) {
+              final String addendum = (e instanceof EvalException) ? "" : (" - specifically: " + e.getMessage());
               Assert.fail(EC.TLC_CONFIG_SUBSTITUTION_NON_CONSTANT,
-                  new String[] { consts[i].getName().toString(), opDef.getName().toString() });
+                  new String[] { consts[i].getName().toString(), opDef.getName().toString(), addendum });
             }
           }
         }
@@ -245,18 +256,17 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
                            && (moduleNode.getVariableDecls().length == 0) ) ;
 
         if (evaluate && opDef.getArity() == 0) {
-          Object realDef = spec.lookup(opDef, Context.Empty, false);
+          Object realDef = symbolNodeValueLookupProvider.lookup(opDef, Context.Empty, false, toolId);
           if (realDef instanceof OpDefNode) {
             opDef = (OpDefNode)realDef;
-            if (spec.getLevelBound(opDef.getBody(), Context.Empty) == 0) {
+            if (symbolNodeValueLookupProvider.getLevelBound(opDef.getBody(), Context.Empty, toolId) == 0) {
               try {
                 UniqueString opName = opDef.getName();
                 if (isVetoed(opName)) {
                 	continue DEFS;
                 }
                 // System.err.println(opName);
-                IValue val = spec.eval(opDef.getBody(), Context.Empty, TLCState.Empty, CostModel.DO_NOT_RECORD);
-                val.deepNormalize();
+                final Object val = WorkerValue.demux(opDefEvaluator, opDef);
                 // System.err.println(opName + ": " + val);
                 opDef.setToolObject(toolId, val);
                 Object def = this.defns.get(opName);
@@ -264,9 +274,13 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
                   this.defns.put(opName, val);
                 }
               }
-              catch (Throwable e) {
-                // Assert.printStack(e);
-              }
+              catch (Throwable swallow) {
+				// We get here when Op fails to evaluate. e is swallowed because Op might e.g. be 
+            	// Reals!Infinity from the standard module that has to be redefined iff it appears
+              	// in the actual spec. Another example is TLC!TLCGet(42) that the code above 
+              	// attempts to evaluate that fails with an EvalException. By definition, TLCGet
+              	// is not constant. 
+			  }
             }
           }
         }
@@ -341,6 +355,10 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
         this.moduleTbl = specObj.getExternalModuleTable();
         UniqueString rootName = UniqueString.uniqueStringOf(this.rootFile);
         this.rootModule = this.moduleTbl.getModuleNode(rootName);
+        
+		Assert.check(this.rootModule != null, EC.TLC_PARSING_FAILED2,
+				String.format(" Module-Table lookup failure for module name %s derived from %s file name.",
+						rootName.toString(), this.rootFile));
 
         // Get all the state variables in the spec:
         OpDeclNode[] varDecls = this.rootModule.getVariableDecls();
@@ -377,7 +395,7 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
         elems[1] = BoolValue.ValTrue;
         this.defns.put("BOOLEAN", new SetEnumValue(elems, true));
 
-        Class stringModule = this.tlaClass.loadClass("Strings");
+        Class<?> stringModule = this.tlaClass.loadClass("Strings");
         if (stringModule == null)
         {
 
@@ -485,7 +503,7 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
         {
         	
         	final UniqueString modName = mods[i].getName();
-            final Class userModule = this.tlaClass.loadClass(modName.toString());
+            final Class<?> userModule = this.tlaClass.loadClass(modName.toString());
             if (userModule != null)
             {
             	final Map<UniqueString, Integer> opname2arity = new HashMap<>();
@@ -510,20 +528,24 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
                     {
                         String name = TLARegistry.mapName(method.getName());
                         UniqueString uname = UniqueString.uniqueStringOf(name);
+                        if (method.getAnnotation(TLAPlusOperator.class) != null) {
+                        	// Skip, handled below with annotation based mechanism.
+                        	continue;
+                        }
                     	final int acnt = method.getParameterCount();
-                    	final MethodValue val = MethodValue.get(method);
+                    	final Value val = MethodValue.get(method);
                         
                         if (!BuiltInModuleHelper.isBuiltInModule(userModule)) {
                     		final URL resource = userModule.getResource(userModule.getSimpleName() + ".class");
                     		// Print success or failure of loading the module override (arity mismatch).
 							final Integer arity = opname2arity.get(uname);
 							if (arity == null || arity != acnt) {
-								MP.printWarning(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_MISMATCH,
-										new String[] { uname.toString(), resource.toExternalForm(), val.toString() });
+								MP.printWarning(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_MISMATCH, uname.toString(),
+										resource.toExternalForm(), val.toString());
 							} else {
 		                        javaDefs.put(uname, val);
-								MP.printMessage(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_LOADED,
-										new String[] { uname.toString(), resource.toExternalForm(), val.toString() });
+								MP.printMessage(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_LOADED, uname.toString(),
+										resource.toExternalForm(), val.toString());
 							}
                         } else {
                             javaDefs.put(uname, val);
@@ -544,6 +566,92 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
                 }
             }
         }
+		// Load override definitions through user-provided index class. In other words,
+		// a user creates a class that implements the interface ITLCOverrides.
+		// ITLCOverride defines a single method that returns an array of classes which
+		// define Java overrides (this approach is simpler and faster than scanning
+		// the complete classpath). The convention is to name the index class
+		// "tlc2.overrides.TLCOverrides":
+        //TODO: Support multiple loader classes (MyTLCOverrides, AnotherTLCOverrides, ...).
+		final Class<?> idx = this.tlaClass.loadClass("tlc2.overrides.TLCOverrides");
+		if (idx != null && ITLCOverrides.class.isAssignableFrom(idx)) {
+			try {
+				final ITLCOverrides index = (ITLCOverrides) idx.newInstance();
+				final Class<?>[] candidateClasses = index.get();
+				for (Class<?> c : candidateClasses) {
+					final Method[] candidateMethods = c.getDeclaredMethods();
+					LOOP: for (Method m : candidateMethods) {
+						
+						
+						final Evaluation evaluation = m.getAnnotation(Evaluation.class);
+						if (evaluation != null) {
+							final Value val = new EvaluatingValue(m, evaluation.minLevel());
+							
+							final ModuleNode moduleNode = modSet.get(evaluation.module());
+							if (moduleNode == null) {
+								if (evaluation.warn()) MP.printMessage(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_MODULE_MISMATCH,
+										evaluation.module() + "!" + evaluation.definition(),
+										c.getResource(c.getSimpleName() + ".class").toExternalForm(), val.toString());
+								continue LOOP;
+							}
+							final OpDefNode opDef = moduleNode.getOpDef(evaluation.definition());
+							if (opDef == null) {
+								if (evaluation.warn()) MP.printMessage(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_IDENTIFIER_MISMATCH,
+										evaluation.module() + "!" + evaluation.definition(),
+										c.getResource(c.getSimpleName() + ".class").toExternalForm(), val.toString());
+								continue LOOP;
+							}
+							
+							opDef.getBody().setToolObject(toolId, val);
+		                    this.defns.put(evaluation.definition(), val);
+		                    
+							// Print success of loading the module override.
+							MP.printMessage(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_LOADED,
+									evaluation.module() + "!" + evaluation.definition(),
+									c.getResource(c.getSimpleName() + ".class").toExternalForm(), val.toString());
+		                    
+		                    // continue with next method (don't try to also load Execution annotation below).
+		                    continue LOOP;
+						}
+						
+						final TLAPlusOperator opOverrideCandidate = m.getAnnotation(TLAPlusOperator.class);
+						if (opOverrideCandidate != null) {
+							final ModuleNode moduleNode = modSet.get(opOverrideCandidate.module());
+							if (moduleNode == null) {
+								if (opOverrideCandidate.warn()) MP.printWarning(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_MODULE_MISMATCH,
+										opOverrideCandidate.identifier(), opOverrideCandidate.module(), m.toString());
+								continue LOOP;
+							}
+							final OpDefNode opDef = moduleNode.getOpDef(opOverrideCandidate.identifier());
+							if (opDef == null) {
+								if (opOverrideCandidate.warn()) MP.printWarning(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_IDENTIFIER_MISMATCH,
+										opOverrideCandidate.identifier(), opOverrideCandidate.module(), m.toString());
+								continue LOOP;
+							}
+
+							final Value val = MethodValue.get(m, opOverrideCandidate.minLevel());
+							if (opDef.getArity() != m.getParameterCount()) {
+								if (opOverrideCandidate.warn()) MP.printWarning(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_MISMATCH,
+										opDef.getName().toString(), c.getName(), val.toString());
+								continue LOOP;
+							} else {
+								if (opOverrideCandidate.warn()) MP.printMessage(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_LOADED,
+										opDef.getName().toString(), c.getName(),
+										val instanceof MethodValue ? val.toString() : val.getClass().getName()); // toString of non-MethodValue instances can be expensive.
+							}
+
+							opDef.getBody().setToolObject(toolId, val);
+							this.defns.put(opOverrideCandidate.identifier(), val);
+						}
+					}
+				}
+			} catch (InstantiationException | IllegalAccessException e) {
+				// TODO Specific error code.
+				Assert.fail(EC.GENERAL);
+				return;
+			}
+        }
+        
 
         Set<String> overriden = new HashSet<String>();
         // Apply config file overrides to constants:
@@ -908,7 +1016,7 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
             if (args.length == 0)
             {
                 SymbolNode opNode = pred1.getOperator();
-                Object val = spec.lookup(opNode, c, false);
+                Object val = symbolNodeValueLookupProvider.lookup(opNode, c, false, toolId);
                 if (val instanceof OpDefNode)
                 {
                     if (((OpDefNode) val).getArity() != 0)
@@ -916,7 +1024,7 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
                         Assert.fail(EC.TLC_CONFIG_OP_NO_ARGS, new String[] { opNode.getName().toString() });
                     }
                     ExprNode body = ((OpDefNode) val).getBody();
-                    if (spec.getLevelBound(body, c) == 1)
+                    if (symbolNodeValueLookupProvider.getLevelBound(body, c, toolId) == 1)
                     {
                         this.initPredVec.addElement(new Action(Specs.addSubsts(body, subs), c, ((OpDefNode) val)));
                     } else
@@ -942,6 +1050,10 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
             }
 
             int opcode = BuiltInOPs.getOpCode(pred1.getOperator().getName());
+            if ((opcode == OPCODE_te) || (opcode == OPCODE_tf))
+            {
+            	Assert.fail(EC.TLC_SPECIFICATION_FEATURES_TEMPORAL_QUANTIFIER);
+            }
             if (opcode == OPCODE_cl || opcode == OPCODE_land)
             {
                 for (int i = 0; i < args.length; i++)
@@ -985,7 +1097,7 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
                             void enter(ExprNode subscript, Context c)
                             {
                                 // if it's a variable, add it to the vector and return
-                                SymbolNode var = spec.getVar(subscript, c, false);
+                                SymbolNode var = symbolNodeValueLookupProvider.getVar(subscript, c, false, toolId);
                                 if (var != null)
                                 {
                                     components.addElement(var);
@@ -1013,11 +1125,11 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
                                         return;
                                     }
                                     // user-defined operator: look up its definition
-                                    Object opDef = spec.lookup(opNode, c, false);
+                                    Object opDef = symbolNodeValueLookupProvider.lookup(opNode, c, false, toolId);
                                     if (opDef instanceof OpDefNode)
                                     {
                                         OpDefNode opDef1 = (OpDefNode) opDef;
-                                        this.enter(opDef1.getBody(), spec.getOpContext(opDef1, args, c, false));
+                                        this.enter(opDef1.getBody(), symbolNodeValueLookupProvider.getOpContext(opDef1, args, c, false, toolId));
                                         return;
                                     }
                                     if (opDef instanceof LazyValue)
@@ -1035,7 +1147,7 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
                                     Context c1 = c;
                                     for (int i = 0; i < subs.length; i++)
                                     {
-                                        c1 = c1.cons(subs[i].getOp(), spec.getVal(subs[i].getExpr(), c, false));
+                                        c1 = c1.cons(subs[i].getOp(), symbolNodeValueLookupProvider.getVal(subs[i].getExpr(), c, false, toolId));
                                     }
                                     this.enter(subscript1.getBody(), c1);
                                     return;
@@ -1080,7 +1192,7 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
                             Subst[] snsubs = sn.getSubsts();
                             for (int i = 0; i < snsubs.length; i++)
                             {
-                                c1 = c1.cons(snsubs[i].getOp(), spec.getVal(snsubs[i].getExpr(), c, false));
+                                c1 = c1.cons(snsubs[i].getOp(), symbolNodeValueLookupProvider.getVal(snsubs[i].getExpr(), c, false, toolId));
                             }
                             subs1 = subs1.cdr();
                         }
@@ -1129,7 +1241,7 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
            }
         }
 
-        int level = spec.getLevelBound(pred, c);
+        int level = symbolNodeValueLookupProvider.getLevelBound(pred, c, toolId);
         if (level <= 1)
         {
             this.initPredVec.addElement(new Action(Specs.addSubsts(pred, subs), c));
@@ -1159,7 +1271,7 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
             if (args.length == 0)
             {
                 SymbolNode opNode = pred1.getOperator();
-                Object val = spec.lookup(opNode, c, false);
+                Object val = symbolNodeValueLookupProvider.lookup(opNode, c, false, toolId);
                 if (val instanceof OpDefNode)
                 {
                     if (((OpDefNode) val).getArity() != 0)
@@ -1207,7 +1319,7 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
                     }
                     this.impliedActNameVec.addElement(name);
                     this.impliedActionVec.addElement(new Action(Specs.addSubsts(boxArg, subs), c));
-                } else if (spec.getLevelBound(boxArg, c) < 2)
+                } else if (symbolNodeValueLookupProvider.getLevelBound(boxArg, c, toolId) < 2)
                 {
                     this.invVec.addElement(new Action(Specs.addSubsts(boxArg, subs), c));
                     if ((boxArg instanceof OpApplNode) && (((OpApplNode) boxArg).getArgs().length == 0))
@@ -1229,7 +1341,7 @@ public class SpecProcessor implements ValueConstants, ToolGlobals {
                return;
            }
         }
-        int level = spec.getLevelBound(pred, c);
+        int level = symbolNodeValueLookupProvider.getLevelBound(pred, c, toolId);
         if (level <= 1)
         {
             this.impliedInitVec.addElement(new Action(Specs.addSubsts(pred, subs), c));
diff --git a/tlatools/src/tlc2/tool/impl/SymbolNodeValueLookupProvider.java b/tlatools/src/tlc2/tool/impl/SymbolNodeValueLookupProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..361ba9c32712a4a76c195faea0e5e489399b3015
--- /dev/null
+++ b/tlatools/src/tlc2/tool/impl/SymbolNodeValueLookupProvider.java
@@ -0,0 +1,244 @@
+package tlc2.tool.impl;
+
+import tla2sany.semantic.APSubstInNode;
+import tla2sany.semantic.ASTConstants;
+import tla2sany.semantic.ExprNode;
+import tla2sany.semantic.ExprOrOpArgNode;
+import tla2sany.semantic.FormalParamNode;
+import tla2sany.semantic.LabelNode;
+import tla2sany.semantic.LetInNode;
+import tla2sany.semantic.OpApplNode;
+import tla2sany.semantic.OpArgNode;
+import tla2sany.semantic.OpDefNode;
+import tla2sany.semantic.SemanticNode;
+import tla2sany.semantic.Subst;
+import tla2sany.semantic.SubstInNode;
+import tla2sany.semantic.SymbolNode;
+import tlc2.tool.BuiltInOPs;
+import tlc2.tool.ToolGlobals;
+import tlc2.tool.coverage.CostModel;
+import tlc2.util.Context;
+import tlc2.value.impl.EvaluatingValue;
+import tlc2.value.impl.IntValue;
+import tlc2.value.impl.LazyValue;
+import tlc2.value.impl.MethodValue;
+import util.UniqueString;
+
+public interface SymbolNodeValueLookupProvider {
+    /* Return the variable if expr is a state variable. Otherwise, null. */
+	default SymbolNode getVar(final SemanticNode expr, final Context c, final boolean cutoff, final int forToolId) {
+		if (expr instanceof OpApplNode) {
+			SymbolNode opNode = ((OpApplNode) expr).getOperator();
+
+			if (opNode.getArity() == 0) {
+				boolean isVarDecl = (opNode.getKind() == ASTConstants.VariableDeclKind);
+				Object val = lookup(opNode, c, cutoff && isVarDecl, forToolId);
+
+				if (val instanceof LazyValue) {
+					LazyValue lval = (LazyValue) val;
+					return getVar(lval.expr, lval.con, cutoff, forToolId);
+				}
+				if (val instanceof OpDefNode) {
+					return getVar(((OpDefNode) val).getBody(), c, cutoff, forToolId);
+				}
+				if (isVarDecl) {
+					return opNode;
+				}
+			}
+		}
+		return null;
+	}
+
+	default Object lookup(final SymbolNode opNode, final Context c, final boolean cutoff, final int forToolId) {
+		final boolean isVarDecl = (opNode.getKind() == ASTConstants.VariableDeclKind);
+		Object result = c.lookup(opNode, cutoff && isVarDecl);
+		if (result != null) {
+			return result;
+		}
+
+		result = opNode.getToolObject(forToolId);
+		if (result != null) {
+			return WorkerValue.mux(result);
+		}
+
+		if (opNode.getKind() == ASTConstants.UserDefinedOpKind) {
+			// Changed by LL on 10 Apr 2011 from
+			//
+			// result = ((OpDefNode) opNode).getBody().getToolObject(toolId);
+			//
+			// to the following
+			ExprNode body = ((OpDefNode) opNode).getBody();
+			result = body.getToolObject(forToolId);
+			while ((result == null) && (body.getKind() == ASTConstants.SubstInKind)) {
+				body = ((SubstInNode) body).getBody();
+				result = body.getToolObject(forToolId);
+			}
+			// end change
+
+			if (result != null) {
+				return result;
+			}
+		}
+		return opNode;
+	}
+
+	default Object getVal(final ExprOrOpArgNode expr, final Context c, final boolean cachable, final int forToolId) {
+		return getVal(expr, c, cachable, CostModel.DO_NOT_RECORD, forToolId);
+	}
+
+	default Object getVal(final ExprOrOpArgNode expr, final Context c, final boolean cachable, final CostModel cm, final int forToolId) {
+		if (expr instanceof ExprNode) {
+			return new LazyValue(expr, c, cachable, cm);
+		}
+		final SymbolNode opNode = ((OpArgNode) expr).getOp();
+		return lookup(opNode, c, false, forToolId);
+	}
+
+	default Context getOpContext(final OpDefNode opDef, final ExprOrOpArgNode[] args, final Context c, final boolean cachable, final int forToolId) {
+		return getOpContext(opDef, args, c, cachable, CostModel.DO_NOT_RECORD, forToolId);
+	}
+
+	default Context getOpContext(final OpDefNode opDef, final ExprOrOpArgNode[] args, final Context c,
+			final boolean cachable, final CostModel cm, int forToolId) {
+		final FormalParamNode[] formals = opDef.getParams();
+		final int alen = args.length;
+		Context c1 = c;
+		for (int i = 0; i < alen; i++) {
+			Object aval = getVal(args[i], c, cachable, cm, forToolId);
+			c1 = c1.cons(formals[i], aval);
+		}
+		return c1;
+	}
+
+    /**
+     * This method only returns an approximation of the level of the
+     * expression.  The "real" level is at most the return value. Adding
+     * <name, ValOne> to the context means that there is no need to
+     * compute level for name.
+     *
+     * Note that this method does not work if called on a part of an
+     * EXCEPT expression.
+     */
+	default int getLevelBound(final SemanticNode expr, final Context c, final int forToolId) {
+		switch (expr.getKind()) {
+			case ASTConstants.OpApplKind: {
+				final OpApplNode expr1 = (OpApplNode) expr;
+				return getLevelBoundAppl(expr1, c, forToolId);
+			}
+			case ASTConstants.LetInKind: {
+				final LetInNode expr1 = (LetInNode) expr;
+				final OpDefNode[] letDefs = expr1.getLets();
+				final int letLen = letDefs.length;
+				Context c1 = c;
+				int level = 0;
+				for (int i = 0; i < letLen; i++) {
+					OpDefNode opDef = letDefs[i];
+					level = Math.max(level, getLevelBound(opDef.getBody(), c1, forToolId));
+					c1 = c1.cons(opDef, IntValue.ValOne);
+				}
+				return Math.max(level, getLevelBound(expr1.getBody(), c1, forToolId));
+			}
+			case ASTConstants.SubstInKind: {
+				final SubstInNode expr1 = (SubstInNode) expr;
+				final Subst[] subs = expr1.getSubsts();
+				final int slen = subs.length;
+				Context c1 = c;
+				for (int i = 0; i < slen; i++) {
+					final Subst sub = subs[i];
+					c1 = c1.cons(sub.getOp(), getVal(sub.getExpr(), c, true, forToolId));
+				}
+				return getLevelBound(expr1.getBody(), c1, forToolId);
+			}
+
+			// Added by LL on 13 Nov 2009 to handle theorem and assumption names.
+			case ASTConstants.APSubstInKind: {
+				final APSubstInNode expr1 = (APSubstInNode) expr;
+				final Subst[] subs = expr1.getSubsts();
+				final int slen = subs.length;
+				Context c1 = c;
+				for (int i = 0; i < slen; i++) {
+					final Subst sub = subs[i];
+					c1 = c1.cons(sub.getOp(), getVal(sub.getExpr(), c, true, forToolId));
+				}
+				return getLevelBound(expr1.getBody(), c1, forToolId);
+			}
+
+			/***********************************************************************
+			 * LabelKind case added by LL on 13 Jun 2007. *
+			 ***********************************************************************/
+			case ASTConstants.LabelKind: {
+				final LabelNode expr1 = (LabelNode) expr;
+				return getLevelBound(expr1.getBody(), c, forToolId);
+			}
+			default: {
+				return 0;
+			}
+		}
+	}
+
+	/**
+	 * Users will likely want to call only {@link #getLevelBound(SemanticNode, Context, int)} - this
+	 * 	method is called from that method in certain cases.
+	 */
+	default int getLevelBoundAppl(final OpApplNode expr, Context c, final int forToolId) {
+		final SymbolNode opNode = expr.getOperator();
+		final UniqueString opName = opNode.getName();
+		final int opcode = BuiltInOPs.getOpCode(opName);
+
+		if (BuiltInOPs.isTemporal(opcode)) {
+			return 3; // Conservative estimate
+		}
+
+		if (BuiltInOPs.isAction(opcode)) {
+			return 2; // Conservative estimate
+		}
+
+		if (opcode == ToolGlobals.OPCODE_enabled) {
+			return 1; // Conservative estimate
+		}
+
+		int level = 0;
+		final ExprNode[] bnds = expr.getBdedQuantBounds();
+		for (int i = 0; i < bnds.length; i++) {
+			level = Math.max(level, getLevelBound(bnds[i], c, forToolId));
+		}
+
+		if (opcode == ToolGlobals.OPCODE_rfs) {
+			// For recursive function, don't compute level of the function body
+			// again in the recursive call.
+			SymbolNode fname = expr.getUnbdedQuantSymbols()[0];
+			c = c.cons(fname, IntValue.ValOne);
+		}
+
+		final ExprOrOpArgNode[] args = expr.getArgs();
+		final int alen = args.length;
+		for (int i = 0; i < alen; i++) {
+			if (args[i] != null) {
+				level = Math.max(level, getLevelBound(args[i], c, forToolId));
+			}
+		}
+
+		if (opcode == 0) {
+			// This operator is a user-defined operator.
+			if (opName.getVarLoc() >= 0)
+				return 1;
+
+			final Object val = lookup(opNode, c, false, forToolId);
+			if (val instanceof OpDefNode) {
+				final OpDefNode opDef = (OpDefNode) val;
+				c = c.cons(opNode, IntValue.ValOne);
+				level = Math.max(level, getLevelBound(opDef.getBody(), c, forToolId));
+			} else if (val instanceof LazyValue) {
+				final LazyValue lv = (LazyValue) val;
+				level = Math.max(level, getLevelBound(lv.expr, lv.con, forToolId));
+            } else if (val instanceof EvaluatingValue) {
+            	final EvaluatingValue ev = (EvaluatingValue) val;
+            	level = Math.max(level, ev.getMinLevel());
+            } else if (val instanceof MethodValue) {
+            	final MethodValue mv = (MethodValue) val;
+            	level = Math.max(level, mv.getMinLevel());
+			}
+		}
+		return level;
+	}
+}
diff --git a/tlatools/src/tlc2/tool/impl/Tool.java b/tlatools/src/tlc2/tool/impl/Tool.java
index bb0f30e7af9f073520c5d46b072a3eaff4274acf..c211acca5ef85bdb3134968042c9695830be6d9e 100644
--- a/tlatools/src/tlc2/tool/impl/Tool.java
+++ b/tlatools/src/tlc2/tool/impl/Tool.java
@@ -7,7 +7,10 @@
 package tlc2.tool.impl;
 
 import java.io.File;
+import java.util.HashSet;
+import java.util.List;
 
+import tla2sany.parser.SyntaxTreeNode;
 import tla2sany.semantic.APSubstInNode;
 import tla2sany.semantic.ExprNode;
 import tla2sany.semantic.ExprOrOpArgNode;
@@ -19,6 +22,7 @@ import tla2sany.semantic.LevelNode;
 import tla2sany.semantic.OpApplNode;
 import tla2sany.semantic.OpArgNode;
 import tla2sany.semantic.OpDefNode;
+import tla2sany.semantic.OpDefOrDeclNode;
 import tla2sany.semantic.SemanticNode;
 import tla2sany.semantic.Subst;
 import tla2sany.semantic.SubstInNode;
@@ -28,11 +32,11 @@ import tlc2.output.EC;
 import tlc2.output.MP;
 import tlc2.tool.Action;
 import tlc2.tool.BuiltInOPs;
-import tlc2.tool.CallStack;
 import tlc2.tool.EvalControl;
 import tlc2.tool.EvalException;
 import tlc2.tool.IActionItemList;
 import tlc2.tool.IContextEnumerator;
+import tlc2.tool.INextStateFunctor;
 import tlc2.tool.IStateFunctor;
 import tlc2.tool.ITool;
 import tlc2.tool.StateVec;
@@ -43,6 +47,7 @@ import tlc2.tool.TLCStateMut;
 import tlc2.tool.ToolGlobals;
 import tlc2.tool.coverage.CostModel;
 import tlc2.util.Context;
+import tlc2.util.ExpectInlined;
 import tlc2.util.IdThread;
 import tlc2.util.Vect;
 import tlc2.value.IFcnLambdaValue;
@@ -53,12 +58,15 @@ import tlc2.value.Values;
 import tlc2.value.impl.Applicable;
 import tlc2.value.impl.BoolValue;
 import tlc2.value.impl.Enumerable;
+import tlc2.value.impl.EvaluatingValue;
 import tlc2.value.impl.FcnLambdaValue;
 import tlc2.value.impl.FcnParams;
 import tlc2.value.impl.FcnRcdValue;
 import tlc2.value.impl.LazyValue;
+import tlc2.value.impl.MVPerm;
 import tlc2.value.impl.MVPerms;
 import tlc2.value.impl.MethodValue;
+import tlc2.value.impl.ModelValue;
 import tlc2.value.impl.OpLambdaValue;
 import tlc2.value.impl.OpValue;
 import tlc2.value.impl.RecordValue;
@@ -80,8 +88,8 @@ import tlc2.value.impl.ValueEnumeration;
 import tlc2.value.impl.ValueExcept;
 import tlc2.value.impl.ValueVec;
 import util.Assert;
-import util.Assert.TLCRuntimeException;
 import util.FilenameToStream;
+import util.TLAConstants;
 import util.UniqueString;
 
 /**
@@ -92,17 +100,14 @@ import util.UniqueString;
  * This is one of two places in TLC, where not all messages are retrieved from the message printer,
  * but constructed just here in the code.
  */
-public class Tool
+public abstract class Tool
     extends Spec
     implements ValueConstants, ToolGlobals, ITool
 {
 	
   public static final Value[] EmptyArgs = new Value[0];
 
-	
   protected final Action[] actions;     // the list of TLA actions.
-  private CallStack callStack;    // the call stack.
-
   private Vect<Action> actionVec = new Vect<>(10);
 
   /**
@@ -124,7 +129,6 @@ public class Tool
   public Tool(String specDir, String specFile, String configFile, FilenameToStream resolver)
   {
       super(specDir, specFile, configFile, resolver);
-      this.callStack = null;
 
       // Initialize state.
       TLCStateMut.setTool(this);
@@ -145,23 +149,10 @@ public class Tool
   Tool(Tool other) {
 	  super(other);
 	  this.actions = other.actions;
-	  this.callStack = other.callStack;
 	  this.actionVec = other.actionVec;
   }
 
-	@Override
-  public final void setCallStack()
-  {
-      this.callStack = new CallStack();
-  }
-
-  @Override
-  public final CallStack getCallStack()
-  {
-      return this.callStack;
-  }
-
-  /**
+	/**
    * This method returns the set of all possible actions of the
    * spec, and sets the actions field of this object. In fact, we
    * could simply treat the next predicate as one "giant" action.
@@ -337,7 +328,7 @@ public class Tool
       // doesn't get added to acts at all).
 	  for (int i = (init.size() - 1); i > 0; i--) {
 		  Action elem = (Action)init.elementAt(i);
-		  acts = (ActionItemList) acts.cons(elem.pred, elem.con, elem.cm, IActionItemList.PRED);
+		  acts = (ActionItemList) acts.cons(elem, IActionItemList.PRED);
 	  }
 	  if (init.size() != 0) {
 		  Action elem = (Action)init.elementAt(0);
@@ -363,10 +354,8 @@ public class Tool
     return state;
   }
 
-  private final void getInitStates(SemanticNode init, ActionItemList acts,
+  protected void getInitStates(SemanticNode init, ActionItemList acts,
                                    Context c, TLCState ps, IStateFunctor states, CostModel cm) {
-    if (this.callStack != null) this.callStack.push(init);
-    try {
         switch (init.getKind()) {
         case OpApplKind:
           {
@@ -387,7 +376,7 @@ public class Tool
             Context c1 = c;
             for (int i = 0; i < subs.length; i++) {
               Subst sub = subs[i];
-              c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, coverage ? sub.getCM() : cm));
+              c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, coverage ? sub.getCM() : cm, toolId));
             }
             this.getInitStates(init1.getBody(), acts, c1, ps, states, cm);
             return;
@@ -400,7 +389,7 @@ public class Tool
             Context c1 = c;
             for (int i = 0; i < subs.length; i++) {
               Subst sub = subs[i];
-              c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, cm));
+              c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, cm, toolId));
             }
             this.getInitStates(init1.getBody(), acts, c1, ps, states, cm);
             return;
@@ -417,17 +406,6 @@ public class Tool
             Assert.fail("The init state relation is not a boolean expression.\n" + init);
           }
         }
-    } catch (TLCRuntimeException | EvalException e) {
-	    if (this.callStack != null) {
-			// Freeze the callStack to ignore subsequent pop operations. This is
-			// necessary to ignore the callStack#pop calls in the finally blocks when the
-			// Java call stack gets unwounded.
-			this.callStack.freeze();
-	    }
-	    throw e;
-    } finally {
-    	if (this.callStack != null) { this.callStack.pop(); }
-    }
   }
 
   private final void getInitStates(ActionItemList acts, TLCState ps, IStateFunctor states, CostModel cm) {
@@ -474,11 +452,9 @@ public class Tool
 		this.getInitStates(acts.carPred(), acts1, acts.carContext(), ps, states, acts.cm);
 	  }
 
-  private final void getInitStatesAppl(OpApplNode init, ActionItemList acts,
+  protected void getInitStatesAppl(OpApplNode init, ActionItemList acts,
                                        Context c, TLCState ps, IStateFunctor states, CostModel cm) {
-    if (this.callStack != null) this.callStack.push(init);
     if (coverage) {cm = cm.get(init);}
-    try {
         ExprOrOpArgNode[] args = init.getArgs();
         int alen = args.length;
         SymbolNode opNode = init.getOperator();
@@ -495,7 +471,7 @@ public class Tool
             opcode = BuiltInOPs.getOpCode(opDef.getName());
             if (opcode == 0) {
               // Context c1 = this.getOpContext(opDef, args, c, false);
-              Context c1 = this.getOpContext(opDef, args, c, true, cm);
+              Context c1 = this.getOpContext(opDef, args, c, true, cm, toolId);
               this.getInitStates(opDef.getBody(), acts, c1, ps, states, cm);
               return;
             }
@@ -667,7 +643,7 @@ public class Tool
           }
         case OPCODE_eq:
           {
-            SymbolNode var = this.getVar(args[0], c, false);
+            SymbolNode var = this.getVar(args[0], c, false, toolId);
             if (var == null || var.getName().getVarLoc() < 0) {
               Value bval = this.eval(init, c, ps, TLCState.Empty, EvalControl.Init, cm);
               if (!((BoolValue)bval).val) {
@@ -695,7 +671,7 @@ public class Tool
           }
         case OPCODE_in:
           {
-            SymbolNode var = this.getVar(args[0], c, false);
+            SymbolNode var = this.getVar(args[0], c, false, toolId);
             if (var == null || var.getName().getVarLoc() < 0) {
               Value bval = this.eval(init, c, ps, TLCState.Empty, EvalControl.Init, cm);
               if (!((BoolValue)bval).val) {
@@ -765,80 +741,63 @@ public class Tool
             return;
           }
         }
-    } catch (TLCRuntimeException | EvalException e) {
-    	// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor)
-    	if (this.callStack != null) { this.callStack.freeze(); }
-	    throw e;
-    } finally {
-    	if (this.callStack != null) { this.callStack.pop(); }
-    }
   }
-
+  
   /**
    * This method returns the set of next states when taking the action
    * in the given state.
    */
   @Override
-public final StateVec getNextStates(Action action, TLCState state) {
+  public final StateVec getNextStates(Action action, TLCState state) {
     ActionItemList acts = ActionItemList.Empty;
     TLCState s1 = TLCState.Empty.createEmpty();
     StateVec nss = new StateVec(0);
-    this.getNextStates(action.pred, acts, action.con, state, s1, nss, action.cm);
+    this.getNextStates(action, action.pred, acts, action.con, state, s1, nss, action.cm);
     if (coverage) { action.cm.incInvocations(nss.size()); }
     return nss;
   }
-
-  private final TLCState getNextStates(SemanticNode pred, ActionItemList acts, Context c,
-                                       TLCState s0, TLCState s1, StateVec nss, CostModel cm) {
-	    if (this.callStack != null) {
-	    	return getNextStatesWithCallStack(pred, acts, c, s0, s1, nss, cm);
-	    } else {
-	    	return getNextStatesImpl(pred, acts, c, s0, s1, nss, cm);
-	    }
-  }
   
-  private final TLCState getNextStatesWithCallStack(SemanticNode pred, ActionItemList acts, Context c,
-              TLCState s0, TLCState s1, StateVec nss, final CostModel cm) {
-	    this.callStack.push(pred);
-	    try {
-	    	return getNextStatesImpl(pred, acts, c, s0, s1, nss, cm);
-	    } catch (TLCRuntimeException | EvalException e) {
-	    	// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor)
-	    	this.callStack.freeze();
-		    throw e;
-	    } finally {
-	    	this.callStack.pop();
-	    }
+  @Override
+  public final boolean getNextStates(final INextStateFunctor functor, final TLCState state) {
+	  for (int i = 0; i < actions.length; i++) {
+			final Action action = actions[i];
+			this.getNextStates(action, action.pred, ActionItemList.Empty, action.con, state, TLCState.Empty.createEmpty(),
+					functor, action.cm);
+		}
+		return false;
   }
+
+  protected abstract TLCState getNextStates(final Action action, SemanticNode pred, ActionItemList acts, Context c,
+                                       TLCState s0, TLCState s1, INextStateFunctor nss, CostModel cm);
   
-  private final TLCState getNextStatesImpl(SemanticNode pred, ActionItemList acts, Context c,
-              TLCState s0, TLCState s1, StateVec nss, CostModel cm) {
+  protected final TLCState getNextStatesImpl(final Action action, SemanticNode pred, ActionItemList acts, Context c,
+              TLCState s0, TLCState s1, INextStateFunctor nss, CostModel cm) {
         switch (pred.getKind()) {
         case OpApplKind:
           {
             OpApplNode pred1 = (OpApplNode)pred;
             if (coverage) {cm = cm.get(pred);}
-            return this.getNextStatesAppl(pred1, acts, c, s0, s1, nss, cm);
+            return this.getNextStatesAppl(action, pred1, acts, c, s0, s1, nss, cm);
           }
         case LetInKind:
           {
             LetInNode pred1 = (LetInNode)pred;
-            return this.getNextStates(pred1.getBody(), acts, c, s0, s1, nss, cm);
+            return this.getNextStates(action, pred1.getBody(), acts, c, s0, s1, nss, cm);
           }
         case SubstInKind:
           {
-            return getNextStatesImplSubstInKind((SubstInNode) pred, acts, c, s0, s1, nss, cm);
+            return getNextStatesImplSubstInKind(action, (SubstInNode) pred, acts, c, s0, s1, nss, cm);
           }
         // Added by LL on 13 Nov 2009 to handle theorem and assumption names.
         case APSubstInKind:
           {
-            return getNextStatesImplApSubstInKind((APSubstInNode) pred, acts, c, s0, s1, nss, cm);
+            return getNextStatesImplApSubstInKind(action, (APSubstInNode) pred, acts, c, s0, s1, nss, cm);
           }
         // LabelKind class added by LL on 13 Jun 2007
         case LabelKind:
           {
             LabelNode pred1 = (LabelNode)pred;
-            return this.getNextStates(pred1.getBody(), acts, c, s0, s1, nss, cm);
+            return this.getNextStates(action, pred1.getBody(), acts, c, s0, s1, nss, cm);
           }
         default:
           {
@@ -848,44 +807,48 @@ public final StateVec getNextStates(Action action, TLCState state) {
     	return s1;
   }
 
-  private final TLCState getNextStatesImplSubstInKind(SubstInNode pred1, ActionItemList acts, Context c, TLCState s0, TLCState s1, StateVec nss, final CostModel cm) {
+  @ExpectInlined
+  private final TLCState getNextStatesImplSubstInKind(final Action action, SubstInNode pred1, ActionItemList acts, Context c, TLCState s0, TLCState s1, INextStateFunctor nss, final CostModel cm) {
   	Subst[] subs = pred1.getSubsts();
   	int slen = subs.length;
   	Context c1 = c;
   	for (int i = 0; i < slen; i++) {
   	  Subst sub = subs[i];
-  	  c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, coverage ? sub.getCM() : cm));
+  	  c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, coverage ? sub.getCM() : cm, toolId));
   	}
-  	return this.getNextStates(pred1.getBody(), acts, c1, s0, s1, nss, cm);
+  	return this.getNextStates(action, pred1.getBody(), acts, c1, s0, s1, nss, cm);
   }
   
-  private final TLCState getNextStatesImplApSubstInKind(APSubstInNode pred1, ActionItemList acts, Context c, TLCState s0, TLCState s1, StateVec nss, final CostModel cm) {
+  @ExpectInlined
+  private final TLCState getNextStatesImplApSubstInKind(final Action action, APSubstInNode pred1, ActionItemList acts, Context c, TLCState s0, TLCState s1, INextStateFunctor nss, final CostModel cm) {
   	Subst[] subs = pred1.getSubsts();
   	int slen = subs.length;
   	Context c1 = c;
   	for (int i = 0; i < slen; i++) {
   	  Subst sub = subs[i];
-  	  c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, cm));
+  	  c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, cm, toolId));
   	}
-  	return this.getNextStates(pred1.getBody(), acts, c1, s0, s1, nss, cm);
+  	return this.getNextStates(action, pred1.getBody(), acts, c1, s0, s1, nss, cm);
   }
   
-  private final TLCState getNextStates(ActionItemList acts, final TLCState s0, final TLCState s1,
-          final StateVec nss, CostModel cm) {
-	  final TLCState copy = getNextStates0(acts, s0, s1, nss, cm);
+  @ExpectInlined
+  private final TLCState getNextStates(final Action action, ActionItemList acts, final TLCState s0, final TLCState s1,
+          final INextStateFunctor nss, CostModel cm) {
+	  final TLCState copy = getNextStates0(action, acts, s0, s1, nss, cm);
 	  if (coverage && copy != s1) {
 		  cm.incInvocations();
 	  }
 	  return copy;
   }
 
-  private final TLCState getNextStates0(ActionItemList acts, final TLCState s0, final TLCState s1,
-                                       final StateVec nss, CostModel cm) {
+  @ExpectInlined
+  private final TLCState getNextStates0(final Action action, ActionItemList acts, final TLCState s0, final TLCState s1,
+                                       final INextStateFunctor nss, CostModel cm) {
     if (acts.isEmpty()) {
-      nss.addElement(s1);
+      nss.addElement(s0, action, s1);
       return s1.copy();
     } else if (s1.allAssigned()) {
-    	return getNextStatesAllAssigned(acts, s0, s1, nss, cm);
+    	return getNextStatesAllAssigned(action, acts, s0, s1, nss, cm);
     }
 
     final int kind = acts.carKind();
@@ -894,30 +857,30 @@ public final StateVec getNextStates(Action action, TLCState state) {
     ActionItemList acts1 = acts.cdr();
     cm = acts.cm;
     if (kind > 0) {
-      return this.getNextStates(pred, acts1, c, s0, s1, nss, cm);
+      return this.getNextStates(action, pred, acts1, c, s0, s1, nss, cm);
     }
     else if (kind == -1) {
-      return this.getNextStates(pred, acts1, c, s0, s1, nss, cm);
+      return this.getNextStates(action, pred, acts1, c, s0, s1, nss, cm);
     }
     else if (kind == -2) {
-      return this.processUnchanged(pred, acts1, c, s0, s1, nss, cm);
+      return this.processUnchanged(action, pred, acts1, c, s0, s1, nss, cm);
     }
     else {
       IValue v1 = this.eval(pred, c, s0, cm);
       IValue v2 = this.eval(pred, c, s1, cm);
       if (!v1.equals(v2)) {
     	  if (coverage) {
-    		  return this.getNextStates(acts1, s0, s1, nss, cm);
+    		  return this.getNextStates(action, acts1, s0, s1, nss, cm);
     	  } else {
-    		  return this.getNextStates0(acts1, s0, s1, nss, cm);
+    		  return this.getNextStates0(action, acts1, s0, s1, nss, cm);
     	  }
       }
     }
     return s1;
   }
   
-  private final TLCState getNextStatesAllAssigned(ActionItemList acts, final TLCState s0, final TLCState s1,
-		  								final StateVec nss, final CostModel cm) {
+  private final TLCState getNextStatesAllAssigned(final Action action, ActionItemList acts, final TLCState s0, final TLCState s1,
+		  								final INextStateFunctor nss, final CostModel cm) {
 	  int kind = acts.carKind();
 	  SemanticNode pred = acts.carPred();
 	  Context c = acts.carContext();
@@ -935,7 +898,7 @@ public final StateVec getNextStates(Action action, TLCState state) {
 			  }
 		  } else if (kind == -2) {
 			  // Identical to default handling below (line 876). Ignored during this optimization.
-			  return this.processUnchanged(pred, acts.cdr(), c, s0, s1, nss, cm2);
+			  return this.processUnchanged(action, pred, acts.cdr(), c, s0, s1, nss, cm2);
 		  } else {
 			  final IValue v1 = this.eval(pred, c, s0, cm2);
 			  final IValue v2 = this.eval(pred, c, s1, cm2);
@@ -950,40 +913,22 @@ public final StateVec getNextStates(Action action, TLCState state) {
 		  kind = acts.carKind();
           cm2 = acts.cm;
 	  }
-	  nss.addElement(s1);
+	  nss.addElement(s0, action, s1);
 	  return s1.copy();
   }
 
   /* getNextStatesAppl */
 
-  private final TLCState getNextStatesAppl(OpApplNode pred, ActionItemList acts, Context c,
-          TLCState s0, TLCState s1, StateVec nss, final CostModel cm) {
-	  if (this.callStack != null) {
-		  return getNextStatesApplWithCallStack(pred, acts, c, s0, s1, nss, cm);
-	  } else {
-	      return getNextStatesApplImpl(pred, acts, c, s0, s1, nss, cm);
-	  }
-  }
+  @ExpectInlined
+  protected abstract TLCState getNextStatesAppl(final Action action, OpApplNode pred, ActionItemList acts, Context c,
+          TLCState s0, TLCState s1, INextStateFunctor nss, final CostModel cm);
   
-  private final TLCState getNextStatesApplWithCallStack(OpApplNode pred, ActionItemList acts, Context c,
-          TLCState s0, TLCState s1, StateVec nss, final CostModel cm) {
-	    this.callStack.push(pred);
-	    try {
-	    	return getNextStatesApplImpl(pred, acts, c, s0, s1, nss, cm);
-	    } catch (TLCRuntimeException | EvalException e) {
-	    	// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor)
-	    	this.callStack.freeze();
-	    	throw e;
-	    } finally {
-	    	this.callStack.pop();
-	    }
-  }
+  protected final TLCState getNextStatesApplImpl(final Action action, final OpApplNode pred, final ActionItemList acts, final Context c,
+                                           final TLCState s0, final TLCState s1, final INextStateFunctor nss, final CostModel cm) {
+        final ExprOrOpArgNode[] args = pred.getArgs();
+        final int alen = args.length;
+        final SymbolNode opNode = pred.getOperator();
 
-  private final TLCState getNextStatesApplImpl(OpApplNode pred, ActionItemList acts, Context c,
-                                           TLCState s0, TLCState s1, StateVec nss, CostModel cm) {
-        ExprOrOpArgNode[] args = pred.getArgs();
-        int alen = args.length;
-        SymbolNode opNode = pred.getOperator();
         int opcode = BuiltInOPs.getOpCode(opNode.getName());
 
         if (opcode == 0) {
@@ -993,13 +938,11 @@ public final StateVec getNextStates(Action action, TLCState state) {
           Object val = this.lookup(opNode, c, s0, false);
 
           if (val instanceof OpDefNode) {
-            OpDefNode opDef = (OpDefNode)val;
-            opcode = BuiltInOPs.getOpCode(opDef.getName());
-            if (opcode == 0) {
-              // Context c1 = this.getOpContext(opDef, args, c, false);
-              Context c1 = this.getOpContext(opDef, args, c, true, cm);
-              return this.getNextStates(opDef.getBody(), acts, c1, s0, s1, nss, cm);
-            }
+				final OpDefNode opDef = (OpDefNode) val;
+				opcode = BuiltInOPs.getOpCode(opDef.getName());
+				if (opcode == 0) {
+					return this.getNextStates(action, opDef.getBody(), acts, this.getOpContext(opDef, args, c, true, cm, toolId), s0, s1, nss, cm);
+	            }
           }
 
           // Added by LL 13 Nov 2009 to fix Yuan's fix
@@ -1008,326 +951,331 @@ public final StateVec getNextStates(Action action, TLCState state) {
            * imported with parameterized instantiation.                         *
            *********************************************************************/
           if (val instanceof ThmOrAssumpDefNode) {
-            ThmOrAssumpDefNode opDef = (ThmOrAssumpDefNode)val;
-            Context c1 = this.getOpContext(opDef, args, c, true);
-            return this.getNextStates(opDef.getBody(), acts, c1, s0, s1, nss, cm);
+            final ThmOrAssumpDefNode opDef = (ThmOrAssumpDefNode)val;
+            return this.getNextStates(action, opDef.getBody(), acts, this.getOpContext(opDef, args, c, true), s0, s1, nss, cm);
           }
 
           if (val instanceof LazyValue) {
-            LazyValue lv = (LazyValue)val;
+            final LazyValue lv = (LazyValue)val;
             if (lv.getValue() == null || lv.isUncachable()) {
-              return this.getNextStates(lv.expr, acts, lv.con, s0, s1, nss, lv.cm);
+              return this.getNextStates(action, lv.expr, acts, lv.con, s0, s1, nss, lv.cm);
             }
             val = lv.getValue();
           }
 
-          Object bval = val;
-          if (alen == 0) {
-            if (val instanceof MethodValue) {
-              bval = ((MethodValue)val).apply(EmptyArgs, EvalControl.Clear);
-            }
-          }
-          else {
-            if (val instanceof OpValue) {
-           	  bval = ((OpValue) val).eval(this, args, c, s0, s1, EvalControl.Clear, cm);
-            }
-          }
+          //TODO If all eval/apply in getNextStatesApplEvalAppl would be side-effect free (ie. not mutate args, c, s0,...), 
+          // this call could be moved into the if(opcode==0) branch below. However, opcode!=0 will only be the case if
+          // OpDefNode above has been substed with a built-in operator. In other words, a user defines an operator Op1,
+          // and re-defines Op1 with a TLA+ built-in one in a TLC model (not assumed to be common). => No point in trying
+          // to move this call into if(opcode==0) because this will be the case most of the time anyway.
+          final Object bval = getNextStatesApplEvalAppl(alen, args, c, s0, s1, cm, val);
 
+	      // opcode == 0 is a user-defined operator.
           if (opcode == 0)
           {
-            if (!(bval instanceof BoolValue))
-            {
-              Assert.fail(EC.TLC_EXPECTED_EXPRESSION_IN_COMPUTING, new String[] { "next states", "boolean",
-                      bval.toString(), pred.toString() });
-            }
-            if (((BoolValue) bval).val)
-            {
-          	  if (coverage) {
-        		  return this.getNextStates(acts, s0, s1, nss, cm);
-          	  } else {
-          		  return this.getNextStates0(acts, s0, s1, nss, cm);
-          	  }
-            }
-            return s1;
+            return getNextStatesApplUsrDefOp(action, pred, acts, s0, s1, nss, cm, bval);
           }
         }
 
-        TLCState resState = s1;
-        switch (opcode) {
-        case OPCODE_cl:     // ConjList
-        case OPCODE_land:
-          {
-            ActionItemList acts1 = acts;
-            for (int i = alen - 1; i > 0; i--) {
-              acts1 = (ActionItemList) acts1.cons(args[i], c, cm, i);
-            }
-            return this.getNextStates(args[0], acts1, c, s0, s1, nss, cm);
-          }
-        case OPCODE_dl:     // DisjList
-        case OPCODE_lor:
-          {
-            for (int i = 0; i < alen; i++) {
-              resState = this.getNextStates(args[i], acts, c, s0, resState, nss, cm);
-            }
-            return resState;
-          }
-        case OPCODE_be:     // BoundedExists
-          {
-            SemanticNode body = args[0];
-            ContextEnumerator Enum = this.contexts(pred, c, s0, s1, EvalControl.Clear, cm);
-            Context c1;
-            while ((c1 = Enum.nextElement()) != null) {
-              resState = this.getNextStates(body, acts, c1, s0, resState, nss, cm);
-            }
-            return resState;
-          }
-        case OPCODE_bf:     // BoundedForall
-          {
-            SemanticNode body = args[0];
-            ContextEnumerator Enum = this.contexts(pred, c, s0, s1, EvalControl.Clear, cm);
-            Context c1 = Enum.nextElement();
-            if (c1 == null) {
-              resState = this.getNextStates(acts, s0, s1, nss, cm);
-            }
-            else {
-              ActionItemList acts1 = acts;
-              Context c2;
-              while ((c2 = Enum.nextElement()) != null) {
-                acts1 = (ActionItemList) acts1.cons(body, c2, cm, IActionItemList.PRED);
-              }
-              resState = this.getNextStates(body, acts1, c1, s0, s1, nss, cm);
-            }
-            return resState;
-          }
-        case OPCODE_fa:     // FcnApply
-          {
-            Value fval = this.eval(args[0], c, s0, s1, EvalControl.KeepLazy, cm);
-            if (fval instanceof FcnLambdaValue) {
-              FcnLambdaValue fcn = (FcnLambdaValue)fval;
-              if (fcn.fcnRcd == null) {
-                Context c1 = this.getFcnContext(fcn, args, c, s0, s1, EvalControl.Clear, cm);
-                return this.getNextStates(fcn.body, acts, c1, s0, s1, nss, cm);
-              }
-              fval = fcn.fcnRcd;
-            }
-            if (!(fval instanceof Applicable)) {
-              Assert.fail("In computing next states, a non-function (" +
-                          fval.getKindString() + ") was applied as a function.\n" + pred);
-            }
-            Applicable fcn = (Applicable)fval;
-            Value argVal = this.eval(args[1], c, s0, s1, EvalControl.Clear, cm);
-            Value bval = fcn.apply(argVal, EvalControl.Clear);
-            if (!(bval instanceof BoolValue)) {
-              Assert.fail(EC.TLC_EXPECTED_EXPRESSION_IN_COMPUTING2, new String[] { "next states", "boolean",
-                      pred.toString() });
-            }
-            if (((BoolValue)bval).val) {
-              return this.getNextStates(acts, s0, s1, nss, cm);
-            }
-            return resState;
-          }
-        case OPCODE_aa:     // AngleAct <A>_e
-          {
-            ActionItemList acts1 = (ActionItemList) acts.cons(args[1], c, cm, IActionItemList.CHANGED);
-            return this.getNextStates(args[0], acts1, c, s0, s1, nss, cm);
-          }
-        case OPCODE_sa:     // [A]_e
-          {
-            /* The following two lines of code did not work, and were changed by
-             * YuanYu to mimic the way \/ works.  Change made
-             *  11 Mar 2009, with LL sitting next to him.
-             */
-              //    this.getNextStates(args[0], acts, c, s0, s1, nss);
-              //    return this.processUnchanged(args[1], acts, c, s0, s1, nss);
-            resState = this.getNextStates(args[0], acts, c, s0, resState, nss, cm);
-            return this.processUnchanged(args[1], acts, c, s0, resState, nss, cm);
-          }
-        case OPCODE_ite:    // IfThenElse
-          {
-            Value guard = this.eval(args[0], c, s0, s1, EvalControl.Clear, cm);
-            if (!(guard instanceof BoolValue)) {
-              Assert.fail("In computing next states, a non-boolean expression (" +
-                          guard.getKindString() + ") was used as the condition of" +
-                          " an IF." + pred);
-            }
-            if (((BoolValue)guard).val) {
-              return this.getNextStates(args[1], acts, c, s0, s1, nss, cm);
-            }
-            else {
-              return this.getNextStates(args[2], acts, c, s0, s1, nss, cm);
-            }
-          }
-        case OPCODE_case:   // Case
-          {
-            SemanticNode other = null;
-            for (int i = 0; i < alen; i++) {
-              OpApplNode pair = (OpApplNode)args[i];
-              ExprOrOpArgNode[] pairArgs = pair.getArgs();
-              if (pairArgs[0] == null) {
-                other = pairArgs[1];
-              }
-              else {
-                Value bval = this.eval(pairArgs[0], c, s0, s1, EvalControl.Clear, coverage ? cm.get(args[i]) : cm);
-                if (!(bval instanceof BoolValue)) {
-                  Assert.fail("In computing next states, a non-boolean expression (" +
-                              bval.getKindString() + ") was used as a guard condition" +
-                              " of a CASE.\n" + pairArgs[1]);
-                }
-                if (((BoolValue)bval).val) {
-                  return this.getNextStates(pairArgs[1], acts, c, s0, s1, nss, coverage ? cm.get(args[i]) : cm);
-                }
-              }
-            }
-            if (other == null) {
-              Assert.fail("In computing next states, TLC encountered a CASE with no" +
-                          " conditions true.\n" + pred);
-            }
-            return this.getNextStates(other, acts, c, s0, s1, nss, coverage ? cm.get(args[alen - 1]) : cm);
-          }
-        case OPCODE_eq:
-          {
-            SymbolNode var = this.getPrimedVar(args[0], c, false);
-            // Assert.check(var.getName().getVarLoc() >= 0);
-            if (var == null) {
-              Value bval = this.eval(pred, c, s0, s1, EvalControl.Clear, cm);
-              if (!((BoolValue)bval).val) {
-                return resState;
-              }
-            }
-            else {
-              UniqueString varName = var.getName();
-              IValue lval = s1.lookup(varName);
-              Value rval = this.eval(args[1], c, s0, s1, EvalControl.Clear, cm);
-              if (lval == null) {
-                resState.bind(varName, rval);
-                resState = this.getNextStates(acts, s0, resState, nss, cm);
-                resState.unbind(varName);
-                return resState;
-              }
-              else if (!lval.equals(rval)) {
-                return resState;
-              }
-            }
-            return this.getNextStates(acts, s0, s1, nss, cm);
-          }
-        case OPCODE_in:
-          {
-            SymbolNode var = this.getPrimedVar(args[0], c, false);
-            // Assert.check(var.getName().getVarLoc() >= 0);
-            if (var == null) {
-              Value bval = this.eval(pred, c, s0, s1, EvalControl.Clear, cm);
-              if (!((BoolValue)bval).val) {
-                return resState;
-              }
-            }
-            else {
-              UniqueString varName = var.getName();
-              Value lval = (Value) s1.lookup(varName);
-              Value rval = this.eval(args[1], c, s0, s1, EvalControl.Clear, cm);
-              if (lval == null) {
-                if (!(rval instanceof Enumerable)) {
-                  Assert.fail("In computing next states, the right side of \\IN" +
-                              " is not enumerable.\n" + pred);
-                }
-                ValueEnumeration Enum = ((Enumerable)rval).elements();
-                Value elem;
-                while ((elem = Enum.nextElement()) != null) {
-                  resState.bind(varName, elem);
-                  resState = this.getNextStates(acts, s0, resState, nss, cm);
-                  resState.unbind(varName);
-                }
-                return resState;
-              }
-              else if (!rval.member(lval)) {
-                return resState;
-              }
-            }
-            return this.getNextStates(acts, s0, s1, nss, cm);
-          }
-        case OPCODE_implies:
-          {
-            Value bval = this.eval(args[0], c, s0, s1, EvalControl.Clear, cm);
-            if (!(bval instanceof BoolValue)) {
-              Assert.fail("In computing next states of a predicate of the form" +
-                          " P => Q, P was\n" + bval.getKindString() + ".\n" + pred);
-            }
-            if (((BoolValue)bval).val) {
-              return this.getNextStates(args[1], acts, c, s0, s1, nss, cm);
-            }
-            else {
-              return this.getNextStates(acts, s0, s1, nss, cm);
-            }
-          }
-        case OPCODE_unchanged:
-          {
-            return this.processUnchanged(args[0], acts, c, s0, s1, nss, cm);
-          }
-        case OPCODE_cdot:
-          {
-            Assert.fail("The current version of TLC does not support action composition.");
-            /***
-            TLCState s01 = TLCStateFun.Empty;
-            StateVec iss = new StateVec(0);
-            this.getNextStates(args[0], ActionItemList.Empty, c, s0, s01, iss);
-            int sz = iss.size();
-            for (int i = 0; i < sz; i++) {
-              s01 = iss.elementAt(i);
-              this.getNextStates(args[1], acts, c, s01, s1, nss);
-            }
-            ***/
-            return s1;
-          }
-        // The following case added by LL on 13 Nov 2009 to handle subexpression names.
-        case OPCODE_nop:
-        {
-            return this.getNextStates(args[0], acts, c, s0, s1, nss, cm);
-        }
-        default:
-          {
-            // We handle all the other builtin operators here.
-            Value bval = this.eval(pred, c, s0, s1, EvalControl.Clear, cm);
-            if (!(bval instanceof BoolValue)) {
-              Assert.fail(EC.TLC_EXPECTED_EXPRESSION_IN_COMPUTING, new String[] { "next states", "boolean",
-                      bval.toString(), pred.toString() });
-            }
-            if (((BoolValue)bval).val) {
-              resState = this.getNextStates(acts, s0, s1, nss, cm);
-            }
-            return resState;
-          }
-        }
+        return getNextStatesApplSwitch(action, pred, acts, c, s0, s1, nss, cm, args, alen, opcode);
   }
   
-  /* processUnchanged */
+  private final Object getNextStatesApplEvalAppl(final int alen, final ExprOrOpArgNode[] args, final Context c,
+			final TLCState s0, final TLCState s1, final CostModel cm, final Object val) {
+	      if (alen == 0) {
+        if (val instanceof MethodValue) {
+        	return ((MethodValue)val).apply(EmptyArgs, EvalControl.Clear);
+        } else if (val instanceof EvaluatingValue) {
+        	return ((EvaluatingValue)val).eval(this, args, c, s0, s1, EvalControl.Clear, cm);
+       }
+      }
+      else {
+        if (val instanceof OpValue) { // EvaluatingValue sub-class of OpValue!
+       	  return ((OpValue) val).eval(this, args, c, s0, s1, EvalControl.Clear, cm);
+        }
+      }
+      return val;
+  }
 
-  private final TLCState processUnchanged(SemanticNode expr, ActionItemList acts, Context c,
-                                          TLCState s0, TLCState s1, StateVec nss, CostModel cm) {
-	  if (this.callStack != null) {
-		  return processUnchangedWithCallStack(expr, acts, c, s0, s1, nss, cm);
+  private final TLCState getNextStatesApplUsrDefOp(final Action action, final OpApplNode pred, final ActionItemList acts, final TLCState s0,
+		final TLCState s1, final INextStateFunctor nss, final CostModel cm, final Object bval) {
+	if (!(bval instanceof BoolValue))
+	{
+	  Assert.fail(EC.TLC_EXPECTED_EXPRESSION_IN_COMPUTING, new String[] { "next states", "boolean",
+	          bval.toString(), pred.toString() });
+	}
+	if (((BoolValue) bval).val)
+	{
+	  if (coverage) {
+		  return this.getNextStates(action, acts, s0, s1, nss, cm);
 	  } else {
-		   return processUnchangedImpl(expr, acts, c, s0, s1, nss, cm);
+		  return this.getNextStates0(action, acts, s0, s1, nss, cm);
 	  }
-  }
-  private final TLCState processUnchangedWithCallStack(SemanticNode expr, ActionItemList acts, Context c,
-          TLCState s0, TLCState s1, StateVec nss, CostModel cm) {
-	   this.callStack.push(expr);
-	   try {
-		   return processUnchangedImpl(expr, acts, c, s0, s1, nss, cm);
-	    } catch (TLCRuntimeException | EvalException e) {
-	    	// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor)
-	    	this.callStack.freeze();
-	    	throw e;
-	    } finally {
-	    	this.callStack.pop();
+	}
+	return s1;
+  }
+
+  private final TLCState getNextStatesApplSwitch(final Action action, final OpApplNode pred, final ActionItemList acts, final Context c, final TLCState s0,
+		final TLCState s1, final INextStateFunctor nss, final CostModel cm, final ExprOrOpArgNode[] args, final int alen, final int opcode) {
+	TLCState resState = s1;
+	switch (opcode) {
+	case OPCODE_cl:     // ConjList
+	case OPCODE_land:
+	  {
+	    ActionItemList acts1 = acts;
+	    for (int i = alen - 1; i > 0; i--) {
+	      acts1 = (ActionItemList) acts1.cons(args[i], c, cm, i);
+	    }
+	    return this.getNextStates(action, args[0], acts1, c, s0, s1, nss, cm);
+	  }
+	case OPCODE_dl:     // DisjList
+	case OPCODE_lor:
+	  {
+	    for (int i = 0; i < alen; i++) {
+	      resState = this.getNextStates(action, args[i], acts, c, s0, resState, nss, cm);
+	    }
+	    return resState;
+	  }
+	case OPCODE_be:     // BoundedExists
+	  {
+	    SemanticNode body = args[0];
+	    ContextEnumerator Enum = this.contexts(pred, c, s0, s1, EvalControl.Clear, cm);
+	    Context c1;
+	    while ((c1 = Enum.nextElement()) != null) {
+	      resState = this.getNextStates(action, body, acts, c1, s0, resState, nss, cm);
+	    }
+	    return resState;
+	  }
+	case OPCODE_bf:     // BoundedForall
+	  {
+	    SemanticNode body = args[0];
+	    ContextEnumerator Enum = this.contexts(pred, c, s0, s1, EvalControl.Clear, cm);
+	    Context c1 = Enum.nextElement();
+	    if (c1 == null) {
+	      resState = this.getNextStates(action, acts, s0, s1, nss, cm);
+	    }
+	    else {
+	      ActionItemList acts1 = acts;
+	      Context c2;
+	      while ((c2 = Enum.nextElement()) != null) {
+	        acts1 = (ActionItemList) acts1.cons(body, c2, cm, IActionItemList.PRED);
+	      }
+	      resState = this.getNextStates(action, body, acts1, c1, s0, s1, nss, cm);
+	    }
+	    return resState;
+	  }
+	case OPCODE_fa:     // FcnApply
+	  {
+	    Value fval = this.eval(args[0], c, s0, s1, EvalControl.KeepLazy, cm);
+	    if (fval instanceof FcnLambdaValue) {
+	      FcnLambdaValue fcn = (FcnLambdaValue)fval;
+	      if (fcn.fcnRcd == null) {
+	        Context c1 = this.getFcnContext(fcn, args, c, s0, s1, EvalControl.Clear, cm);
+	        return this.getNextStates(action, fcn.body, acts, c1, s0, s1, nss, fcn.cm);
+	      }
+	      fval = fcn.fcnRcd;
+	    }
+	    if (!(fval instanceof Applicable)) {
+	      Assert.fail("In computing next states, a non-function (" +
+	                  fval.getKindString() + ") was applied as a function.\n" + pred);
+	    }
+	    Applicable fcn = (Applicable)fval;
+	    Value argVal = this.eval(args[1], c, s0, s1, EvalControl.Clear, cm);
+	    Value bval = fcn.apply(argVal, EvalControl.Clear);
+	    if (!(bval instanceof BoolValue)) {
+	      Assert.fail(EC.TLC_EXPECTED_EXPRESSION_IN_COMPUTING2, new String[] { "next states", "boolean",
+	              pred.toString() });
+	    }
+	    if (((BoolValue)bval).val) {
+	      return this.getNextStates(action, acts, s0, s1, nss, cm);
+	    }
+	    return resState;
+	  }
+	case OPCODE_aa:     // AngleAct <A>_e
+	  {
+	    ActionItemList acts1 = (ActionItemList) acts.cons(args[1], c, cm, IActionItemList.CHANGED);
+	    return this.getNextStates(action, args[0], acts1, c, s0, s1, nss, cm);
+	  }
+	case OPCODE_sa:     // [A]_e
+	  {
+	    /* The following two lines of code did not work, and were changed by
+	     * YuanYu to mimic the way \/ works.  Change made
+	     *  11 Mar 2009, with LL sitting next to him.
+	     */
+	      //    this.getNextStates(action, args[0], acts, c, s0, s1, nss);
+	      //    return this.processUnchanged(args[1], acts, c, s0, s1, nss);
+	    resState = this.getNextStates(action, args[0], acts, c, s0, resState, nss, cm);
+	    return this.processUnchanged(action, args[1], acts, c, s0, resState, nss, cm);
+	  }
+	case OPCODE_ite:    // IfThenElse
+	  {
+	    Value guard = this.eval(args[0], c, s0, s1, EvalControl.Clear, cm);
+	    if (!(guard instanceof BoolValue)) {
+	      Assert.fail("In computing next states, a non-boolean expression (" +
+	                  guard.getKindString() + ") was used as the condition of" +
+	                  " an IF." + pred);
+	    }
+	    if (((BoolValue)guard).val) {
+	      return this.getNextStates(action, args[1], acts, c, s0, s1, nss, cm);
+	    }
+	    else {
+	      return this.getNextStates(action, args[2], acts, c, s0, s1, nss, cm);
+	    }
+	  }
+	case OPCODE_case:   // Case
+	  {
+	    SemanticNode other = null;
+	    for (int i = 0; i < alen; i++) {
+	      OpApplNode pair = (OpApplNode)args[i];
+	      ExprOrOpArgNode[] pairArgs = pair.getArgs();
+	      if (pairArgs[0] == null) {
+	        other = pairArgs[1];
+	      }
+	      else {
+	        Value bval = this.eval(pairArgs[0], c, s0, s1, EvalControl.Clear, coverage ? cm.get(args[i]) : cm);
+	        if (!(bval instanceof BoolValue)) {
+	          Assert.fail("In computing next states, a non-boolean expression (" +
+	                      bval.getKindString() + ") was used as a guard condition" +
+	                      " of a CASE.\n" + pairArgs[1]);
+	        }
+	        if (((BoolValue)bval).val) {
+	          return this.getNextStates(action, pairArgs[1], acts, c, s0, s1, nss, coverage ? cm.get(args[i]) : cm);
+	        }
+	      }
+	    }
+	    if (other == null) {
+	      Assert.fail("In computing next states, TLC encountered a CASE with no" +
+	                  " conditions true.\n" + pred);
+	    }
+	    return this.getNextStates(action, other, acts, c, s0, s1, nss, coverage ? cm.get(args[alen - 1]) : cm);
+	  }
+	case OPCODE_eq:
+	  {
+	    SymbolNode var = this.getPrimedVar(args[0], c, false);
+	    // Assert.check(var.getName().getVarLoc() >= 0);
+	    if (var == null) {
+	      Value bval = this.eval(pred, c, s0, s1, EvalControl.Clear, cm);
+	      if (!((BoolValue)bval).val) {
+	        return resState;
+	      }
+	    }
+	    else {
+	      UniqueString varName = var.getName();
+	      IValue lval = s1.lookup(varName);
+	      Value rval = this.eval(args[1], c, s0, s1, EvalControl.Clear, cm);
+	      if (lval == null) {
+	        resState.bind(varName, rval);
+	        resState = this.getNextStates(action, acts, s0, resState, nss, cm);
+	        resState.unbind(varName);
+	        return resState;
+	      }
+	      else if (!lval.equals(rval)) {
+	        return resState;
+	      }
+	    }
+	    return this.getNextStates(action, acts, s0, s1, nss, cm);
+	  }
+	case OPCODE_in:
+	  {
+	    SymbolNode var = this.getPrimedVar(args[0], c, false);
+	    // Assert.check(var.getName().getVarLoc() >= 0);
+	    if (var == null) {
+	      Value bval = this.eval(pred, c, s0, s1, EvalControl.Clear, cm);
+	      if (!((BoolValue)bval).val) {
+	        return resState;
+	      }
+	    }
+	    else {
+	      UniqueString varName = var.getName();
+	      Value lval = (Value) s1.lookup(varName);
+	      Value rval = this.eval(args[1], c, s0, s1, EvalControl.Clear, cm);
+	      if (lval == null) {
+	        if (!(rval instanceof Enumerable)) {
+	          Assert.fail("In computing next states, the right side of \\IN" +
+	                      " is not enumerable.\n" + pred);
+	        }
+	        ValueEnumeration Enum = ((Enumerable)rval).elements();
+	        Value elem;
+	        while ((elem = Enum.nextElement()) != null) {
+	          resState.bind(varName, elem);
+	          resState = this.getNextStates(action, acts, s0, resState, nss, cm);
+	          resState.unbind(varName);
+	        }
+	        return resState;
+	      }
+	      else if (!rval.member(lval)) {
+	        return resState;
+	      }
+	    }
+	    return this.getNextStates(action, acts, s0, s1, nss, cm);
+	  }
+	case OPCODE_implies:
+	  {
+	    Value bval = this.eval(args[0], c, s0, s1, EvalControl.Clear, cm);
+	    if (!(bval instanceof BoolValue)) {
+	      Assert.fail("In computing next states of a predicate of the form" +
+	                  " P => Q, P was\n" + bval.getKindString() + ".\n" + pred);
+	    }
+	    if (((BoolValue)bval).val) {
+	      return this.getNextStates(action, args[1], acts, c, s0, s1, nss, cm);
+	    }
+	    else {
+	      return this.getNextStates(action, acts, s0, s1, nss, cm);
+	    }
+	  }
+	case OPCODE_unchanged:
+	  {
+	    return this.processUnchanged(action, args[0], acts, c, s0, s1, nss, cm);
+	  }
+	case OPCODE_cdot:
+	  {
+	    Assert.fail("The current version of TLC does not support action composition.");
+	    /***
+	    TLCState s01 = TLCStateFun.Empty;
+	    StateVec iss = new StateVec(0);
+	    this.getNextStates(action, args[0], ActionItemList.Empty, c, s0, s01, iss);
+	    int sz = iss.size();
+	    for (int i = 0; i < sz; i++) {
+	      s01 = iss.elementAt(i);
+	      this.getNextStates(action, args[1], acts, c, s01, s1, nss);
+	    }
+	    ***/
+	    return s1;
+	  }
+	// The following case added by LL on 13 Nov 2009 to handle subexpression names.
+	case OPCODE_nop:
+	{
+	    return this.getNextStates(action, args[0], acts, c, s0, s1, nss, cm);
+	}
+	default:
+	  {
+	    // We handle all the other builtin operators here.
+	    Value bval = this.eval(pred, c, s0, s1, EvalControl.Clear, cm);
+	    if (!(bval instanceof BoolValue)) {
+	      Assert.fail(EC.TLC_EXPECTED_EXPRESSION_IN_COMPUTING, new String[] { "next states", "boolean",
+	              bval.toString(), pred.toString() });
+	    }
+	    if (((BoolValue)bval).val) {
+	      resState = this.getNextStates(action, acts, s0, s1, nss, cm);
 	    }
+	    return resState;
+	  }
+	}
   }
-  private final TLCState processUnchangedImpl(SemanticNode expr, ActionItemList acts, Context c,
-          TLCState s0, TLCState s1, StateVec nss, CostModel cm) {
+  
+  /* processUnchanged */
+
+  @ExpectInlined
+  protected abstract TLCState processUnchanged(final Action action, SemanticNode expr, ActionItemList acts, Context c,
+                                          TLCState s0, TLCState s1, INextStateFunctor nss, CostModel cm);
+  
+  protected final TLCState processUnchangedImpl(final Action action, SemanticNode expr, ActionItemList acts, Context c,
+          TLCState s0, TLCState s1, INextStateFunctor nss, CostModel cm) {
     if (coverage){cm = cm.get(expr);}
-        SymbolNode var = this.getVar(expr, c, false);
+        SymbolNode var = this.getVar(expr, c, false, toolId);
         TLCState resState = s1;
         if (var != null) {
-            return processUnchangedImplVar(expr, acts, s0, s1, nss, var, cm);
+            return processUnchangedImplVar(action, expr, acts, s0, s1, nss, var, cm);
         }
 
         if (expr instanceof OpApplNode) {
@@ -1339,40 +1287,41 @@ public final StateVec getNextStates(Action action, TLCState state) {
           int opcode = BuiltInOPs.getOpCode(opName);
 
           if (opcode == OPCODE_tup) {
-            return processUnchangedImplTuple(acts, c, s0, s1, nss, args, alen, cm, coverage ? cm.get(expr1) : cm);
+            return processUnchangedImplTuple(action, acts, c, s0, s1, nss, args, alen, cm, coverage ? cm.get(expr1) : cm);
           }
 
           if (opcode == 0 && alen == 0) {
             // a 0-arity operator:
-            return processUnchangedImpl0Arity(expr, acts, c, s0, s1, nss, cm, opNode, opName);
+            return processUnchangedImpl0Arity(action, expr, acts, c, s0, s1, nss, cm, opNode, opName);
           }
         }
 
         IValue v0 = this.eval(expr, c, s0, cm);
         Value v1 = this.eval(expr, c, s1, null, EvalControl.Clear, cm);
         if (v0.equals(v1)) {
-          resState = this.getNextStates(acts, s0, s1, nss, cm);
+          resState = this.getNextStates(action, acts, s0, s1, nss, cm);
         }
         return resState;
   }
 
-  private final TLCState processUnchangedImpl0Arity(final SemanticNode expr, final ActionItemList acts,
-			final Context c, final TLCState s0, final TLCState s1, final StateVec nss, final CostModel cm,
+  @ExpectInlined
+  private final TLCState processUnchangedImpl0Arity(final Action action, final SemanticNode expr, final ActionItemList acts,
+			final Context c, final TLCState s0, final TLCState s1, final INextStateFunctor nss, final CostModel cm,
 			final SymbolNode opNode, final UniqueString opName) {
 		final Object val = this.lookup(opNode, c, false);
 	
 		if (val instanceof OpDefNode) {
-		  return this.processUnchanged(((OpDefNode)val).getBody(), acts, c, s0, s1, nss, cm);
+		  return this.processUnchanged(action, ((OpDefNode)val).getBody(), acts, c, s0, s1, nss, cm);
 		}
 		else if (val instanceof LazyValue) {
 		  final LazyValue lv = (LazyValue)val;
-		  return this.processUnchanged(lv.expr, acts, lv.con, s0, s1, nss, cm);
+		  return this.processUnchanged(action, lv.expr, acts, lv.con, s0, s1, nss, cm);
 		}
 		else {
 		  Assert.fail("In computing next states, TLC found the identifier\n" +
 		              opName + " undefined in an UNCHANGED expression at\n" + expr);
 		}
-		return this.getNextStates(acts, s0, s1, nss, cm);
+		return this.getNextStates(action, acts, s0, s1, nss, cm);
   }
 
   @Override
@@ -1380,7 +1329,8 @@ public final StateVec getNextStates(Action action, TLCState state) {
 	    return this.eval(expr, c, s0, TLCState.Empty, EvalControl.Clear, CostModel.DO_NOT_RECORD);
 	  }
 
-  private final TLCState processUnchangedImplTuple(ActionItemList acts, Context c, TLCState s0, TLCState s1, StateVec nss,
+  @ExpectInlined
+  private final TLCState processUnchangedImplTuple(final Action action, ActionItemList acts, Context c, TLCState s0, TLCState s1, INextStateFunctor nss,
   		ExprOrOpArgNode[] args, int alen, CostModel cm, CostModel cmNested) {
   	// a tuple:
   	if (alen != 0) {
@@ -1388,12 +1338,13 @@ public final StateVec getNextStates(Action action, TLCState state) {
   	  for (int i = alen-1; i > 0; i--) {
   	    acts1 = (ActionItemList) acts1.cons(args[i], c, cmNested, IActionItemList.UNCHANGED);
   	  }
-  	  return this.processUnchanged(args[0], acts1, c, s0, s1, nss, cmNested);
+  	  return this.processUnchanged(action, args[0], acts1, c, s0, s1, nss, cmNested);
   	}
-  	return this.getNextStates(acts, s0, s1, nss, cm);
+  	return this.getNextStates(action, acts, s0, s1, nss, cm);
   }
   
-  private final TLCState processUnchangedImplVar(SemanticNode expr, ActionItemList acts, TLCState s0, TLCState s1, StateVec nss,
+  @ExpectInlined
+  private final TLCState processUnchangedImplVar(final Action action, SemanticNode expr, ActionItemList acts, TLCState s0, TLCState s1, INextStateFunctor nss,
   		SymbolNode var, final CostModel cm) {
           TLCState resState = s1;
           // expr is a state variable:
@@ -1403,17 +1354,17 @@ public final StateVec getNextStates(Action action, TLCState state) {
           if (val1 == null) {
 		  	resState.bind(varName, val0);
             if (coverage) {
-            	resState = this.getNextStates(acts, s0, resState, nss, cm);
+            	resState = this.getNextStates(action, acts, s0, resState, nss, cm);
             } else {
-            	resState = this.getNextStates0(acts, s0, resState, nss, cm);
+            	resState = this.getNextStates0(action, acts, s0, resState, nss, cm);
             }
 		  	resState.unbind(varName);
           }
           else if (val0.equals(val1)) {
               if (coverage) {
-                  resState = this.getNextStates(acts, s0, s1, nss, cm);
+                  resState = this.getNextStates(action, acts, s0, s1, nss, cm);
               } else {
-                  resState = this.getNextStates0(acts, s0, s1, nss, cm);
+                  resState = this.getNextStates0(action, acts, s0, s1, nss, cm);
               }
           }
           else {
@@ -1439,29 +1390,11 @@ public final StateVec getNextStates(Action action, TLCState state) {
    * This method evaluates the expression expr in the given context,
    * current state, and partial next state.
    */
-  public final Value eval(SemanticNode expr, Context c, TLCState s0,
-                          TLCState s1, final int control, final CostModel cm) {
-	    if (this.callStack != null) {
-	    	return evalWithCallStack(expr, c, s0, s1, control, cm);
-	    } else {
-	    	return evalImpl(expr, c, s0, s1, control, cm);
-	    }
-  }
-  private final Value evalWithCallStack(SemanticNode expr, Context c, TLCState s0,
-          TLCState s1, final int control, final CostModel cm) {
-	    this.callStack.push(expr);
-	    try {
-	    	return evalImpl(expr, c, s0, s1, control, cm);
-	    } catch (TLCRuntimeException | EvalException e) {
-	    	// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor)
-	    	this.callStack.freeze();
-	    	throw e;
-	    } finally {
-	    	this.callStack.pop();
-	    }
-  }
+  public abstract Value eval(SemanticNode expr, Context c, TLCState s0,
+                          TLCState s1, final int control, final CostModel cm);
   
-  private final Value evalImpl(final SemanticNode expr, final Context c, final TLCState s0,
+  @ExpectInlined
+  protected final Value evalImpl(final SemanticNode expr, final Context c, final TLCState s0,
           final TLCState s1, final int control, CostModel cm) {
         switch (expr.getKind()) {
         /***********************************************************************
@@ -1495,7 +1428,7 @@ public final StateVec getNextStates(Action action, TLCState state) {
         case DecimalKind:
         case StringKind:
           {
-            return (Value) expr.getToolObject(toolId);
+            return (Value) WorkerValue.mux(expr.getToolObject(toolId));
           }
         case AtNodeKind:
           {
@@ -1514,6 +1447,7 @@ public final StateVec getNextStates(Action action, TLCState state) {
         }
   }
 
+  @ExpectInlined
   private final Value evalImplLetInKind(LetInNode expr1, Context c, TLCState s0, TLCState s1, final int control, final CostModel cm) {
 	OpDefNode[] letDefs = expr1.getLets();
 	int letLen = letDefs.length;
@@ -1528,28 +1462,31 @@ public final StateVec getNextStates(Action action, TLCState state) {
 	return this.eval(expr1.getBody(), c1, s0, s1, control, cm);
   }
 
+  @ExpectInlined
   private final Value evalImplSubstInKind(SubstInNode expr1, Context c, TLCState s0, TLCState s1, final int control, final CostModel cm) {
   	Subst[] subs = expr1.getSubsts();
   	int slen = subs.length;
   	Context c1 = c;
   	for (int i = 0; i < slen; i++) {
   	  Subst sub = subs[i];
-  	  c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true, coverage ? sub.getCM() : cm));
+  	  c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true, coverage ? sub.getCM() : cm, toolId));
   	}
   	return this.eval(expr1.getBody(), c1, s0, s1, control, cm);
   }
     
+  @ExpectInlined
   private final Value evalImplApSubstInKind(APSubstInNode expr1, Context c, TLCState s0, TLCState s1, final int control, final CostModel cm) {
   	Subst[] subs = expr1.getSubsts();
   	int slen = subs.length;
   	Context c1 = c;
   	for (int i = 0; i < slen; i++) {
   	  Subst sub = subs[i];
-  	  c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true, cm));
+  	  c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, true, cm, toolId));
   	}
   	return this.eval(expr1.getBody(), c1, s0, s1, control, cm);
   }
   
+  @ExpectInlined
   private final Value evalImplOpArgKind(OpArgNode expr1, Context c, TLCState s0, TLCState s1, final CostModel cm) {
   	SymbolNode opNode = expr1.getOp();
   	Object val = this.lookup(opNode, c, false);
@@ -1561,30 +1498,11 @@ public final StateVec getNextStates(Action action, TLCState state) {
   
   /* evalAppl */
   
-  private final Value evalAppl(final OpApplNode expr, Context c, TLCState s0,
-          TLCState s1, final int control, final CostModel cm) {
-	  if (this.callStack != null) {
-		  return evalApplWithCallStack(expr, c, s0, s1, control, cm);
-	  } else {
-		  return evalApplImpl(expr, c, s0, s1, control, cm);
-	  }
-  }
+  @ExpectInlined
+  protected abstract Value evalAppl(final OpApplNode expr, Context c, TLCState s0,
+          TLCState s1, final int control, final CostModel cm);
 
-  private final Value evalApplWithCallStack(final OpApplNode expr, Context c, TLCState s0,
-          TLCState s1, final int control, final CostModel cm) {
-	    this.callStack.push(expr);
-	    try {
-	    	return evalApplImpl(expr, c, s0, s1, control, cm);
-	    } catch (TLCRuntimeException | EvalException e) {
-	    	// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor)
-	    	this.callStack.freeze();
-	    	throw e;
-	    } finally {
-	    	this.callStack.pop();
-	    }
-  }
-  
-  private final Value evalApplImpl(final OpApplNode expr, Context c, TLCState s0,
+  protected final Value evalApplImpl(final OpApplNode expr, Context c, TLCState s0,
                               TLCState s1, final int control, CostModel cm) {
     if (coverage){
     	cm = cm.getAndIncrement(expr);
@@ -1712,7 +1630,7 @@ public final StateVec getNextStates(Action action, TLCState state) {
             OpDefNode opDef = (OpDefNode)val;
             opcode = BuiltInOPs.getOpCode(opDef.getName());
             if (opcode == 0) {
-              Context c1 = this.getOpContext(opDef, args, c, true, cm);
+              Context c1 = this.getOpContext(opDef, args, c, true, cm, toolId);
               res = this.eval(opDef.getBody(), c1, s0, s1, control, cm);
             }
           }
@@ -1722,8 +1640,15 @@ public final StateVec getNextStates(Action action, TLCState state) {
             if (alen == 0) {
               if (val instanceof MethodValue) {
                 res = ((MethodValue)val).apply(EmptyArgs, EvalControl.Clear);
+              } else if (val instanceof EvaluatingValue) {
+            	  // Allow EvaluatingValue overwrites to have zero arity.
+            	  res = ((EvaluatingValue) val).eval(this, args, c, s0, s1, control, cm);
               }
             }
+            else if (val instanceof Evaluator) {
+            	  Evaluator evaluator = (Evaluator) val;
+            	  res = evaluator.eval(this, args, c, s0, s1, control, cm);
+            } 
             else {
               if (val instanceof OpValue) {
             	  res = ((OpValue) val).eval(this, args, c, s0, s1, control, cm);
@@ -1883,7 +1808,8 @@ public final StateVec getNextStates(Action action, TLCState state) {
               ExprOrOpArgNode[] pairArgs = pairNode.getArgs();
               if (pairArgs[0] == null) {
                 other = pairArgs[1];
-              }
+                if (coverage) { cm = cm.get(pairNode); }
+               }
               else {
                 Value bval = this.eval(pairArgs[0], c, s0, s1, control, coverage ? cm.get(pairNode) : cm);
                 if (!(bval instanceof BoolValue)) {
@@ -2049,7 +1975,7 @@ public final StateVec getNextStates(Action action, TLCState state) {
         case OPCODE_rs:     // RcdSelect
           {
             Value rval = this.eval(args[0], c, s0, s1, control, cm);
-            Value sval = (Value) args[1].getToolObject(toolId);
+            Value sval = (Value) WorkerValue.mux(args[1].getToolObject(toolId));
             if (rval instanceof RecordValue) {
               Value result = (Value) ((RecordValue)rval).select(sval);
               if (result == null) {
@@ -2475,12 +2401,7 @@ public final StateVec getNextStates(Action action, TLCState state) {
         }
   }
 
-  private final Value setSource(final SemanticNode expr, final Value value) {
-    if (this.callStack != null) {
-      value.setSource(expr);
-    }
-    return value;
-  }
+  protected abstract Value setSource(final SemanticNode expr, final Value value);
 
   /**
    * This method determines if the argument is a valid state.  A state
@@ -2520,6 +2441,11 @@ public final StateVec getNextStates(Action action, TLCState state) {
     return true;
   }
   
+  @Override
+  public final boolean hasStateOrActionConstraints() {
+	  return this.getModelConstraints().length > 0 || this.getActionConstraints().length > 0;
+  }
+  
   @Override
   public final TLCState enabled(SemanticNode pred, Context c, TLCState s0, TLCState s1) {
 		  return enabled(pred, ActionItemList.Empty, c, s0, s1, CostModel.DO_NOT_RECORD);
@@ -2542,30 +2468,10 @@ public final StateVec getNextStates(Action action, TLCState state) {
    * enabled in the state s and context act.con.
    */
   @Override
-  public final TLCState enabled(SemanticNode pred, IActionItemList acts,
-                                Context c, TLCState s0, TLCState s1, CostModel cm) {
-	    if (this.callStack != null) {
-	    	return enabledWithCallStack(pred, (ActionItemList) acts, c, s0, s1, cm);
-	    } else {
-	    	return enabledImpl(pred, (ActionItemList) acts, c, s0, s1, cm);
-	    }
-  }
+  public abstract TLCState enabled(SemanticNode pred, IActionItemList acts,
+                                Context c, TLCState s0, TLCState s1, CostModel cm);
 
-  private final TLCState enabledWithCallStack(SemanticNode pred, ActionItemList acts,
-          Context c, TLCState s0, TLCState s1, CostModel cm) {
-    this.callStack.push(pred);
-    try {
-    	return enabledImpl(pred, acts, c, s0, s1, cm);
-    } catch (TLCRuntimeException | EvalException e) {
-    	// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor)
-    	this.callStack.freeze();
-    	throw e;
-    } finally {
-    	this.callStack.pop();
-    }
-  }
-  
-  private final TLCState enabledImpl(SemanticNode pred, ActionItemList acts,
+  protected final TLCState enabledImpl(SemanticNode pred, ActionItemList acts,
           Context c, TLCState s0, TLCState s1, CostModel cm) {
         switch (pred.getKind()) {
         case OpApplKind:
@@ -2595,7 +2501,7 @@ public final StateVec getNextStates(Action action, TLCState state) {
             Context c1 = c;
             for (int i = 0; i < slen; i++) {
               Subst sub = subs[i];
-              c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, coverage ? sub.getCM() : cm));
+              c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, coverage ? sub.getCM() : cm, toolId));
             }
             return this.enabled(pred1.getBody(), acts, c1, s0, s1, cm);
           }
@@ -2608,7 +2514,7 @@ public final StateVec getNextStates(Action action, TLCState state) {
             Context c1 = c;
             for (int i = 0; i < slen; i++) {
               Subst sub = subs[i];
-              c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, cm));
+              c1 = c1.cons(sub.getOp(), this.getVal(sub.getExpr(), c, false, cm, toolId));
             }
             return this.enabled(pred1.getBody(), acts, c1, s0, s1, cm);
           }
@@ -2659,30 +2565,9 @@ public final StateVec getNextStates(Action action, TLCState state) {
     return res;
   }
 
-  private final TLCState enabledAppl(OpApplNode pred, ActionItemList acts, Context c, TLCState s0, TLCState s1, CostModel cm)
-  {
-	    if (this.callStack != null) {
-	    	return enabledApplWithCallStack(pred, acts, c, s0, s1, cm);
-	    } else {
-	    	return enabledApplImpl(pred, acts, c, s0, s1, cm);
-	    }
-  }
+  protected abstract TLCState enabledAppl(OpApplNode pred, ActionItemList acts, Context c, TLCState s0, TLCState s1, CostModel cm);
 
-  private final TLCState enabledApplWithCallStack(OpApplNode pred, ActionItemList acts, Context c, TLCState s0, TLCState s1, CostModel cm)
-  {
-	    this.callStack.push(pred);
-	    try {
-	    	return enabledApplImpl(pred, acts, c, s0, s1, cm);
-	    } catch (TLCRuntimeException | EvalException e) {
-	    	// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor)
-	    	this.callStack.freeze();
-	    	throw e;
-	    } finally {
-	    	this.callStack.pop();
-	    }
-  }
- 
-  private final TLCState enabledApplImpl(OpApplNode pred, ActionItemList acts, Context c, TLCState s0, TLCState s1, CostModel cm)
+  protected final TLCState enabledApplImpl(OpApplNode pred, ActionItemList acts, Context c, TLCState s0, TLCState s1, CostModel cm)
   {
     if (coverage) {cm = cm.get(pred);}
         ExprOrOpArgNode[] args = pred.getArgs();
@@ -2704,7 +2589,7 @@ public final StateVec getNextStates(Action action, TLCState state) {
             if (opcode == 0)
             {
               // Context c1 = this.getOpContext(opDef, args, c, false);
-              Context c1 = this.getOpContext(opDef, args, c, true, cm);
+              Context c1 = this.getOpContext(opDef, args, c, true, cm, toolId);
               return this.enabled(opDef.getBody(), acts, c1, s0, s1, cm);
             }
           }
@@ -3079,33 +2964,13 @@ public final StateVec getNextStates(Action action, TLCState state) {
         }
   }
 
-  private final TLCState enabledUnchanged(SemanticNode expr, ActionItemList acts,
-                                          Context c, TLCState s0, TLCState s1, CostModel cm) {
-	    if (this.callStack != null) {
-	    	return enabledUnchangedWithCallStack(expr, acts, c, s0, s1, cm);
-	    } else {
-	    	return enabledUnchangedImpl(expr, acts, c, s0, s1, cm);
-	    }
-  }
-
-  private final TLCState enabledUnchangedWithCallStack(SemanticNode expr, ActionItemList acts,
-          Context c, TLCState s0, TLCState s1, CostModel cm) {
-    this.callStack.push(expr);
-    try {
-    	return enabledUnchangedImpl(expr, acts, c, s0, s1, cm);
-    } catch (TLCRuntimeException | EvalException e) {
-    	// see tlc2.tool.Tool.getInitStates(SemanticNode, ActionItemList, Context, TLCState, IStateFunctor)
-    	this.callStack.freeze();
-    	throw e;
-    } finally {
-    	this.callStack.pop();
-    }
-  }
+  protected abstract TLCState enabledUnchanged(SemanticNode expr, ActionItemList acts,
+                                          Context c, TLCState s0, TLCState s1, CostModel cm);
   
-  private final TLCState enabledUnchangedImpl(SemanticNode expr, ActionItemList acts,
+  protected final TLCState enabledUnchangedImpl(SemanticNode expr, ActionItemList acts,
             Context c, TLCState s0, TLCState s1, CostModel cm) {
 	    if (coverage) {cm = cm.get(expr);}
-        SymbolNode var = this.getVar(expr, c, true);
+        SymbolNode var = this.getVar(expr, c, true, toolId);
         if (var != null) {
           // a state variable, e.g. UNCHANGED var1
           UniqueString varName = var.getName();
@@ -3341,13 +3206,137 @@ public final StateVec getNextStates(Action action, TLCState state) {
     if (!(symm instanceof OpDefNode)) {
       Assert.fail("The symmetry function " + name + " must specify a set of permutations.");
     }
+    final OpDefNode opDef = (OpDefNode)symm;
     // This calls tlc2.module.TLC.Permutations(Value) and returns a Value of |fcns|
     // = n! where n is the capacity of the symmetry set.
-    final IValue fcns = this.eval(((OpDefNode)symm).getBody(), Context.Empty, TLCState.Empty, CostModel.DO_NOT_RECORD);
-    if (!(fcns instanceof Enumerable)) {
+    final IValue fcns = this.eval(opDef.getBody(), Context.Empty, TLCState.Empty, CostModel.DO_NOT_RECORD);
+    if (!(fcns instanceof Enumerable) || !(fcns instanceof SetEnumValue)) {
       Assert.fail("The symmetry operator must specify a set of functions.");
     }
-    return MVPerms.permutationSubgroup((Enumerable) fcns);
+    final List<Value> values = ((SetEnumValue)fcns).elements().all();
+    for (final Value v : values) {
+    	if (!(v instanceof FcnRcdValue)) {
+    		Assert.fail("The symmetry values must be function records.");
+    	}
+    }
+    final ExprOrOpArgNode[] argNodes = ((OpApplNode)opDef.getBody()).getArgs();
+    // In the case where the config defines more than one set which is symmetric, they will pass through the
+    //		enumerable size() check even if they are single element sets
+    final StringBuilder cardinalityOneSetList = new StringBuilder();
+    int offenderCount = 0;
+    if (argNodes.length >= values.size()) {
+    	// If equal, we have as many values as we have permuted sets => we have all 1-element sets;
+    	//		if greater than, then we have a heterogenous cardinality of sets, including 0 element sets.
+    	for (final ExprOrOpArgNode node : argNodes) {
+			addToSubTwoSizedSymmetrySetList(node, cardinalityOneSetList);
+			offenderCount++;
+    	}
+    }
+    
+    final IMVPerm[] subgroup;
+    if (offenderCount == 0) {
+        subgroup = MVPerms.permutationSubgroup((Enumerable)fcns);
+        final HashSet<ModelValue> subgroupMembers = new HashSet<>();
+        for (final IMVPerm imvp : subgroup) {
+        	if (imvp instanceof MVPerm) { // should always be the case
+        		subgroupMembers.addAll(((MVPerm)imvp).getAllModelValues());
+        	}
+        }
+        for (final ExprOrOpArgNode node : argNodes) {
+        	final SetEnumValue enumValue = getSetEnumValueFromArgumentNode(node);
+        	
+        	if (enumValue != null) {
+        		final ValueEnumeration ve = enumValue.elements();
+        		
+        		boolean found = false;
+        		Value v;
+        		while ((v = ve.nextElement()) != null) {
+        			if ((v instanceof ModelValue) && subgroupMembers.contains(v)) {
+        				found = true;
+        				break;
+        			}
+        		}
+        		
+        		if (!found) {
+    				addToSubTwoSizedSymmetrySetList(node, cardinalityOneSetList);
+    				offenderCount++;
+        		}
+        	}
+        }
+    } else {
+    	subgroup = null;
+    }
+    
+    if (offenderCount > 0) {
+      final String plurality = (offenderCount > 1) ? "s" : "";
+      final String antiPlurality = (offenderCount > 1) ? "" : "s";
+      final String toHaveConjugation = (offenderCount > 1) ? "have" : "has";
+      
+      MP.printWarning(EC.TLC_SYMMETRY_SET_TOO_SMALL,
+    		  	  	  new String[] { plurality, cardinalityOneSetList.toString(), toHaveConjugation, antiPlurality });
+    }
+    
+    return subgroup;
+  }
+  
+  /**
+   * Teases the original spec name for the set out of node and appends it to the {@code StringBuilder} instance.
+   */
+  private void addToSubTwoSizedSymmetrySetList(final ExprOrOpArgNode node, final StringBuilder cardinalityOneSetList) {
+		final SyntaxTreeNode tn = (SyntaxTreeNode)node.getTreeNode();
+		final String image = tn.getHumanReadableImage();
+		final String alias;
+	    if (image.startsWith(TLAConstants.BuiltInOperators.PERMUTATIONS)) {
+		  final int imageLength = image.length();
+		  alias = image.substring((TLAConstants.BuiltInOperators.PERMUTATIONS.length() + 1),
+				  						  (imageLength - 1));
+	    } else {
+	    	alias = image;
+	    }
+		final String specDefinitionName = this.config.getOverridenSpecNameForConfigName(alias);
+		final String displayDefinition = (specDefinitionName != null) ? specDefinitionName : alias;
+		
+		if (cardinalityOneSetList.length() > 0) {
+			cardinalityOneSetList.append(", and ");
+		}
+
+		cardinalityOneSetList.append(displayDefinition);
+  }
+  
+  /**
+   * @param node
+   * @return if the node represents a permutation, this will return the {@link SetEnumValue} instance contains its
+   * 					model values
+   */
+  private SetEnumValue getSetEnumValueFromArgumentNode(final ExprOrOpArgNode node) {
+	  if (node instanceof OpApplNode) {
+		  final OpApplNode permutationNode = (OpApplNode)node;
+		  if (permutationNode.getOperator() instanceof OpDefNode) {
+			  final OpDefNode operator = (OpDefNode)permutationNode.getOperator();
+			  if (TLAConstants.BuiltInOperators.PERMUTATIONS.equals(operator.getName().toString())) {
+				  final ExprOrOpArgNode[] operands = permutationNode.getArgs();
+				  if ((operands.length == 1)
+						  && (operands[0] instanceof OpApplNode)
+						  && (((OpApplNode)operands[0]).getOperator() instanceof OpDefOrDeclNode)) {
+					  final Object o = ((OpDefOrDeclNode)((OpApplNode)operands[0]).getOperator()).getToolObject(toolId);
+					  
+					  if (o instanceof SetEnumValue) {
+						  return (SetEnumValue)o;
+					  } else if (o instanceof WorkerValue) {
+						  // If TLC was started with a -workers N specification, N > 1, o will be a WorkerValue instance
+						  final WorkerValue wv = (WorkerValue)o;
+						  final Object unwrapped = WorkerValue.mux(wv);
+						  
+						  if (unwrapped instanceof SetEnumValue) {
+							  return (SetEnumValue)unwrapped;
+						  }
+					  }
+				  }
+			  }
+		  }
+	  }
+
+	  return null;
   }
 
   @Override
@@ -3486,4 +3475,23 @@ public final StateVec getNextStates(Action action, TLCState state) {
     }
     return new ContextEnumerator(vars, enums, c);
   }
+
+    // These three are expected by implementing the {@link ITool} interface; they used
+    //		to mirror exactly methods that our parent class ({@link Spec}) implemented
+    //		however those methods have changed signature with refactoring done for 
+    //		Issue #393
+	@Override
+	public Context getOpContext(OpDefNode odn, ExprOrOpArgNode[] args, Context ctx, boolean b) {
+		return getOpContext(odn, args, ctx, b, toolId);
+	}
+	
+	@Override
+	public Object lookup(SymbolNode opNode, Context con, boolean b) {
+		return lookup(opNode, con, b, toolId);
+	}
+	
+	@Override
+	public Object getVal(ExprOrOpArgNode expr, Context con, boolean b) {
+		return getVal(expr, con, b, toolId);
+	}
 }
diff --git a/tlatools/src/tlc2/tool/impl/WorkerValue.java b/tlatools/src/tlc2/tool/impl/WorkerValue.java
new file mode 100644
index 0000000000000000000000000000000000000000..7fbe4f7874e8f8fed4864f4aa8d8ea81c63568d3
--- /dev/null
+++ b/tlatools/src/tlc2/tool/impl/WorkerValue.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool.impl;
+
+import tla2sany.semantic.OpDefNode;
+import tla2sany.semantic.SemanticNode;
+import tlc2.TLCGlobals;
+import tlc2.tool.IWorker;
+import tlc2.tool.TLCState;
+import tlc2.tool.coverage.CostModel;
+import tlc2.util.Context;
+import tlc2.value.IValue;
+
+/*
+Root Cause:
+---------
+
+1) [Values](https://github.com/tlaplus/tlaplus/blob/master/tlatools/src/tlc2/value/impl/Value.java) can be (deeply) nested.
+
+1) Values transition through the following sequence of states:  New (instantiated), normalized, and fingerprinted.  Transitioning from one state to another is not thread-safe.  Non-technical speaking, a value is both the symbolic and the explicit entity.
+
+2) Normalization of an (enumerable) value causes its elements to be sorted and duplicates to be removed.  It does not cause new elements to be  generated/enumerated. For example, normalizing the [SetPredValue](https://github.com/tlaplus/tlaplus/blob/master/tlatools/src/tlc2/value/impl/SetPredValue.java), corresponding to the expression ```tla { s \in SUBSET S : s # {} }```, causes ```S``` to be sorted and any duplicate elements to be removed.
+
+3) Fingerprinting an enumerable value causes its elements to be explicitly enumerated.  For example, the SetPredValue from before causes all subsets ```s``` to be enumerated.
+
+4) At startup, TLC eagerly evaluates zero-arity constant definitions and operators which involves creating values.  These values are normalized but not fingerprinted!  For example, the operator ```NonEmptySubsS == { s \in SUBSET S : s # {} }``` will be evaluated to a SetPredValue that is stored in the ```NonEmptySubsS``` node of the semantic graph.  We denote the set of values in the semantic graph with V<sub>SG</sub>.
+
+5) Generating a [TLCState](https://github.com/tlaplus/tlaplus/blob/master/tlatools/src/tlc2/tool/TLCTrace.java) during the evaluation of the next-state relation, assigns newly created values to variables.  Before a TLCState is enqueued in the [StateQueue](https://github.com/tlaplus/tlaplus/blob/master/tlatools/src/tlc2/tool/queue/StateQueue.java), its values are fingerprinted.  Thus, values of TLCStates can safely be shared across [Workers](https://github.com/tlaplus/tlaplus/blob/master/tlatools/src/tlc2/tool/Worker.java).
+
+Lets assume a spec with one variable ```x``` whose value - in all states - is some set.  Furthermore, let ```P``` be the property ```[](x \in NonEmptySubsS)```.  For simplicity reasons,  we assume:
+
+1)  ```P``` is not checked on the initial states
+2) Two Workers check next states simultaneously
+
+Under these two assumptions, both Workers will race to enumerate (fingerprint) ```NonEmptySubsS```.
+
+Note that the fact that we had to assume 1) and 2) explains why this race condition didn't surfaced earlier.  However, the assumptions are true in real-world executions of TLC.  For example, the evaluation of a more complex NonEmptySubsS, with a deeply nested hierarchy of values, may not require the evaluation of nested values in the initial states.
+
+---------------
+
+@xxyzzn came up with another scenario that might lead to the calculation of bogus fingerprints:
+
+```tla
+EXTENDS Integers, Sequences
+VARIABLE x, y
+
+Foo == { s \in SUBSET {1,2,3,4} : s # {} }
+
+Init == x = << >> /\ y \in 1..2
+
+Next == x' \in {<<i, Foo>> : i \in 1..2} /\ UNCHANGED y
+```
+
+Variable ```y``` only exists so that the state-graph has two initial states (sequentially generated).  A single initial state would restrict the first evaluation of Next to a single Worker (only a single initial state to dequeue from the ```StateQueue```) and thus fingerprinting cannot occur concurrently.
+
+Attempted Fix A:
+---------------------
+
+[At startup](https://github.com/tlaplus/tlaplus/blob/63bab42e79e750b7ac033cfe7196d8f0b53e861e/tlatools/src/tlc2/tool/impl/SpecProcessor.java#L202-L281), (eagerly) fingerprint all values of V<sub>SG</sub>.
+
+Problem: Not all values in V<sub>SG</sub> need not be fingerprinted to completely check a spec.  For some specs such as [CarTalkPuzzle](https://github.com/tlaplus/tlaplus/issues/361#issuecomment-543256201), this is even prohibitive because explicit enumeration is infeasible: TLC will hang at startup.
+
+Deferring fingerprinting of V<sub>SG</sub> until after the assumptions have been checked, such as when the initial states are (atomically) generated, is no general solution.
+
+Proposed Fix A:
+--------------------
+
+Properly synchronize values such that no race conditions are possible if two or more Workers enumerate them concurrently.  
+
+Disadvantages:  
+1) It creates a scalability bottleneck: Workers will content for the synchronized ```NonEmptySubs```on every state that is generated.
+2) Engineering effort to correctly synchronize the Value type hierarchy without introducing dead-locks.
+
+Proposed Fix B:
+--------------------
+
+For each worker, create a copy of V<sub>SG</sub> (technically borrows from the concept of  a ```ThreadLocal```).
+
+Disadvantages:  
+1) Requires a type check (and potentially cast) on every [lookup](https://github.com/tlaplus/tlaplus/blob/63bab42e79e750b7ac033cfe7196d8f0b53e861e/tlatools/src/tlc2/tool/impl/Spec.java#L448-L497) that occurrs during the [evaluation of the next-state relation](https://github.com/tlaplus/tlaplus/blob/63bab42e79e750b7ac033cfe7196d8f0b53e861e/tlatools/src/tlc2/tool/impl/Tool.java#L782-L814).  An optimization would be to [eventually](https://github.com/tlaplus/tlaplus/blob/63bab42e79e750b7ac033cfe7196d8f0b53e861e/tlatools/src/tlc2/tool/AbstractChecker.java#L496) garbage-collect the copies of V<sub>SG</sub> to at least skip the type cast once one copy is completely fingerprinted.
+2) [Value#deepCopy](https://github.com/tlaplus/tlaplus/blob/63bab42e79e750b7ac033cfe7196d8f0b53e861e/tlatools/src/tlc2/value/IValue.java#L104)  - required to create the copies of V<sub>SG</sub> - is [broken for most value types](https://github.com/tlaplus/tlaplus/blob/63bab42e79e750b7ac033cfe7196d8f0b53e861e/tlatools/src/tlc2/value/impl/SubsetValue.java#L232) (can probably be fixed).
+*/
+public class WorkerValue {
+	
+	/*
+	 * Demuxing is supposed to be called only once per sn/opDef whereas muxing is called many many times.
+	 */
+	
+    public static Object demux(final OpDefEvaluator spec, final OpDefNode opDef) {
+    	return demux(spec, opDef, opDef);
+    }
+    
+    public static Object demux(final OpDefEvaluator spec, final SemanticNode sn, final OpDefNode opDef) {
+    	final IValue defVal = spec.eval(opDef.getBody(), Context.Empty, TLCState.Empty, CostModel.DO_NOT_RECORD);
+    	defVal.deepNormalize();
+    	
+    	if (defVal.mutates() && TLCGlobals.getNumWorkers() > 1) {
+    		final IValue[] values = new IValue[TLCGlobals.getNumWorkers()];
+    		values[0] = defVal;
+
+    		for (int i = 1; i < values.length; i++) {
+    			// Ideally, we could invoke IValue#deepCopy here instead of evaluating opDef again.  However,
+    			// IValue#deepCopy doesn't create copies for most values.
+    			values[i] = spec.eval(opDef.getBody(), Context.Empty, TLCState.Empty, CostModel.DO_NOT_RECORD);
+    			values[i].deepNormalize();
+    		}
+    		
+    		return new WorkerValue(values);
+    	} else {
+    		return defVal;
+    	}
+    }
+    
+	public static Object mux(final Object result) {
+		if (!(result instanceof WorkerValue)) {
+			return result;
+		}
+		
+		final WorkerValue vp = (WorkerValue) result;
+		final Thread t = Thread.currentThread();
+		if (t instanceof IWorker) {
+			final IWorker w = (IWorker) t;
+			return vp.values[w.myGetId()];
+		} else {
+			return vp.values[0];
+		}
+	}
+	
+	private final IValue[] values;
+
+	private WorkerValue(IValue[] values) {
+		this.values = values;
+	}
+}
diff --git a/tlatools/src/tlc2/tool/liveness/LiveCheck.java b/tlatools/src/tlc2/tool/liveness/LiveCheck.java
index a6387a7340509da3908d6cd8ef8ad65a1ec00a34..f253e135f1c81f10e042d0f2165b50f1341b843a 100644
--- a/tlatools/src/tlc2/tool/liveness/LiveCheck.java
+++ b/tlatools/src/tlc2/tool/liveness/LiveCheck.java
@@ -9,28 +9,30 @@ import java.util.Arrays;
 import java.util.Enumeration;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CompletionService;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
 
 import tlc2.TLC;
 import tlc2.TLCGlobals;
 import tlc2.output.EC;
 import tlc2.output.MP;
 import tlc2.tool.Action;
-import tlc2.tool.IStateFunctor;
 import tlc2.tool.ITool;
 import tlc2.tool.ModelChecker;
 import tlc2.tool.StateVec;
 import tlc2.tool.TLCState;
-import tlc2.tool.impl.Tool;
 import tlc2.util.BitVector;
-import tlc2.util.FP64;
 import tlc2.util.IStateWriter;
 import tlc2.util.IStateWriter.Visualization;
 import tlc2.util.NoopStateWriter;
 import tlc2.util.SetOfStates;
-import tlc2.util.statistics.DummyBucketStatistics;
 import tlc2.util.statistics.IBucketStatistics;
 import util.Assert;
-import util.SimpleFilenameToStream;
 
 public class LiveCheck implements ILiveCheck {
 
@@ -215,26 +217,57 @@ public class LiveCheck implements ILiveCheck {
 		final BlockingQueue<ILiveChecker> queue = new ArrayBlockingQueue<ILiveChecker>(checker.length);
 		queue.addAll(Arrays.asList(checker));
 
-		int slen = checker.length;
-		int wNum = Math.min(slen, TLCGlobals.getNumWorkers());
-
-		if (wNum == 1) {
-			LiveWorker worker = new LiveWorker(tool, 0, 1, this, queue, finalCheck);
-			worker.run();
-		} else {
-			final LiveWorker[] workers = new LiveWorker[wNum];
-			for (int i = 0; i < wNum; i++) {
-				workers[i] = new LiveWorker(tool, i, wNum, this, queue, finalCheck);
-				workers[i].start();
-			}
-			for (int i = 0; i < wNum; i++) {
-				workers[i].join();
+		
+		/*
+		 * A LiveWorker below can either complete a unit of work a) without finding a
+		 * liveness violation, b) finds a violation, or c) fails to check because of an
+		 * exception/error (such as going out of memory). In case an LW fails to check,
+		 * we still wait for all other LWs to complete. A subset of the LWs might have
+		 * found a violation. In other words, the OOM of an LW has lower precedence than
+		 * a violation found by another LW. However, if any LW fails to check, we terminate
+		 * model checking after all LWs completed.
+		 */
+		final int wNum = TLCGlobals.doSequentialLiveness() ? 1 : Math.min(checker.length, TLCGlobals.getNumWorkers());
+		final ExecutorService pool = Executors.newFixedThreadPool(wNum);
+		// CS is really just a container around the set of Futures returned by the pool. It saves us from
+		// creating a low-level array.
+		final CompletionService<Boolean> completionService = new ExecutorCompletionService<Boolean>(pool);
+
+		for (int i = 0; i < wNum; i++) {
+			completionService.submit(new LiveWorker(tool, i, wNum, this, queue, finalCheck));
+		}
+		// Wait for all LWs to complete.
+		pool.shutdown();
+		pool.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); // wait forever
+
+		// Check if any one of the LWs found a violation (ignore failures for now).
+		ExecutionException ee = null;
+		for (int i = 0; i < wNum; i++) {
+			try {
+				final Future<Boolean> future = completionService.take();
+				if (future.get()) {
+					MP.printMessage(EC.TLC_CHECKING_TEMPORAL_PROPS_END,
+							TLC.convertRuntimeToHumanReadable(System.currentTimeMillis() - startTime));
+					return EC.TLC_TEMPORAL_PROPERTY_VIOLATED;
+				}
+			} catch (final ExecutionException e) {
+				// handled below!
+				ee = e;
 			}
 		}
-
-		if (LiveWorker.hasErrFound()) {
-			MP.printMessage(EC.TLC_CHECKING_TEMPORAL_PROPS_END, TLC.convertRuntimeToHumanReadable(System.currentTimeMillis() - startTime));
-			return EC.TLC_TEMPORAL_PROPERTY_VIOLATED;
+		// Terminate if any one of the LWs failed c)
+		if (ee != null) {
+			final Throwable cause = ee.getCause();
+			if (cause instanceof OutOfMemoryError) {
+				MP.printError(EC.SYSTEM_OUT_OF_MEMORY_LIVENESS, cause);
+			} else if (cause instanceof StackOverflowError) {
+				MP.printError(EC.SYSTEM_STACK_OVERFLOW, cause);
+			} else if (cause != null) {
+				MP.printError(EC.GENERAL, cause);
+			} else {
+				MP.printError(EC.GENERAL, ee);
+			}
+			System.exit(1);
 		}
 		
 		// Reset after checking unless it's the final check:
@@ -744,59 +777,4 @@ public class LiveCheck implements ILiveCheck {
 			return dgraph;
 		}
 	}
-	
-	// Intended to be used in unit tests only!!! This is not part of the API!!!
-	static class TestHelper {
-		
-		/*
-		 * - EWD840 (with tableau) spec with N = 11 and maxSetSize = 9.000.000 => 12GB nodes file, 46.141.438 distinct states
-		 * - EWD840 (with tableau) spec with N = 12 and maxSetSize = 9.000.000 => 56GB, 201.334.782 dist. states 
-		 */
-		
-		// The Eclipse Launch configuration has to set the working directory
-		// (Arguments tab) to the parent directory of the folder containing the
-		// nodes_* and ptrs_* files. The parent folder has to contain the spec
-		// and config file both named "MC".
-		// metadir is the the name of the folder with the nodes_* and ptrs_*
-		// relative to the parent directory. The directory does *not* need to contain the
-		// backing file of the fingerprint set or the state queue files.
-		public static ILiveCheck recreateFromDisk(final String path) throws Exception {
-			// Don't know with which Polynomial the FP64 has been initialized, but
-			// the default is 0.
-			FP64.Init(0);
-			
-			// Most models won't need this, but let's increase this anyway.
-			TLCGlobals.setBound = 9000000;
-
-			// Re-create the tool to do the init states down below (LiveCheck#init
-			// doesn't really need tool).
-	        final ITool tool = new Tool("", "MC", "MC", new SimpleFilenameToStream());
-	        
-			// Initialize tool's actions explicitly. LiveCheck#printTrace is
-			// going to access the actions and fails with a NPE unless
-			// initialized.
-	        tool.getActions();
-	        
-			final ILiveCheck liveCheck = new LiveCheck(tool, null, path, new DummyBucketStatistics());
-			
-			// Calling recover requires a .chkpt file to be able to re-create the
-			// internal data structures to continue with model checking. However, we
-			// only want to execute liveness checks on the current static disk
-			// graph. Thus, we don't need the .chkpt file.
-			//recover();
-			
-			// After recovery, one has to redo the init states
-			tool.getInitStates(new IStateFunctor() {
-				/* (non-Javadoc)
-				 * @see tlc2.tool.IStateFunctor#addElement(tlc2.tool.TLCState)
-				 */
-				public Object addElement(TLCState state) {
-					liveCheck.addInitState(tool, state, state.fingerPrint());
-					return true;
-				}
-			});
-			
-			return liveCheck; 
-		}
-	}
 }
diff --git a/tlatools/src/tlc2/tool/liveness/LiveWorker.java b/tlatools/src/tlc2/tool/liveness/LiveWorker.java
index 1bd8d4c6b871c3a2b4b99c643e8e3d8d98a743a0..21f23c196f76b94ad51f4a501f4cdc6aacb59a37 100644
--- a/tlatools/src/tlc2/tool/liveness/LiveWorker.java
+++ b/tlatools/src/tlc2/tool/liveness/LiveWorker.java
@@ -21,7 +21,6 @@ import tlc2.output.StatePrinter;
 import tlc2.tool.EvalException;
 import tlc2.tool.ITool;
 import tlc2.tool.TLCStateInfo;
-import tlc2.util.IdThread;
 import tlc2.util.IntStack;
 import tlc2.util.LongVec;
 import tlc2.util.MemIntQueue;
@@ -39,7 +38,7 @@ import tlc2.util.statistics.IBucketStatistics;
  * <li>In case of a violation, reconstructs and prints the error trace.</li>
  * </ul>
  */
-public class LiveWorker extends IdThread {
+public class LiveWorker implements Callable<Boolean> {
 
 	/**
 	 * A marker that is pushed onto the dfsStack during SCC depth-first-search
@@ -68,27 +67,33 @@ public class LiveWorker extends IdThread {
 
 	private final ITool tool;
 
+	private final int id;
+
 	public LiveWorker(final ITool tool, int id, int numWorkers, final ILiveCheck liveCheck, final BlockingQueue<ILiveChecker> queue, final boolean finalCheck) {
-		super(id);
+		this.id = id;
 		this.tool = tool;
 		this.numWorkers = numWorkers;
 		this.liveCheck = liveCheck;
 		this.queue = queue;
 		this.isFinalCheck = finalCheck;
-		
-		// Set the name to something more indicative than "Thread-4711".
-		this.setName("TLCLiveWorkerThread-" + String.format("%03d", id));
 	}
 
 	/**
 	 * Returns true iff an error has already been found.
 	 */
-	public static boolean hasErrFound() {
+	private static boolean hasErrFound() {
 		synchronized (workerLock) {
 			return (errFoundByThread != -1);
 		}
 	}
 
+	// True iff this LiveWorker found a liveness violation.zs
+	private static boolean hasErrFound(final int id) {
+		synchronized (workerLock) {
+			return (errFoundByThread == id);
+		}
+	}
+
 	/**
 	 * Returns true iff either an error has not been found or the error is found
 	 * by this thread.
@@ -99,9 +104,9 @@ public class LiveWorker extends IdThread {
 	private/* static synchronized */boolean setErrFound() {
 		synchronized (workerLock) {
 			if (errFoundByThread == -1) {
-				errFoundByThread = this.myGetId(); // GetId();
+				errFoundByThread = this.id; // GetId();
 				return true;
-			} else if (errFoundByThread == this.myGetId()) { // (* GetId()) {
+			} else if (errFoundByThread == this.id) { // (* GetId()) {
 				return true;
 			}
 			return false;
@@ -197,18 +202,28 @@ public class LiveWorker extends IdThread {
 		final int slen = this.oos.getCheckState().length;
 		final int alen = this.oos.getCheckAction().length;
 		
-		// Tarjan's stack
-		// Append thread id to name for unique disk files during concurrent SCC search 
-		final IntStack dfsStack = getStack(liveCheck.getMetaDir(), "dfs" + this.myGetId());
 		
-		// comStack is only being added to during the deep first search. It is passed
-		// to the checkComponent method while in DFS though. Note that the nodes pushed
-		// onto comStack don't necessarily form a strongly connected component (see
-		// comment above this.checkComponent(...) below for more details).
-		//
-		// See tlc2.tool.liveness.LiveWorker.DetailedFormatter.toString(MemIntStack)
-		// which is useful during debugging.
-		final IntStack comStack = getStack(liveCheck.getMetaDir(), "com" + this.myGetId());
+		// Synchronize all LiveWorker instances to consistently read free
+		// memory. This method is only called during initialization of SCC
+		// search, thus synchronization should not cause significant thread
+		// contention. We want a single LW to successfully allocate both
+		// dfsStack *and* comStack.
+		final IntStack dfsStack;
+		final IntStack comStack;
+		synchronized (LiveWorker.class) {
+			// Tarjan's stack
+			// Append thread id to name for unique disk files during concurrent SCC search
+			dfsStack = getStack(liveCheck.getMetaDir(), "dfs" + this.id);
+			
+			// comStack is only being added to during the deep first search. It is passed
+			// to the checkComponent method while in DFS though. Note that the nodes pushed
+			// onto comStack don't necessarily form a strongly connected component (see
+			// comment above this.checkComponent(...) below for more details).
+			//
+			// See tlc2.tool.liveness.LiveWorker.DetailedFormatter.toString(MemIntStack)
+			// which is useful during debugging.
+			comStack = getStack(liveCheck.getMetaDir(), "com" + this.id);
+		}
 
 		// Generate the SCCs and check if they contain a "bad" cycle.
 		while (nodeQueue.size() > 0) {
@@ -457,16 +472,12 @@ public class LiveWorker extends IdThread {
 	}
 
 	private IntStack getStack(final String metaDir, final String name) throws IOException {
-		// Synchronize all LiveWorker instances to consistently read free
-		// memory. This method is only called during initialization of SCC
-		// search, thus synchronization should not cause significant thread
-		// contention.
-		synchronized (LiveWorker.class) {
-			// It is unlikely that the stacks will fit into memory if the
-			// size of the behavior graph is larger relative to the available
-			// memory. Also take the total number of simultaneously running
-			// workers into account that have to share the available memory
-			// among each other.
+		// It is unlikely that the stacks will fit into memory if the
+		// size of the behavior graph is larger relative to the available
+		// memory. Also take the total number of simultaneously running
+		// workers into account that have to share the available memory
+		// among each other.
+		try {
 			final double freeMemoryInBytes = (Runtime.getRuntime().freeMemory() / (numWorkers * 1d));
 			final long graphSizeInBytes = this.dg.getSizeOnDisk();
 			final double ratio = graphSizeInBytes / freeMemoryInBytes;
@@ -485,6 +496,17 @@ public class LiveWorker extends IdThread {
 			// If the disk graph as a whole fits into memory, do not use a
 			// disk-backed SynchronousDiskIntStack.
 			return new MemIntStack(metaDir, name);
+		} catch (final OutOfMemoryError oom) {
+			System.gc();
+			// If the allocation above failed, be more conservative. If it fails to
+			// allocate even 16mb, TLC will subsequently terminate with a message about insufficient
+			// memory. 
+			final SynchronousDiskIntStack sdis = new SynchronousDiskIntStack(metaDir, name,
+					SynchronousDiskIntStack.BufSize / 2);
+			MP.printWarning(EC.GENERAL,
+					"Liveness checking will be extremely slow because TLC is running low on memory.\n"
+							+ "Try allocating more memory to the Java pool (heap) in future TLC runs.");
+			return sdis;
 		}
 	}
 
@@ -1212,49 +1234,39 @@ public class LiveWorker extends IdThread {
 		return curNode;
 	}
 
-	/* (non-Javadoc)
-	 * @see java.lang.Thread#run()
-	 */
-	public final void run() {
-		try {
-			while (true) {
-				// Use poll() to get the next checker from the queue or null if
-				// there is none. Do *not* block when there are no more checkers
-				// available. Nobody is going to add new checkers to the queue.
-				final ILiveChecker checker = queue.poll();
-				if (checker == null || hasErrFound()) {
-					// Another thread has either found an error (violation of a
-					// liveness property) OR there is no more work (checker) to
-					// be done.
-					break;
-				}
+	public final Boolean call() throws IOException, InterruptedException, ExecutionException {
+		while (true) {
+			// Use poll() to get the next checker from the queue or null if
+			// there is none. Do *not* block when there are no more checkers
+			// available. Nobody is going to add new checkers to the queue.
+			final ILiveChecker checker = queue.poll();
+			if (checker == null || hasErrFound()) {
+				// Another thread has either found an error (violation of a
+				// liveness property) OR there is no more work (checker) to
+				// be done.
+				break;
+			}
 
-				this.oos = checker.getSolution();
-				this.dg = checker.getDiskGraph();
-				this.dg.createCache();
-				PossibleErrorModel[] pems = this.oos.getPems();
-				for (int i = 0; i < pems.length; i++) {
-					if (!hasErrFound()) {
-						this.pem = pems[i];
-						this.checkSccs(tool);
-					}
+			this.oos = checker.getSolution();
+			this.dg = checker.getDiskGraph();
+			this.dg.createCache();
+			PossibleErrorModel[] pems = this.oos.getPems();
+			for (int i = 0; i < pems.length; i++) {
+				if (!hasErrFound()) {
+					this.pem = pems[i];
+					this.checkSccs(tool);
 				}
-				this.dg.destroyCache();
-				// Record the size of the disk graph at the time its checked. This
-				// information is later used to decide if it it makes sense to
-				// run the next check on the larger but still *partial* graph.
-				this.dg.recordSize();
-				// If assertions are on (e.g. during unit testing) make sure
-				// that the disk graph's invariants hold.
-				assert this.dg.checkInvariants(oos.getCheckState().length, oos.getCheckAction().length);
 			}
-		} catch (Exception e) {
-			MP.printError(EC.GENERAL, "checking liveness", e); // LL changed
-			// call 7 April
-			// 2012
-			// Assert.printStack(e);
-			return;
+			this.dg.destroyCache();
+			// Record the size of the disk graph at the time its checked. This
+			// information is later used to decide if it it makes sense to
+			// run the next check on the larger but still *partial* graph.
+			this.dg.recordSize();
+			// If assertions are on (e.g. during unit testing) make sure
+			// that the disk graph's invariants hold.
+			assert this.dg.checkInvariants(oos.getCheckState().length, oos.getCheckAction().length);
 		}
+		return hasErrFound(this.id);
 	}
 
 	public String toDotViz(final long state, final int tidx, TableauNodePtrTable tnpt) throws IOException {
diff --git a/tlatools/src/tlc2/tool/liveness/NodePtrTable.java b/tlatools/src/tlc2/tool/liveness/NodePtrTable.java
index 09f2222abc69beeabcac5ece093efd6615f81f01..e5a6a1d9368692c613b4b320b00586e62647ac30 100644
--- a/tlatools/src/tlc2/tool/liveness/NodePtrTable.java
+++ b/tlatools/src/tlc2/tool/liveness/NodePtrTable.java
@@ -111,13 +111,12 @@ public class NodePtrTable {
 
 	/* Double the table when the table is full by the threshhold. */
 	private final void grow() {
-		// TODO This grows unbound up to an OOM exception or fails to increase
-		// the array when length reaches Integer.MAX_VALUE.
-		// In case of Integer.MAX_VALUE, all subsequent put(long,long)
-		// invocations will fail to put the new key causing TLC to live-lock.
-		// This can possibly be replaced with a variant of DiskFPSet.
+		final int newLength = 2 * this.length + 1;
+		grow(newLength);
+	}
+
+    private final void grow(final int newLength) {
 		try {
-			final int newLength = 2 * this.length + 1;
 			final long[] oldKeys = this.keys;
 			final long[] oldElems = this.elems;
 			this.keys = new long[newLength];
@@ -147,9 +146,22 @@ public class NodePtrTable {
 			}
 			this.length = newLength;
 			this.thresh = (int) (newLength * 0.75);
-		} catch (Throwable t) {
+		} catch (OutOfMemoryError t) {
+			// Handle OOM error locally because grow is on the code path of safety checking
+			// (LiveCheck#addInit/addNext...).
 			System.gc();
-			MP.printError(EC.SYSTEM_OUT_OF_MEMORY, t);
+			if (newLength <= this.length + 1) {
+				MP.printError(EC.SYSTEM_OUT_OF_MEMORY, t);
+				System.exit(1);
+			}
+			try {
+				// It doesn't buy us much, but - as fallback - do not grow capacity
+				// exponentially.
+				grow(newLength - (newLength >> 2));
+			} catch (OutOfMemoryError inner) {
+				MP.printError(EC.SYSTEM_OUT_OF_MEMORY, inner);
+				System.exit(1);
+			}
 		}
 	}
 
diff --git a/tlatools/src/tlc2/tool/liveness/NoopLivenessStateWriter.java b/tlatools/src/tlc2/tool/liveness/NoopLivenessStateWriter.java
index 2555ca56a7936665e8f38e9b51fd3dfd10a7832a..5ad36cd603101b81cc7b00c3e7ee6e000e0de018 100644
--- a/tlatools/src/tlc2/tool/liveness/NoopLivenessStateWriter.java
+++ b/tlatools/src/tlc2/tool/liveness/NoopLivenessStateWriter.java
@@ -25,6 +25,8 @@
  ******************************************************************************/
 package tlc2.tool.liveness;
 
+import java.io.IOException;
+
 import tlc2.tool.Action;
 import tlc2.tool.TLCState;
 import tlc2.util.BitVector;
@@ -125,4 +127,11 @@ public class NoopLivenessStateWriter implements ILivenessStateWriter {
 	public boolean isDot() {
 		return false;
 	}
+
+	/* (non-Javadoc)
+	 * @see tlc2.util.IStateWriter#snapshot()
+	 */
+	@Override
+	public void snapshot() throws IOException {
+	}
 }
diff --git a/tlatools/src/tlc2/tool/liveness/TBGraph.java b/tlatools/src/tlc2/tool/liveness/TBGraph.java
index 1f7e16b30b3ebc2ea56e1c11e03a4c9bc93ed443..ecd714ec7fe1744af1ea26ff3aaf1a4837bd6ec4 100644
--- a/tlatools/src/tlc2/tool/liveness/TBGraph.java
+++ b/tlatools/src/tlc2/tool/liveness/TBGraph.java
@@ -83,6 +83,10 @@ public class TBGraph extends Vect<TBGraphNode> {
 	public int getInitCnt() {
 		return this.initCnt;
 	}
+	
+	private boolean isInitNode(TBGraphNode aNode) {
+		return aNode.getIndex() < getInitCnt();
+	}
 
 	public final void toString(StringBuffer sb, String padding) {
 		for (int i = 0; i < this.size(); i++) {
@@ -113,7 +117,8 @@ public class TBGraph extends Vect<TBGraphNode> {
 		sb.append("nodesep = 0.7\n");
 		sb.append("rankdir=LR;\n"); // Left to right rather than top to bottom
 		for(int i = 0; i < size(); i++) {
-			sb.append(getNode(i).toDotViz());
+			final TBGraphNode node = getNode(i);
+			sb.append(node.toDotViz(isInitNode(node)));
 		}
 		sb.append("}");
 		return sb.toString();
diff --git a/tlatools/src/tlc2/tool/liveness/TBGraphNode.java b/tlatools/src/tlc2/tool/liveness/TBGraphNode.java
index c2265aa6678c29d652cb15c7e71437e66eae46f6..d3177d8fb3cd5bb16fd728db6f897850d7d1b099 100644
--- a/tlatools/src/tlc2/tool/liveness/TBGraphNode.java
+++ b/tlatools/src/tlc2/tool/liveness/TBGraphNode.java
@@ -122,11 +122,14 @@ public class TBGraphNode {
 	/**
 	 * @see TBGraph#toDotViz()
 	 */
-	public String toDotViz() {
+	public String toDotViz(final boolean isInitNode) {
 		final String label = "\"Id: " + this.index + "\n" + par.toDotViz() + "\"";
 		
 		final StringBuffer buf = new StringBuffer(nextSize());
 		buf.append(this.index + " [label=" + label + "]\n"); // nodes label
+		if (isInitNode) {
+			buf.append("[style = filled]\n");
+		}
 		for (int i = 0; i < nextSize(); i++) {
 			final TBGraphNode successor = nextAt(i);
 			buf.append(this.index + " -> " + successor.index);
diff --git a/tlatools/src/tlc2/util/DotStateWriter.java b/tlatools/src/tlc2/util/DotStateWriter.java
index 2db4c067e37fa0ee15e28b8c5526c2786af4b43a..8cb2ca08a3ae87941d0285aa04292035b7736074 100644
--- a/tlatools/src/tlc2/util/DotStateWriter.java
+++ b/tlatools/src/tlc2/util/DotStateWriter.java
@@ -27,6 +27,9 @@
 package tlc2.util;
 
 import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -34,6 +37,7 @@ import java.util.Set;
 
 import tlc2.tool.Action;
 import tlc2.tool.TLCState;
+import util.FileUtil;
 
 /**
  * Writes the given state in dot notation.
@@ -71,8 +75,11 @@ public class DotStateWriter extends StateWriter {
 	// by 1 every time a new color is assigned to an action.
 	private Integer colorGen = 1;
 	
+	// Create a valid fname_snapshot.dot file after a state is written.
+	private final boolean snapshot;
+	
 	public DotStateWriter(final String fname, final String strict) throws IOException {
-		this(fname, strict, false, false);
+		this(fname, strict, false, false, false);
 	}
 	
 	/**
@@ -85,14 +92,17 @@ public class DotStateWriter extends StateWriter {
 	 *            clutter for large graphs with many actions.
 	 * @throws IOException
 	 */
-	public DotStateWriter(final String fname, final boolean colorize, final boolean actionLabels) throws IOException {
-		this(fname, "strict ", colorize, actionLabels);
+	public DotStateWriter(final String fname, final boolean colorize, final boolean actionLabels,
+			final boolean snapshot) throws IOException {
+		this(fname, "strict ", colorize, actionLabels, snapshot);
 	}
 	
-	public DotStateWriter(final String fname, final String strict, final boolean colorize, final boolean actionLabels) throws IOException {
+	public DotStateWriter(final String fname, final String strict, final boolean colorize, final boolean actionLabels,
+			final boolean snapshot) throws IOException {
 		super(fname);
 		this.colorize = colorize;
 		this.actionLabels = actionLabels;
+		this.snapshot = snapshot;
 		this.writer.append(strict + "digraph DiskGraph {\n"); // strict removes redundant edges
 		// Turned off LR because top to bottom provides better results with GraphViz viewer.
 //		this.writer.append("rankdir=LR;\n"); // Left to right rather than top to bottom
@@ -130,6 +140,16 @@ public class DotStateWriter extends StateWriter {
 		this.writer.append("\n");
 		
 		maintainRanks(state);
+		
+		if (snapshot) {
+			try {
+				this.snapshot();
+			} catch (IOException e) {
+				// Let's assume this never happens!
+				e.printStackTrace();
+				throw new RuntimeException(e);
+			}
+		}
 	}
 	
 	protected void maintainRanks(final TLCState state) {
@@ -199,6 +219,16 @@ public class DotStateWriter extends StateWriter {
 		}
 		
 		maintainRanks(state);
+		
+		if (snapshot) {
+			try {
+				this.snapshot();
+			} catch (IOException e) {
+				// Let's assume this never happens!
+				e.printStackTrace();
+				throw new RuntimeException(e);
+			}
+		}
 	}
 	
 	/**
@@ -318,4 +348,33 @@ public class DotStateWriter extends StateWriter {
 		this.writer.append("}");
 		super.close();
 	}
+	
+	/* (non-Javadoc)
+	 * @see tlc2.util.IStateWriter#snapshot()
+	 */
+	@Override
+	public void snapshot() throws IOException {
+		this.writer.flush();
+		
+		final String snapshot = fname.replace(".dot", "_snapshot" + ".dot");
+		FileUtil.copyFile(this.fname, snapshot);
+
+		StringBuffer buf = new StringBuffer();
+		for (final Set<Long> entry : rankToNodes.values()) {
+			buf.append("{rank = same; ");
+			for (final Long l : entry) {
+				buf.append(l + ";");
+			}
+			buf.append("}\n");
+		}
+		buf.append("}\n");
+		// We only need the legend if the edges are colored by action and there is more
+		// than a single action.
+		if (colorize && this.actionToColors.size() > 1) {
+			buf.append(dotLegend("DotLegend", this.actionToColors.keySet()));
+		}
+		buf.append("}");
+
+	    Files.write(Paths.get(snapshot), buf.toString().getBytes(), StandardOpenOption.APPEND);
+	}
 }
diff --git a/tlatools/src/tlc2/util/ExpectInlined.java b/tlatools/src/tlc2/util/ExpectInlined.java
new file mode 100644
index 0000000000000000000000000000000000000000..535c8f2a0bad69cff9203b700e3e47319ce37c6a
--- /dev/null
+++ b/tlatools/src/tlc2/util/ExpectInlined.java
@@ -0,0 +1,13 @@
+package tlc2.util;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Retention(RUNTIME)
+@Target(METHOD)
+public @interface ExpectInlined {
+	
+}
\ No newline at end of file
diff --git a/tlatools/src/tlc2/util/FP64.java b/tlatools/src/tlc2/util/FP64.java
index 7660e0e7b227d472ee05c4917866405f59477943..b02408439640bd9fe8c4cdd81cf8755bac3cf6ba 100644
--- a/tlatools/src/tlc2/util/FP64.java
+++ b/tlatools/src/tlc2/util/FP64.java
@@ -128,7 +128,7 @@ public class FP64 {
      * Extend the fingerprint <code>fp</code> by an
      * integer <code>x</code>.
      */
-    public static long Extend(long fp, int x)
+    public static long ExtendLoop(long fp, int x)
     {
         long[] mod = ByteModTable_7;
 	for (int i = 0; i < 4; i++) {
@@ -139,6 +139,27 @@ public class FP64 {
 	return fp;
     }
 
+    public static long Extend(long fp, int x)
+    {
+      final long[] mod = ByteModTable_7;
+      byte b = (byte)(x & 0xFF);
+	  fp = ((fp >>> 8) ^ (mod[(b ^ ((int)fp)) & 0xFF]));
+  	  x = x >>> 8;
+
+	  b = (byte)(x & 0xFF);
+	  fp = ((fp >>> 8) ^ (mod[(b ^ ((int)fp)) & 0xFF]));
+	  x = x >>> 8;
+
+	  b = (byte)(x & 0xFF);
+	  fp = ((fp >>> 8) ^ (mod[(b ^ ((int)fp)) & 0xFF]));
+	  x = x >>> 8;
+
+	  b = (byte)(x & 0xFF);
+	  fp = ((fp >>> 8) ^ (mod[(b ^ ((int)fp)) & 0xFF]));
+	  
+	  return fp;
+    }
+
     /*
      * Extend the fingerprint <code>fp</code> by a long
      * integer <code>fp1</code>.
@@ -378,7 +399,7 @@ public class FP64 {
     /* This is the table used for computing fingerprints.  The
        ByteModTable could be hardwired.  Note that since we just
        extend a byte at a time, we need just "ByteModeTable[7]". */
-    private static long[] ByteModTable_7;
+    private static final long[] ByteModTable_7 = new long[256];
 
     /* This is the irreducible polynomial used as seed.  */
     private static long IrredPoly;
@@ -423,7 +444,6 @@ public class FP64 {
       }
 
       // Just need the 7th iteration of the ByteModTable initialization code
-      ByteModTable_7 = new long[256];
       for (int j = 0; j <= 255; j++) {
 	long v = Zero;
 	for (int k = 0; k <= 7; k++) {
diff --git a/tlatools/src/tlc2/util/IStateWriter.java b/tlatools/src/tlc2/util/IStateWriter.java
index 57997266e8eac25cee2be5d43ee074eae6ee1c13..b57111c3cb31b8591f1d8bd804ee56b9abb7d8e6 100644
--- a/tlatools/src/tlc2/util/IStateWriter.java
+++ b/tlatools/src/tlc2/util/IStateWriter.java
@@ -25,6 +25,8 @@
  ******************************************************************************/
 package tlc2.util;
 
+import java.io.IOException;
+
 import tlc2.tool.Action;
 import tlc2.tool.TLCState;
 
@@ -65,4 +67,6 @@ public interface IStateWriter {
 	boolean isNoop();
 	
 	boolean isDot();
+
+	void snapshot() throws IOException;
 }
\ No newline at end of file
diff --git a/tlatools/src/tlc2/util/NoopStateWriter.java b/tlatools/src/tlc2/util/NoopStateWriter.java
index f3e85e5ec733371abf9c45d33b8f943431bd71fc..4d3dce4cdea66bf803c7b04fc41fd9983d854db1 100644
--- a/tlatools/src/tlc2/util/NoopStateWriter.java
+++ b/tlatools/src/tlc2/util/NoopStateWriter.java
@@ -25,6 +25,8 @@
  ******************************************************************************/
 package tlc2.util;
 
+import java.io.IOException;
+
 import tlc2.tool.Action;
 import tlc2.tool.TLCState;
 
@@ -102,4 +104,10 @@ public final class NoopStateWriter implements IStateWriter {
 		return "";
 	}
 
+	/* (non-Javadoc)
+	 * @see tlc2.util.IStateWriter#snapshot()
+	 */
+	@Override
+	public void snapshot() throws IOException {
+	}
 }
diff --git a/tlatools/src/tlc2/util/StateWriter.java b/tlatools/src/tlc2/util/StateWriter.java
index f9fb560e32288207f13f7f3f2acabaa80ff3ace3..3efc5a0754bf1efc43998448b0e7b2c35aa9c8d2 100644
--- a/tlatools/src/tlc2/util/StateWriter.java
+++ b/tlatools/src/tlc2/util/StateWriter.java
@@ -15,7 +15,7 @@ public class StateWriter implements IStateWriter
 {
     protected final PrintWriter writer;
     protected int stateNum;
-	private String fname;
+    protected String fname;
 
     public StateWriter(String fname) throws IOException
     {
@@ -62,14 +62,14 @@ public class StateWriter implements IStateWriter
     public synchronized void writeState(final TLCState state, final TLCState successor, final boolean successorStateIsNew)
     {
     	if (successorStateIsNew) {
-    		this.writeState(state);
+    		this.writeState(successor);
     	}
     }
 
     public synchronized void writeState(final TLCState state, final TLCState successor, final boolean successorStateIsNew, Action action)
     {
     	if (successorStateIsNew) {
-    		this.writeState(state);
+    		this.writeState(successor);
     	}
     }
     
@@ -78,7 +78,7 @@ public class StateWriter implements IStateWriter
      */
     public void writeState(TLCState state, TLCState successor, final boolean successorStateIsNew, final Visualization visualization) {
     	if (successorStateIsNew) {
-    		this.writeState(state);
+    		this.writeState(successor);
     	}
     }
     
@@ -108,4 +108,9 @@ public class StateWriter implements IStateWriter
     		this.writeState(state);
     	}
 	}
+
+	@Override
+	public void snapshot() throws IOException {
+		// No-op unless DotStateWriter.
+	}
 }
diff --git a/tlatools/src/tlc2/util/SynchronousDiskIntStack.java b/tlatools/src/tlc2/util/SynchronousDiskIntStack.java
index 15c34bfea156b75a4a1f9ae38c46ceba7e8b25cf..b66120433be9da7b4676c741617549739c626013 100644
--- a/tlatools/src/tlc2/util/SynchronousDiskIntStack.java
+++ b/tlatools/src/tlc2/util/SynchronousDiskIntStack.java
@@ -55,7 +55,7 @@ public class SynchronousDiskIntStack implements IntStack {
 	
 	public SynchronousDiskIntStack(String diskdir, String name, int capacity) {
 		// Hard-limit capacity to 1gb per page file
-		capacity = Math.min(BufSizeMax, Math.max(capacity, BufSize));
+		capacity = Math.min(BufSizeMax, capacity);
 		this.filePrefix = diskdir + FileUtil.separator + name;
 		this.bufSize = capacity;
 		this.buf = new int[capacity];
diff --git a/tlatools/src/tlc2/util/Vect.java b/tlatools/src/tlc2/util/Vect.java
index b5852d01a72b431731c67090497a5df35e7c8bee..8d4907820ed4d1fbc12c8195a6839c1cfa95d02d 100644
--- a/tlatools/src/tlc2/util/Vect.java
+++ b/tlatools/src/tlc2/util/Vect.java
@@ -9,12 +9,19 @@ import java.util.Enumeration;
 import java.util.NoSuchElementException;
 import java.util.Vector;
 
+/**
+ * TODO it's unclear why we've written our own list implementation; we should consider using existing framework code for this;
+ * 		we've also written our own "Vector" class in SANY...
+ */
 @SuppressWarnings("unchecked")
 public class Vect<E> implements Cloneable, Serializable {
+	private static final long serialVersionUID = 1L;
+
+	
   private E[] elementData;
   private int elementCount;
          
-  final class Enumerator<E> implements Enumeration {
+  final class Enumerator implements Enumeration<E> {
     int index = 0;
 
     public final boolean hasMoreElements () {
@@ -38,11 +45,11 @@ public class Vect<E> implements Cloneable, Serializable {
     }
   }
 
-  public Vect(Vector v) {
+  public Vect(Vector<E> v) {
     this(v.size());
     int sz = v.size();    
     for (int i = 0; i < sz; i++) {
-      this.addElement((E) v.elementAt(i));
+      this.addElement(v.elementAt(i));
     }
   }
 
diff --git a/tlatools/src/tlc2/value/IBoolValue.java b/tlatools/src/tlc2/value/IBoolValue.java
index f41b70740142350308bb4e8da06db434b50551b1..552782b693c3cd6505cafe1347c33345bf17c786 100644
--- a/tlatools/src/tlc2/value/IBoolValue.java
+++ b/tlatools/src/tlc2/value/IBoolValue.java
@@ -27,5 +27,5 @@ package tlc2.value;
 
 public interface IBoolValue extends IValue {
 
-	public boolean getVal();
+	boolean getVal();
 }
\ No newline at end of file
diff --git a/tlatools/src/tlc2/value/IFcnLambdaValue.java b/tlatools/src/tlc2/value/IFcnLambdaValue.java
index 25b7bc46bd6c9c989f60d050d97b017896be5798..b91d82fef09e099887269b6356d5cc9dfec9864a 100644
--- a/tlatools/src/tlc2/value/IFcnLambdaValue.java
+++ b/tlatools/src/tlc2/value/IFcnLambdaValue.java
@@ -28,8 +28,6 @@ package tlc2.value;
 
 import tla2sany.semantic.SemanticNode;
 import tlc2.util.Context;
-import tlc2.value.IFcnParams;
-import tlc2.value.IFcnRcdValue;
 
 public interface IFcnLambdaValue {
 
diff --git a/tlatools/src/tlc2/value/IMVPerm.java b/tlatools/src/tlc2/value/IMVPerm.java
index 63c298db2552278ef4b45cc3a02b5529a7ad50d7..2682c3c1f0e0f972b14a189f6fab121e3e8bfaca 100644
--- a/tlatools/src/tlc2/value/IMVPerm.java
+++ b/tlatools/src/tlc2/value/IMVPerm.java
@@ -25,8 +25,6 @@
  ******************************************************************************/
 package tlc2.value;
 
-import tlc2.value.IModelValue;
-
 public interface IMVPerm {
 
 	IValue get(IValue value);
diff --git a/tlatools/src/tlc2/value/ITupleValue.java b/tlatools/src/tlc2/value/ITupleValue.java
index a211b7eb1123f3a9db1d7bfba437de2fafb432a2..6525574b3c5448aa4a7d2d26250a7675be0148e8 100644
--- a/tlatools/src/tlc2/value/ITupleValue.java
+++ b/tlatools/src/tlc2/value/ITupleValue.java
@@ -31,5 +31,6 @@ public interface ITupleValue extends IValue {
 
 	IValue[] getElems();
 
+	@Override
 	int size();
 }
\ No newline at end of file
diff --git a/tlatools/src/tlc2/value/IValue.java b/tlatools/src/tlc2/value/IValue.java
index ec51eace725544c66f935966aef34281d1765de9..30e7a4addfc2052935bc77e8b80301130db20f94 100644
--- a/tlatools/src/tlc2/value/IValue.java
+++ b/tlatools/src/tlc2/value/IValue.java
@@ -29,10 +29,15 @@ import java.io.IOException;
 
 import tla2sany.semantic.SemanticNode;
 import tlc2.tool.coverage.CostModel;
+import tlc2.value.impl.BoolValue;
+import tlc2.value.impl.IntValue;
+import tlc2.value.impl.ModelValue;
+import tlc2.value.impl.StringValue;
 
 public interface IValue extends Comparable<Object> {
 
 	/* This method compares this with val.  */
+	@Override
 	int compareTo(Object val);
 
 	void write(IValueOutputStream vos) throws IOException;
@@ -47,6 +52,32 @@ public interface IValue extends Comparable<Object> {
 
 	boolean hasSource();
 
+	/* MAK 09/17/2019: Introduced to guarantee that Value instances are
+	 * fully initialized when created by the SpecProcessor (as opposed
+	 * to by workers during state space exploration).
+	 */
+	/**
+	 * Fully initialize this instance which includes:
+	 * - deep normalization
+	 * - conversion and caching iff defined by the sub-class
+	 * 
+	 *  No further mutation of this instance should be required
+	 *  for any evaluation whatsoever.
+	 *  
+	 *  Afterwards, isNormalized below returns true (it does not
+	 *  return true for all sub-classes when only deepNormalized
+	 *  is executed)!
+	 *  
+	 *  see comment in UnionValue#deepNormalize too
+	 */
+	default IValue initialize() {
+		this.deepNormalize();
+		// Execute fingerprint code path to internally trigger convertAndCache iff
+		// defined (0L parameter is not relevant)
+		this.fingerPrint(0L);
+		return this;
+	}
+	
 	/**
 	   * This method normalizes (destructively) the representation of
 	   * the value. It is essential for equality comparison.
@@ -87,5 +118,22 @@ public interface IValue extends Comparable<Object> {
 	String toString();
 
 	String toString(String delim);
+	
+	String toUnquotedString();
+
+	default boolean isAtom() {
+		if (this instanceof ModelValue || this instanceof IntValue || this instanceof StringValue
+				|| this instanceof BoolValue) {
+			return true;
+		}
+		return false;
+	}
+	
+	/**
+	 * @return true if a value mutates as part of normalization or fingerprinting.
+	 */
+	default boolean mutates() {
+		return true;
+	}
 
 }
\ No newline at end of file
diff --git a/tlatools/src/tlc2/value/RandomEnumerableValues.java b/tlatools/src/tlc2/value/RandomEnumerableValues.java
index ebd30c2a977d638f3f54713d0597b5329fd9b795..9d7d3f97f5e71369d1328dc961083587fd3556ad 100644
--- a/tlatools/src/tlc2/value/RandomEnumerableValues.java
+++ b/tlatools/src/tlc2/value/RandomEnumerableValues.java
@@ -96,8 +96,8 @@ public abstract class RandomEnumerableValues {
 		}
 	};
 		
-	private static interface EnumerableValueRandom {
-		public Random initialize();
+	private interface EnumerableValueRandom {
+		Random initialize();
 	}
 
 	@SuppressWarnings("serial")
diff --git a/tlatools/src/tlc2/value/ValueConstants.java b/tlatools/src/tlc2/value/ValueConstants.java
index 8717f41f50e06692cddd41fbaf3da08764aff66e..108c7b08049db3e49bd9afa493ee8b16a9f2ecc6 100644
--- a/tlatools/src/tlc2/value/ValueConstants.java
+++ b/tlatools/src/tlc2/value/ValueConstants.java
@@ -8,32 +8,32 @@ package tlc2.value;
 public interface ValueConstants {
 
   /* Type code for values. */
-  public final byte BOOLVALUE        = 0;
-  public final byte INTVALUE         = BOOLVALUE + 1;
-  public final byte REALVALUE        = INTVALUE + 1;  
-  public final byte STRINGVALUE      = REALVALUE + 1;
-  public final byte RECORDVALUE      = STRINGVALUE + 1;
-  public final byte SETENUMVALUE     = RECORDVALUE + 1;
-  public final byte SETPREDVALUE     = SETENUMVALUE + 1;
-  public final byte TUPLEVALUE       = SETPREDVALUE + 1;
-  public final byte FCNLAMBDAVALUE   = TUPLEVALUE + 1;
-  public final byte FCNRCDVALUE      = FCNLAMBDAVALUE + 1;
-  public final byte OPLAMBDAVALUE    = FCNRCDVALUE + 1;
-  public final byte OPRCDVALUE       = OPLAMBDAVALUE + 1;
-  public final byte METHODVALUE      = OPRCDVALUE + 1;
-  public final byte SETOFFCNSVALUE   = METHODVALUE + 1;
-  public final byte SETOFRCDSVALUE   = SETOFFCNSVALUE + 1;
-  public final byte SETOFTUPLESVALUE = SETOFRCDSVALUE + 1;
-  public final byte SUBSETVALUE      = SETOFTUPLESVALUE + 1;
-  public final byte SETDIFFVALUE     = SUBSETVALUE + 1;
-  public final byte SETCAPVALUE      = SETDIFFVALUE + 1;
-  public final byte SETCUPVALUE      = SETCAPVALUE + 1;
-  public final byte UNIONVALUE       = SETCUPVALUE + 1;
-  public final byte MODELVALUE       = UNIONVALUE + 1;
-  public final byte USERVALUE        = MODELVALUE + 1;
-  public final byte INTERVALVALUE    = USERVALUE + 1;
-  public final byte UNDEFVALUE       = INTERVALVALUE + 1;
-  public final byte LAZYVALUE        = UNDEFVALUE + 1;
-  public final byte DUMMYVALUE       = LAZYVALUE + 1;
+  byte BOOLVALUE        = 0;
+  byte INTVALUE         = BOOLVALUE + 1;
+  byte REALVALUE        = INTVALUE + 1;
+  byte STRINGVALUE      = REALVALUE + 1;
+  byte RECORDVALUE      = STRINGVALUE + 1;
+  byte SETENUMVALUE     = RECORDVALUE + 1;
+  byte SETPREDVALUE     = SETENUMVALUE + 1;
+  byte TUPLEVALUE       = SETPREDVALUE + 1;
+  byte FCNLAMBDAVALUE   = TUPLEVALUE + 1;
+  byte FCNRCDVALUE      = FCNLAMBDAVALUE + 1;
+  byte OPLAMBDAVALUE    = FCNRCDVALUE + 1;
+  byte OPRCDVALUE       = OPLAMBDAVALUE + 1;
+  byte METHODVALUE      = OPRCDVALUE + 1;
+  byte SETOFFCNSVALUE   = METHODVALUE + 1;
+  byte SETOFRCDSVALUE   = SETOFFCNSVALUE + 1;
+  byte SETOFTUPLESVALUE = SETOFRCDSVALUE + 1;
+  byte SUBSETVALUE      = SETOFTUPLESVALUE + 1;
+  byte SETDIFFVALUE     = SUBSETVALUE + 1;
+  byte SETCAPVALUE      = SETDIFFVALUE + 1;
+  byte SETCUPVALUE      = SETCAPVALUE + 1;
+  byte UNIONVALUE       = SETCUPVALUE + 1;
+  byte MODELVALUE       = UNIONVALUE + 1;
+  byte USERVALUE        = MODELVALUE + 1;
+  byte INTERVALVALUE    = USERVALUE + 1;
+  byte UNDEFVALUE       = INTERVALVALUE + 1;
+  byte LAZYVALUE        = UNDEFVALUE + 1;
+  byte DUMMYVALUE       = LAZYVALUE + 1;
 
 }
diff --git a/tlatools/src/tlc2/value/ValueInputStream.java b/tlatools/src/tlc2/value/ValueInputStream.java
index 2e1c90b2a580defd715bf18f799e87f6f24372d4..a2a80d4624be158c50e6b641a3beebb908f02326 100644
--- a/tlatools/src/tlc2/value/ValueInputStream.java
+++ b/tlatools/src/tlc2/value/ValueInputStream.java
@@ -5,6 +5,7 @@ package tlc2.value;
 import java.io.EOFException;
 import java.io.File;
 import java.io.IOException;
+import java.util.Map;
 
 import tlc2.TLCGlobals;
 import tlc2.value.impl.BoolValue;
@@ -27,12 +28,17 @@ public final class ValueInputStream implements ValueConstants, IValueInputStream
   private final BufferedDataInputStream dis;
   private final HandleTable handles;
 
-  public ValueInputStream(File file) throws IOException 
+  public ValueInputStream(File file, final boolean compressed) throws IOException 
   {
       // SZ Feb 24, 2009: FileUtil refactoring
-    this.dis = FileUtil.newBdFIS(TLCGlobals.useGZIP, file);
+    this.dis = FileUtil.newBdFIS(compressed, file);
     this.handles = new HandleTable();
   }
+  
+  public ValueInputStream(File file) throws IOException 
+  {
+	  this(file, TLCGlobals.useGZIP);
+  }
 
   public ValueInputStream(String fname) throws IOException {
       this(new File(fname));
@@ -78,7 +84,47 @@ public final class ValueInputStream implements ValueConstants, IValueInputStream
 		}
 		}
 	}
-  
+	
+	public final IValue read(final Map<String, UniqueString> tbl) throws IOException {
+		final byte kind = this.dis.readByte();
+
+		switch (kind) {
+		case BOOLVALUE: {
+			return (this.dis.readBoolean()) ? BoolValue.ValTrue : BoolValue.ValFalse;
+		}
+		case INTVALUE: {
+			return IntValue.gen(this.dis.readInt());
+		}
+		case STRINGVALUE: {
+			return StringValue.createFrom(this, tbl);
+		}
+		case MODELVALUE: {
+			return ModelValue.mvs[this.dis.readShort()];
+		}
+		case INTERVALVALUE: {
+			return new IntervalValue(this.dis.readInt(), this.dis.readInt());
+		}
+		case RECORDVALUE: {
+			return RecordValue.createFrom(this, tbl);
+		}
+		case FCNRCDVALUE: {
+			return FcnRcdValue.createFrom(this, tbl);
+		}
+		case SETENUMVALUE: {
+			return SetEnumValue.createFrom(this, tbl);
+		}
+		case TUPLEVALUE: {
+			return TupleValue.createFrom(this, tbl);
+		}
+		case DUMMYVALUE: {
+			return (IValue) this.handles.getValue(this.readNat());
+		}
+		default: {
+			throw new WrongInvocationException("ValueInputStream: Can not unpickle a value of kind " + kind);
+		}
+		}
+	}
+ 
   @Override
   public final int readShort() throws IOException {
 	    return this.dis.readShort();
diff --git a/tlatools/src/tlc2/value/ValueOutputStream.java b/tlatools/src/tlc2/value/ValueOutputStream.java
index e28c39beb3f59ed8291b01c54ae75fe38506da66..f4b56b4da9fbfa2f3bc350de0f72d64a9cd74295 100644
--- a/tlatools/src/tlc2/value/ValueOutputStream.java
+++ b/tlatools/src/tlc2/value/ValueOutputStream.java
@@ -18,7 +18,11 @@ public final class ValueOutputStream implements IValueOutputStream {
   private final HandleTable handles;
 
   public ValueOutputStream(File file) throws IOException {
-    if (TLCGlobals.useGZIP) {
+	  this(file, TLCGlobals.useGZIP);
+  }
+
+  public ValueOutputStream(File file, final boolean compress) throws IOException {
+    if (compress) {
       OutputStream os = new GZIPOutputStream(new FileOutputStream(file));
       this.dos = new BufferedDataOutputStream(os);
     }
@@ -29,15 +33,19 @@ public final class ValueOutputStream implements IValueOutputStream {
   }
 
   public ValueOutputStream(String fname) throws IOException {
-    if (TLCGlobals.useGZIP) {
-      OutputStream os = new GZIPOutputStream(new FileOutputStream(fname));
-      this.dos = new BufferedDataOutputStream(os);
-    }
-    else {
-      this.dos = new BufferedDataOutputStream(fname);
-    }
-    this.handles = new HandleTable();
+	  this(fname, TLCGlobals.useGZIP);
   }
+  
+  public ValueOutputStream(String fname, boolean zip) throws IOException {
+	    if (zip) {
+	      OutputStream os = new GZIPOutputStream(new FileOutputStream(fname));
+	      this.dos = new BufferedDataOutputStream(os);
+	    }
+	    else {
+	      this.dos = new BufferedDataOutputStream(fname);
+	    }
+	    this.handles = new HandleTable();
+	  }
 
   @Override
   public final void writeShort(short x) throws IOException {
diff --git a/tlatools/src/tlc2/value/impl/Applicable.java b/tlatools/src/tlc2/value/impl/Applicable.java
index 1f291877651bc50cf5bf857ed952ac37df7da124..3822610bebdcf9b0e245320b9c09d7c5cefef5ed 100644
--- a/tlatools/src/tlc2/value/impl/Applicable.java
+++ b/tlatools/src/tlc2/value/impl/Applicable.java
@@ -9,9 +9,9 @@ import tlc2.tool.EvalException;
 
 public interface Applicable {
   
-  public Value apply(Value[] args, int control) throws EvalException;
-  public Value apply(Value arg, int control) throws EvalException;
-  public Value getDomain() throws EvalException;
-  public Value select(Value arg) throws EvalException;
+  Value apply(Value[] args, int control) throws EvalException;
+  Value apply(Value arg, int control) throws EvalException;
+  Value getDomain() throws EvalException;
+  Value select(Value arg) throws EvalException;
   
 }
diff --git a/tlatools/src/tlc2/value/impl/BoolValue.java b/tlatools/src/tlc2/value/impl/BoolValue.java
index 4b9fdee0ea37ce93617cff77debfd5fe16f9a275..a6b40dc3bb7d40b15c3e27f4e3a98aee00d8462c 100644
--- a/tlatools/src/tlc2/value/impl/BoolValue.java
+++ b/tlatools/src/tlc2/value/impl/BoolValue.java
@@ -19,9 +19,9 @@ import util.Assert;
 
 public class BoolValue extends Value implements IBoolValue {
   public boolean val;   // the boolean
-  public final static BoolValue ValFalse = new BoolValue(false);
+  public static final BoolValue ValFalse = new BoolValue(false);
   /* Value constants. */
-  public final static BoolValue ValTrue  = new BoolValue(true);
+  public static final BoolValue ValTrue  = new BoolValue(true);
 
   /* Constructor */
   public BoolValue(boolean b) { this.val = b; }
@@ -31,8 +31,10 @@ public class BoolValue extends Value implements IBoolValue {
 	  return val;
   }
   
+  @Override
   public final byte getKind() { return BOOLVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       if (obj instanceof BoolValue) {
@@ -69,6 +71,7 @@ public class BoolValue extends Value implements IBoolValue {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) +
@@ -81,6 +84,7 @@ public class BoolValue extends Value implements IBoolValue {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       Assert.fail("Attempted to check if the boolean " + Values.ppr(this.toString()) +
@@ -93,6 +97,7 @@ public class BoolValue extends Value implements IBoolValue {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -107,6 +112,7 @@ public class BoolValue extends Value implements IBoolValue {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (exs.length != 0) {
@@ -121,6 +127,7 @@ public class BoolValue extends Value implements IBoolValue {
     }
   }
 
+  @Override
   public final int size() {
     try {
       Assert.fail("Attempted to compute the number of elements in the boolean " +
@@ -133,14 +140,24 @@ public class BoolValue extends Value implements IBoolValue {
     }
   }
 
+  @Override
+  public boolean mutates() {
+	  return false;
+  }
+
+  @Override
   public final boolean isNormalized() { return true; }
 
+  @Override
   public final Value normalize() { /*nop*/ return this; }
 
+  @Override
   public final boolean isDefined() { return true; }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       return ((val instanceof BoolValue) &&
@@ -159,6 +176,7 @@ public class BoolValue extends Value implements IBoolValue {
 	}
 
   /* The fingerprint method */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       fp = FP64.Extend(fp, BOOLVALUE) ;
@@ -171,6 +189,7 @@ public class BoolValue extends Value implements IBoolValue {
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) { return this; }
 
   /* The string representation */
@@ -179,6 +198,7 @@ public class BoolValue extends Value implements IBoolValue {
 }
 
 /* The string representation */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       return sb.append((this.val) ? "TRUE" : "FALSE");
diff --git a/tlatools/src/tlc2/value/impl/Enumerable.java b/tlatools/src/tlc2/value/impl/Enumerable.java
index f0bc0029fb607ade5a31729e7129c74117d6b88b..2622b6a8f93c05bee0189c7ab298c99932edee0b 100644
--- a/tlatools/src/tlc2/value/impl/Enumerable.java
+++ b/tlatools/src/tlc2/value/impl/Enumerable.java
@@ -15,16 +15,17 @@ public interface Enumerable extends IValue {
 		 * The normalized order is the order of elements when a Value gets
 		 * fingerprinted (@see {@link Value#fingerPrint(long)}.
 		 */
-		NORMALIZED;
-	}
+		NORMALIZED
+    }
 	
-  public int size();
-  public boolean member(Value elem);
+  @Override
+  int size();
+  boolean member(Value elem);
   /**
    * Semantics or Enumerable#elements(Ordering#UNDEFINED) 
    */
-  public ValueEnumeration elements();
-  public ValueEnumeration elements(final Ordering ordering);
+  ValueEnumeration elements();
+  ValueEnumeration elements(final Ordering ordering);
   /**
    * Returns a {@link ValueEnumeration} which returns k 
    * {@link IValue}s of all {@link IValue}s returned by 
@@ -32,8 +33,8 @@ public interface Enumerable extends IValue {
    * a randomly chosen subset of all {@link IValue} members of
    * this {@link Enumerable}.
    */
-  public ValueEnumeration elements(final int k);
-  public EnumerableValue getRandomSubset(final int k);
-  public Value isSubsetEq(Value other);
+  ValueEnumeration elements(final int k);
+  EnumerableValue getRandomSubset(final int k);
+  Value isSubsetEq(Value other);
 }
 
diff --git a/tlatools/src/tlc2/value/impl/EnumerableValue.java b/tlatools/src/tlc2/value/impl/EnumerableValue.java
index bb4128757858a8ffcb3677b83bbf53ba62aea8a9..86586301a1e8549df487709e53bd3c1d62ed2e42 100644
--- a/tlatools/src/tlc2/value/impl/EnumerableValue.java
+++ b/tlatools/src/tlc2/value/impl/EnumerableValue.java
@@ -34,6 +34,7 @@ import tlc2.value.RandomEnumerableValues;
 
 public abstract class EnumerableValue extends Value implements Enumerable {
 
+  @Override
   public Value isSubsetEq(Value other) {
     try {
       final ValueEnumeration Enum = this.elements();
@@ -78,6 +79,7 @@ public abstract class EnumerableValue extends Value implements Enumerable {
 		return elements();
 	}
 	
+	@Override
 	public ValueEnumeration elements(final int k) {
 		// The generic implementation collects all n elements of the actual Enumerable
 		// into the temporary variable values. The SubSetEnumerator then randomly
@@ -119,7 +121,7 @@ public abstract class EnumerableValue extends Value implements Enumerable {
 			//
 			// x has to be co-prime to n. Since n might or might not be a prime number
 			// - it depends on the actual size of the set - we simply set x to
-			// be a prime number. The prime x has to be larger than n tough, since n is
+			// be a prime number. The prime x has to be larger than n though, since n is
 			// bound by Integer.MAX_VALUE, we simply choose the Mersenne prime
 			// Integer.MAX_VALUE
 			// for x and accept that we fail if n = Integer.MAX_VALUE. To minimize
@@ -138,6 +140,7 @@ public abstract class EnumerableValue extends Value implements Enumerable {
 			}
 		}
 
+		@Override
 		public void reset() {
 			i = 0;
 		}
@@ -162,6 +165,7 @@ public abstract class EnumerableValue extends Value implements Enumerable {
 			return index;
 		}
 
+		@Override
 		public abstract Value nextElement();
 	}
 }
diff --git a/tlatools/src/tlc2/value/impl/EvaluatingValue.java b/tlatools/src/tlc2/value/impl/EvaluatingValue.java
new file mode 100644
index 0000000000000000000000000000000000000000..e498d10a8e650163d3bd65b135561f5e305c1392
--- /dev/null
+++ b/tlatools/src/tlc2/value/impl/EvaluatingValue.java
@@ -0,0 +1,250 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.value.impl;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Method;
+
+import tla2sany.semantic.ExprOrOpArgNode;
+import tlc2.output.EC;
+import tlc2.output.MP;
+import tlc2.tool.FingerprintException;
+import tlc2.tool.TLCState;
+import tlc2.tool.coverage.CostModel;
+import tlc2.tool.impl.Tool;
+import tlc2.util.Context;
+import tlc2.value.IValue;
+import tlc2.value.Values;
+import util.Assert;
+import util.Assert.TLCRuntimeException;
+import util.WrongInvocationException;
+
+public class EvaluatingValue extends OpValue implements Applicable {
+  private final MethodHandle mh;
+  private final Method md;
+  private final int minLevel;
+
+  /* Constructor */
+	public EvaluatingValue(final Method md, final int minLevel) {
+		this.md = md;
+		this.minLevel = minLevel;
+		try {
+			this.mh = MethodHandles.publicLookup().unreflect(md).asFixedArity();
+		} catch (IllegalAccessException e) {
+			throw new TLCRuntimeException(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, MP.getMessage(
+					EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, new String[] { md.toString(), e.getMessage() }));
+		}
+	}
+
+	public Value eval(final Tool tool, final ExprOrOpArgNode[] args, final Context c, final TLCState s0,
+			final TLCState s1, final int control, final CostModel cm) {
+		try {
+			return (Value) this.mh.invoke(tool, args, c, s0, s1, control, cm);
+		} catch (Throwable e) {
+            Assert.fail(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, new String[]{this.md.toString(), e.getMessage()});
+            return null; // make compiler happy
+		}
+	}
+
+  public final byte getKind() { return METHODVALUE; }
+
+  public final int compareTo(Object obj) {
+    try {
+      Assert.fail("Attempted to compare operator " + this.toString() +
+      " with value:\n" + obj == null ? "null" : Values.ppr(obj.toString()));
+      return 0;       // make compiler happy
+    }
+    catch (RuntimeException | OutOfMemoryError e) {
+      if (hasSource()) { throw FingerprintException.getNewHead(this, e); }
+      else { throw e; }
+    }
+  }
+
+  public final boolean equals(Object obj) {
+    try {
+      Assert.fail("Attempted to check equality of operator " + this.toString() +
+      " with value:\n" + obj == null ? "null" : Values.ppr(obj.toString()));
+      return false;   // make compiler happy
+    }
+    catch (RuntimeException | OutOfMemoryError e) {
+      if (hasSource()) { throw FingerprintException.getNewHead(this, e); }
+      else { throw e; }
+    }
+  }
+
+  public final boolean member(Value elem) {
+    try {
+      Assert.fail("Attempted to check if the value:\n" + elem == null ? "null" : Values.ppr(elem.toString()) +
+      "\nis an element of operator " + this.toString());
+      return false;   // make compiler happy
+    }
+    catch (RuntimeException | OutOfMemoryError e) {
+      if (hasSource()) { throw FingerprintException.getNewHead(this, e); }
+      else { throw e; }
+    }
+  }
+
+  public final boolean isFinite() {
+    try {
+      Assert.fail("Attempted to check if the operator " + this.toString() +
+      " is a finite set.");
+      return false;   // make compiler happy
+    }
+    catch (RuntimeException | OutOfMemoryError e) {
+      if (hasSource()) { throw FingerprintException.getNewHead(this, e); }
+      else { throw e; }
+    }
+  }
+
+  public final Value apply(Value arg, int control) {
+    try {
+      throw new WrongInvocationException("It is a TLC bug: Should use the other apply method.");
+    }
+    catch (RuntimeException | OutOfMemoryError e) {
+      if (hasSource()) { throw FingerprintException.getNewHead(this, e); }
+      else { throw e; }
+    }
+  }
+
+  public final Value apply(Value[] args, int control) {
+	    try {
+	        throw new WrongInvocationException("It is a TLC bug: Should use the other apply method.");
+	      }
+	      catch (RuntimeException | OutOfMemoryError e) {
+	        if (hasSource()) { throw FingerprintException.getNewHead(this, e); }
+	        else { throw e; }
+	      }
+  }
+
+  public final Value select(Value arg) {
+    try {
+      throw new WrongInvocationException("It is a TLC bug: Attempted to call MethodValue.select().");
+    }
+    catch (RuntimeException | OutOfMemoryError e) {
+      if (hasSource()) { throw FingerprintException.getNewHead(this, e); }
+      else { throw e; }
+    }
+  }
+
+  public final Value takeExcept(ValueExcept ex) {
+    try {
+      Assert.fail("Attempted to appy EXCEPT construct to the operator " +
+      this.toString() + ".");
+      return null;   // make compiler happy
+    }
+    catch (RuntimeException | OutOfMemoryError e) {
+      if (hasSource()) { throw FingerprintException.getNewHead(this, e); }
+      else { throw e; }
+    }
+  }
+
+  public final Value takeExcept(ValueExcept[] exs) {
+    try {
+      Assert.fail("Attempted to apply EXCEPT construct to the operator " +
+      this.toString() + ".");
+      return null;   // make compiler happy
+    }
+    catch (RuntimeException | OutOfMemoryError e) {
+      if (hasSource()) { throw FingerprintException.getNewHead(this, e); }
+      else { throw e; }
+    }
+  }
+
+  public final Value getDomain() {
+    try {
+      Assert.fail("Attempted to compute the domain of the operator " +
+      this.toString() + ".");
+      return SetEnumValue.EmptySet;   // make compiler happy
+    }
+    catch (RuntimeException | OutOfMemoryError e) {
+      if (hasSource()) { throw FingerprintException.getNewHead(this, e); }
+      else { throw e; }
+    }
+  }
+
+  public final int size() {
+    try {
+      Assert.fail("Attempted to compute the number of elements in the operator " +
+      this.toString() + ".");
+      return 0;   // make compiler happy
+    }
+    catch (RuntimeException | OutOfMemoryError e) {
+      if (hasSource()) { throw FingerprintException.getNewHead(this, e); }
+      else { throw e; }
+    }
+  }
+
+  /* Should never normalize an operator. */
+  public final boolean isNormalized() {
+    try {
+      throw new WrongInvocationException("It is a TLC bug: Attempted to normalize an operator.");
+    }
+    catch (RuntimeException | OutOfMemoryError e) {
+      if (hasSource()) { throw FingerprintException.getNewHead(this, e); }
+      else { throw e; }
+    }
+  }
+
+  public final Value normalize() {
+    try {
+      throw new WrongInvocationException("It is a TLC bug: Attempted to normalize an operator.");
+    }
+    catch (RuntimeException | OutOfMemoryError e) {
+      if (hasSource()) { throw FingerprintException.getNewHead(this, e); }
+      else { throw e; }
+    }
+  }
+
+  public final boolean isDefined() { return true; }
+
+  public final IValue deepCopy() { return this; }
+
+  public final boolean assignable(Value val) {
+    try {
+      throw new WrongInvocationException("It is a TLC bug: Attempted to initialize an operator.");
+    }
+    catch (RuntimeException | OutOfMemoryError e) {
+      if (hasSource()) { throw FingerprintException.getNewHead(this, e); }
+      else { throw e; }
+    }
+  }
+
+  /* String representation of the value.  */
+  public final StringBuffer toString(StringBuffer sb, int offset, boolean ignored) {
+    try {
+      return sb.append("<Java Method: " + this.md + ">");
+    }
+    catch (RuntimeException | OutOfMemoryError e) {
+      if (hasSource()) { throw FingerprintException.getNewHead(this, e); }
+      else { throw e; }
+    }
+  }
+
+  public int getMinLevel() {
+	  return minLevel;
+  }
+}
diff --git a/tlatools/src/tlc2/value/impl/FcnLambdaValue.java b/tlatools/src/tlc2/value/impl/FcnLambdaValue.java
index f943f672b813f619bffdd4e495766a0d23c7955c..364c0e89130796b6250c7ae7505a23cc5ca72d1e 100644
--- a/tlatools/src/tlc2/value/impl/FcnLambdaValue.java
+++ b/tlatools/src/tlc2/value/impl/FcnLambdaValue.java
@@ -68,11 +68,11 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
 	  this.cm = cm;
   }
 
-  public FcnLambdaValue(FcnLambdaValue fcn) {
+  public FcnLambdaValue(FcnLambdaValue fcn, ITool tool) {
     this.params = fcn.params;
     this.body = fcn.body;
     this.excepts = fcn.excepts;
-    this.tool = fcn.tool;
+    this.tool = tool;
     this.con = fcn.con;
     this.state = fcn.state;
     this.pstate = fcn.pstate;
@@ -80,6 +80,11 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
     this.fcnRcd = fcn.fcnRcd;
   }
 
+  public FcnLambdaValue(FcnLambdaValue fcn) {
+	  this(fcn, fcn.tool);
+  }
+
+  @Override
   public final byte getKind() { return FCNLAMBDAVALUE; }
 
   public final void makeRecursive(SymbolNode fname) {
@@ -93,6 +98,7 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
     }
   }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       FcnRcdValue fcn = (FcnRcdValue) this.toFcnRcd();
@@ -115,6 +121,7 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) +
@@ -127,6 +134,7 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       Assert.fail("Attempted to check if the function:\n" + Values.ppr(this.toString()) +
@@ -140,6 +148,7 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
   }
 
   /* Apply this function to the arguments given by args.  */
+  @Override
   public final Value apply(Value args, int control) throws EvalException {
     try {
 
@@ -260,6 +269,7 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
   }
 
   /* This one does not seem to be needed anymore.  */
+  @Override
   public final Value apply(Value[] args, int control) throws EvalException {
     try {
       return this.apply(new TupleValue(args), control);
@@ -270,6 +280,7 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
     }
   }
 
+  @Override
   public final Value select(Value arg) {
     try {
 
@@ -380,6 +391,7 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
   }
 
   /* This method returns a new function value by taking except. */
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
 
@@ -411,6 +423,7 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
   }
 
   /* This method returns a new function value by taking excepts. */
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
 
@@ -449,6 +462,7 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
     }
   }
 
+  @Override
   public final Value getDomain() {
     try {
 
@@ -484,6 +498,7 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
     }
   }
 
+  @Override
   public final int size() {
     try {
       if (this.fcnRcd == null) {
@@ -497,8 +512,10 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
     }
   }
 
+  @Override
   public final boolean isDefined() { return true; }
 
+  @Override
   public final IValue deepCopy() {
     try {
       FcnLambdaValue fcn = new FcnLambdaValue(this);
@@ -515,6 +532,7 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
     }
   }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       return (val instanceof FcnLambdaValue);
@@ -534,6 +552,7 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
     oos.writeObject(res);
   }
 
+  @Override
   public final boolean isNormalized() {
     try {
       if (this.fcnRcd == null) {
@@ -547,6 +566,7 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
     }
   }
 
+  @Override
   public final Value normalize() {
     try {
       if (this.fcnRcd != null) {
@@ -714,6 +734,7 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
 	}
   
   /* The fingerprint methods.  */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       Value  fcn = this.toFcnRcd();
@@ -725,6 +746,7 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) {
     try {
       Value  fcn = this.toFcnRcd();
@@ -742,6 +764,7 @@ public class FcnLambdaValue extends Value implements Applicable, IFcnLambdaValue
 }
 
 /* The string representation of this function.  */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       if (TLCGlobals.expand || this.params == null) {
diff --git a/tlatools/src/tlc2/value/impl/FcnParams.java b/tlatools/src/tlc2/value/impl/FcnParams.java
index 9298fd02c3542b579c65a7f154b54305cb567e65..d91b0d953573e5d7c51243742dfc0f11d7262488 100644
--- a/tlatools/src/tlc2/value/impl/FcnParams.java
+++ b/tlatools/src/tlc2/value/impl/FcnParams.java
@@ -27,6 +27,7 @@ public class FcnParams implements IFcnParams {
     }
   }
 
+  @Override
   public final int length() { return this.argLen; }
   
   public final int size() {
@@ -136,6 +137,7 @@ public class FcnParams implements IFcnParams {
       }
     }
 
+    @Override
     public final void reset() {
       if (this.enums != null) {
 	for (int i = 0; i < this.enums.length; i++) {
@@ -145,6 +147,7 @@ public class FcnParams implements IFcnParams {
       }
     }
 
+    @Override
     public final Value nextElement() {
       if (this.enums == null) return null;
       Value[] elems = new Value[argLen];
diff --git a/tlatools/src/tlc2/value/impl/FcnRcdValue.java b/tlatools/src/tlc2/value/impl/FcnRcdValue.java
index 17fcd1e4020a98e0272a72ce7cb2db96812beb71..b8c18ab21d7f6fa86631c40377f931931fb13e61 100644
--- a/tlatools/src/tlc2/value/impl/FcnRcdValue.java
+++ b/tlatools/src/tlc2/value/impl/FcnRcdValue.java
@@ -8,6 +8,7 @@ package tlc2.value.impl;
 
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.Map;
 
 import tlc2.tool.EvalControl;
 import tlc2.tool.FingerprintException;
@@ -18,8 +19,10 @@ import tlc2.value.IMVPerm;
 import tlc2.value.IValue;
 import tlc2.value.IValueInputStream;
 import tlc2.value.IValueOutputStream;
+import tlc2.value.ValueInputStream;
 import tlc2.value.Values;
 import util.Assert;
+import util.TLAConstants;
 import util.UniqueString;
 
 public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
@@ -28,7 +31,7 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
   public final Value[] values;
   private boolean isNorm;
   private int[] indexTbl;  // speed up function application
-  public final static Value EmptyFcn = new FcnRcdValue(new Value[0], new Value[0], true);
+  public static final Value EmptyFcn = new FcnRcdValue(new Value[0], new Value[0], true);
 
   /* Constructor */
   public FcnRcdValue(Value[] domain, Value[] values, boolean isNorm) {
@@ -74,6 +77,7 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
 	  this.cm = cm;
   }
 
+  @Override
   public final byte getKind() { return FCNRCDVALUE; }
 
   /* We create an index only when the domain is not very small. */
@@ -115,6 +119,7 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
     }
   }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
 
@@ -281,6 +286,7 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) +
@@ -293,8 +299,10 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
     }
   }
 
+  @Override
   public final boolean isFinite() { return true; }
 
+  @Override
   public final Value apply(Value arg, int control) {
     try {
     	Value result = this.select(arg);
@@ -312,6 +320,7 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
   }
 
   /* This one does not seem to be needed anymore.  */
+  @Override
   public final Value apply(Value[] args, int control) {
     try {
       return this.apply(new TupleValue(args), EvalControl.Clear);
@@ -322,6 +331,7 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
     }
   }
 
+  @Override
   public final Value select(Value arg) {
     try {
 
@@ -410,6 +420,7 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
 
@@ -460,6 +471,7 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       Value res = this;
@@ -474,6 +486,7 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
     }
   }
 
+  @Override
   public final Value getDomain() {
     try {
       if (this.intv != null) {
@@ -500,6 +513,7 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
 	  }
   }
   
+  @Override
   public final int size() {
     try {
       this.normalize();
@@ -510,6 +524,16 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
       else { throw e; }
     }
   }
+  
+  /**
+   * {@link #size()} first normalizes, destructively, this instance; for inspections on the size without normalization
+   * 	use this method.
+   * 
+   * @return
+   */
+  public int nonNormalizedSize() {
+	  return values.length;
+  }
 
   @Override
   public final Value toTuple() {
@@ -555,9 +579,11 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
 	}
   
   /* Return true iff this function is in normal form. */
+  @Override
   public final boolean isNormalized() { return this.isNorm; }
 
   /* This method normalizes (destructively) this function. */
+  @Override
   public final Value normalize() {
     try {
 
@@ -620,6 +646,7 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
 	    }
   }
 
+  @Override
   public final boolean isDefined() {
     try {
 
@@ -641,6 +668,7 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
     }
   }
 
+  @Override
   public final IValue deepCopy() {
     try {
     	Value[] vals = new Value[this.values.length];
@@ -655,6 +683,7 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
     }
   }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       boolean canAssign = ((val instanceof FcnRcdValue) &&
@@ -702,6 +731,7 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
 	}
 
   /* The fingerprint method.  */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       this.normalize();
@@ -729,6 +759,7 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) {
     try {
 
@@ -815,6 +846,7 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
   }
 
   /* The string representation of the value.  */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
 
@@ -824,12 +856,12 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
       }
       else if (this.isRcd()) {
         sb.append("[");
-        sb.append(((StringValue)this.domain[0]).val + " |-> ");
+        sb.append(((StringValue)this.domain[0]).val + TLAConstants.RECORD_ARROW);
         sb = this.values[0].toString(sb, offset, swallow);
 
         for (int i = 1; i < len; i++) {
           sb.append(", ");
-          sb.append(((StringValue)this.domain[i]).val + " |-> ");
+          sb.append(((StringValue)this.domain[i]).val + TLAConstants.RECORD_ARROW);
           sb = this.values[i].toString(sb, offset, swallow);
         }
         sb.append("]");
@@ -893,4 +925,30 @@ public class FcnRcdValue extends Value implements Applicable, IFcnRcdValue {
 		vos.assign(res, index);
 		return res;
 	}
+
+	public static IValue createFrom(final ValueInputStream vos, final Map<String, UniqueString> tbl) throws IOException {
+		final int index = vos.getIndex();
+		final int len = vos.readNat();
+		final int info = vos.readByte();
+		Value res;
+		final Value[] rvals = new Value[len];
+		if (info == 0) {
+			final int low = vos.readInt();
+			final int high = vos.readInt();
+			for (int i = 0; i < len; i++) {
+				rvals[i] = (Value) vos.read(tbl);
+			}
+			final IntervalValue intv = new IntervalValue(low, high);
+			res = new FcnRcdValue(intv, rvals);
+		} else {
+			final Value[] dvals = new Value[len];
+			for (int i = 0; i < len; i++) {
+				dvals[i] = (Value) vos.read(tbl);
+				rvals[i] = (Value) vos.read(tbl);
+			}
+			res = new FcnRcdValue(dvals, rvals, (info == 1));
+		}
+		vos.assign(res, index);
+		return res;
+	}
 }
diff --git a/tlatools/src/tlc2/value/impl/IntValue.java b/tlatools/src/tlc2/value/impl/IntValue.java
index edfc0f1f7002a0097ff837a9c7a1a83b906c9cab..5f6fc3212df40c69f3d1d2e5c0a2434ccca48a37 100644
--- a/tlatools/src/tlc2/value/impl/IntValue.java
+++ b/tlatools/src/tlc2/value/impl/IntValue.java
@@ -26,11 +26,11 @@ public class IntValue extends Value {
     }
   }
 
-	public final static IntValue ValNegOne = gen(-1);
+	public static final IntValue ValNegOne = gen(-1);
 	
-	public final static IntValue ValOne    = gen(1);
+	public static final IntValue ValOne    = gen(1);
 	
-	public final static IntValue ValZero   = gen(0);
+	public static final IntValue ValZero   = gen(0);
 
   public static final int nbits(int tmp) {
     int nb = 0;
@@ -45,6 +45,7 @@ public class IntValue extends Value {
 
   private IntValue(int i) { this.val = i; }
 
+  @Override
   public final byte getKind() { return INTVALUE; }
 
   // the number of bits needed to encode the value of this int
@@ -65,10 +66,11 @@ public class IntValue extends Value {
     return new IntValue(i);
   }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       if (obj instanceof IntValue) {
-        return this.val - ((IntValue)obj).val;
+        return Integer.compare(this.val, ((IntValue)obj).val);
       }
       if (!(obj instanceof ModelValue)) {
         Assert.fail("Attempted to compare integer " + Values.ppr(this.toString()) +
@@ -99,6 +101,7 @@ public class IntValue extends Value {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) +
@@ -111,6 +114,7 @@ public class IntValue extends Value {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       Assert.fail("Attempted to check if the integer " + Values.ppr(this.toString()) +
@@ -123,6 +127,7 @@ public class IntValue extends Value {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -137,6 +142,7 @@ public class IntValue extends Value {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (exs.length != 0) {
@@ -151,6 +157,7 @@ public class IntValue extends Value {
     }
   }
 
+  @Override
   public final int size() {
     try {
       Assert.fail("Attempted to compute the number of elements in the integer " +
@@ -163,14 +170,25 @@ public class IntValue extends Value {
     }
   }
 
+  @Override
+  public boolean mutates() {
+	  // finalized after construction.
+	  return true;
+  }
+
+  @Override
   public final boolean isNormalized() { return true; }
 
+  @Override
   public final Value normalize() { /*nop*/return this; }
 
+  @Override
   public final boolean isDefined() { return true; }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       return ((val instanceof IntValue) &&
@@ -189,6 +207,7 @@ public class IntValue extends Value {
 	}
 
   /* The fingerprint methods */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       return FP64.Extend(FP64.Extend(fp, INTVALUE), this.val);
@@ -199,9 +218,11 @@ public class IntValue extends Value {
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) { return this; }
 
   /* The string representation. */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean ignored) {
     try {
       return sb.append(this.val);
diff --git a/tlatools/src/tlc2/value/impl/IntervalValue.java b/tlatools/src/tlc2/value/impl/IntervalValue.java
index 48198debbfb008bca6224f68fdc4238e480c8209..f6b47041fa28d3baa84b87fd5633c9cbeb083f34 100644
--- a/tlatools/src/tlc2/value/impl/IntervalValue.java
+++ b/tlatools/src/tlc2/value/impl/IntervalValue.java
@@ -26,17 +26,24 @@ implements Enumerable, Reducible {
     this.high = high;
   }
 
+  @Override
   public final byte getKind() { return INTERVALVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
-      if (obj instanceof IntervalValue) {
-        IntervalValue intv = (IntervalValue)obj;
-        int cmp = this.size() - intv.size();
-        if (cmp != 0) return cmp;
-        if (this.size() == 0) return 0;
-        return this.low - intv.low;
-      }
+        if (obj instanceof IntervalValue) {
+				IntervalValue intv = (IntervalValue) obj;
+		        int cmp = this.size() - intv.size();
+		        if (cmp != 0) {
+					return cmp;
+				}
+				if (this.size() == 0) {
+					// empty intervals are equal, regardless of the low value
+					return 0;
+				}
+                return Integer.compare(this.low, intv.low);
+			}
       // Well, we have to convert them to sets and compare.
       return this.toSetEnum().compareTo(obj);
     }
@@ -62,6 +69,7 @@ implements Enumerable, Reducible {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       if (elem instanceof IntValue) {
@@ -82,6 +90,7 @@ implements Enumerable, Reducible {
     }
   }
 
+  @Override
   public Value isSubsetEq(Value other) {
     try {
       if (other instanceof IntervalValue) {
@@ -98,12 +107,22 @@ implements Enumerable, Reducible {
     }
   }
 
+  @Override
   public final boolean isFinite() { return true; }
 
+  @Override
   public final int size() {
     try {
-      if (this.high < this.low) return 0;
-      return this.high - this.low + 1;
+		if (this.high < this.low) {
+			return 0;
+		}
+		try {
+			return Math.addExact(Math.subtractExact(this.high, this.low), 1);
+		} catch (ArithmeticException e) {
+			Assert.fail("Size of interval value exceeds the maximum representable size (32bits): "
+			      + Values.ppr(this.toString()) + ".");
+			return 0; // unreachable, but it satisfies the compiler
+		}
     }
     catch (RuntimeException | OutOfMemoryError e) {
       if (hasSource()) { throw FingerprintException.getNewHead(this, e); }
@@ -125,6 +144,7 @@ implements Enumerable, Reducible {
 	}
   
   /* Return this - val.  */
+  @Override
   public final Value diff(Value val) {
     try {
       ValueVec diffElems = new ValueVec();
@@ -141,6 +161,7 @@ implements Enumerable, Reducible {
   }
 
   /* Return this \cap val. */
+  @Override
   public final Value cap(Value val) {
     try {
       ValueVec capElems = new ValueVec();
@@ -157,6 +178,7 @@ implements Enumerable, Reducible {
   }
 
   /* Return this \cup val.  */
+  @Override
   public final Value cup(Value set) {
     try {
       if (this.size() == 0) return set;
@@ -181,6 +203,7 @@ implements Enumerable, Reducible {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -195,6 +218,7 @@ implements Enumerable, Reducible {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (exs.length != 0) {
@@ -209,14 +233,19 @@ implements Enumerable, Reducible {
     }
   }
 
+  @Override
   public final boolean isNormalized() { return true; }
 
+  @Override
   public final Value normalize() { /*nop*/return this; }
 
+  @Override
   public final boolean isDefined() { return true; }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       return ((val instanceof IntervalValue) &&
@@ -237,6 +266,7 @@ implements Enumerable, Reducible {
 	}
 
   /* The fingerprint method */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       fp = FP64.Extend(fp, SETENUMVALUE);
@@ -253,6 +283,12 @@ implements Enumerable, Reducible {
     }
   }
 
+  @Override
+  public boolean mutates() {
+	  return false;
+  }
+  
+  @Override
   public final IValue permute(IMVPerm perm) {
     return this;
   }
@@ -268,6 +304,7 @@ implements Enumerable, Reducible {
   }
 
   /* The string representation */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, final boolean ignored) {
     try {
       if (this.low <= this.high) {
@@ -303,6 +340,7 @@ implements Enumerable, Reducible {
         return null; // make compiler happy
 	}
     
+  @Override
   public final ValueEnumeration elements() {
     try {
       return new Enumerator();
@@ -316,8 +354,10 @@ implements Enumerable, Reducible {
   final class Enumerator implements ValueEnumeration {
     int index = low;
 
+    @Override
     public final void reset() { this.index = low; }
 
+    @Override
     public final Value nextElement() {
       if (this.index <= high) {
     	  if (coverage) { cm.incSecondary(); }
diff --git a/tlatools/src/tlc2/value/impl/LazyValue.java b/tlatools/src/tlc2/value/impl/LazyValue.java
index 9c4e3c5a62b1af892c8bcd20ebc6c4b8e01113e1..81ee51d9413883138c546f34d4be4bfb2ea95db9 100644
--- a/tlatools/src/tlc2/value/impl/LazyValue.java
+++ b/tlatools/src/tlc2/value/impl/LazyValue.java
@@ -78,8 +78,10 @@ public class LazyValue extends Value {
 	  return this.val;
   }
  
+  @Override
   public final byte getKind() { return LAZYVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       if (this.val == null || this.val == UndefValue.ValUndef) {
@@ -106,6 +108,7 @@ public class LazyValue extends Value {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       if (this.val == null || this.val == UndefValue.ValUndef) {
@@ -119,6 +122,7 @@ public class LazyValue extends Value {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       if (this.val == null || this.val == UndefValue.ValUndef) {
@@ -132,6 +136,7 @@ public class LazyValue extends Value {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (this.val == null || this.val == UndefValue.ValUndef) {
@@ -145,6 +150,7 @@ public class LazyValue extends Value {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (this.val == null || this.val == UndefValue.ValUndef) {
@@ -158,6 +164,7 @@ public class LazyValue extends Value {
     }
   }
 
+  @Override
   public final int size() {
     try {
       if (this.val == null || this.val == UndefValue.ValUndef) {
@@ -183,6 +190,7 @@ public class LazyValue extends Value {
   }
 
   /* Nothing to normalize. */
+  @Override
   public final boolean isNormalized() {
     try {
       if (this.val == null || this.val == UndefValue.ValUndef) {
@@ -196,6 +204,7 @@ public class LazyValue extends Value {
     }
   }
 
+  @Override
   public final Value normalize() {
     try {
       if (this.val == null || this.val == UndefValue.ValUndef) {
@@ -210,8 +219,10 @@ public class LazyValue extends Value {
     }
   }
 
+  @Override
   public final boolean isDefined() { return true; }
 
+  @Override
   public final IValue deepCopy() {
     try {
       if (this.val == null || this.val == UndefValue.ValUndef) return this;
@@ -223,6 +234,7 @@ public class LazyValue extends Value {
     }
   }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       if (this.val == null || this.val == UndefValue.ValUndef) {
@@ -237,6 +249,7 @@ public class LazyValue extends Value {
   }
 
   /* The fingerprint method */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       if (this.val == null || this.val == UndefValue.ValUndef) {
@@ -250,6 +263,7 @@ public class LazyValue extends Value {
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) {
     try {
       if (this.val == null || this.val == UndefValue.ValUndef) {
@@ -264,6 +278,7 @@ public class LazyValue extends Value {
   }
 
   /* The string representation of the value. */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       if (this.val == null || this.val == UndefValue.ValUndef) {
diff --git a/tlatools/src/tlc2/value/impl/MVPerm.java b/tlatools/src/tlc2/value/impl/MVPerm.java
index 17ce861766890bc0f15d995f7cd5303b42b181b1..ac04e48c0ce83dac470fd0b5ab802b78e1bb2bee 100644
--- a/tlatools/src/tlc2/value/impl/MVPerm.java
+++ b/tlatools/src/tlc2/value/impl/MVPerm.java
@@ -5,6 +5,9 @@
 
 package tlc2.value.impl;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import tlc2.value.IMVPerm;
 import tlc2.value.IModelValue;
 import tlc2.value.IValue;
@@ -47,8 +50,10 @@ public final class MVPerm implements IMVPerm {
     return res;
   }
   
+  @Override
   public final int size() { return this.count; }
 
+  @Override
   public final IValue get(IValue k) {
     return this.elems[((ModelValue) k).index];
   }
@@ -90,6 +95,24 @@ public final class MVPerm implements IMVPerm {
     }
     return res;
   }
+  
+  /**
+   * Consider caching if this method is used frequently; currently it is used once per instance per
+   * 	execution of TLC, during initial state setup / expansion.
+   * 
+   * @return a {@code List} of all {@link ModelValue} instances held by this permutation.
+   */
+  public List<ModelValue> getAllModelValues() {
+	  final List<ModelValue> values = new ArrayList<>();
+	  
+	  for (int i = 0; i < elems.length; i++) {
+		  if (elems[i] != null) {
+			  values.add(elems[i]);
+		  }
+	  }
+	  
+	  return values;
+  }
 
   public final String toString() {
     StringBuffer sb = new StringBuffer("[");
diff --git a/tlatools/src/tlc2/value/impl/MethodValue.java b/tlatools/src/tlc2/value/impl/MethodValue.java
index bc83114d3c14d14be30720e2c5804cabb209cc6a..2674782629d468ae96332aa9dca3fe7baaf8e2ee 100644
--- a/tlatools/src/tlc2/value/impl/MethodValue.java
+++ b/tlatools/src/tlc2/value/impl/MethodValue.java
@@ -6,6 +6,8 @@
 
 package tlc2.value.impl;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.reflect.InvocationTargetException;
@@ -25,22 +27,28 @@ import util.Assert.TLCRuntimeException;
 import util.WrongInvocationException;
 
 public class MethodValue extends OpValue implements Applicable {
+
+	public static Value get(final Method md) {
+		return get(md, 0);
+	}
 	
-	public static MethodValue get(final Method md) {
-		final MethodValue mv = new MethodValue(md);
+	public static Value get(final Method md, int minLevel) {
+		final MethodValue mv = new MethodValue(md, minLevel);
 		// Eagerly evaluate the constant operator if possible (zero arity) to only
 		// evaluate once at startup and not during state exploration.
 		final int acnt = md.getParameterTypes().length;
     	final boolean isConstant = (acnt == 0) && Modifier.isFinal(md.getModifiers());
-    	return isConstant ? (MethodValue) mv.apply(Tool.EmptyArgs, EvalControl.Clear) : mv;
+    	return isConstant ? mv.apply(Tool.EmptyArgs, EvalControl.Clear) : mv;
 	}
 	
   private final MethodHandle mh;
   private final Method md;
+  private final int minLevel;
 
   /* Constructor */
-	private MethodValue(final Method md) {
+	private MethodValue(final Method md, final int minLevel) {
 		this.md = md;
+		this.minLevel = minLevel;
 		try {
 			final int parameterCount = this.md.getParameterCount();
 			if (parameterCount > 0) {
@@ -61,8 +69,17 @@ public class MethodValue extends OpValue implements Applicable {
 		}
 	}
 
+  @Override
   public final byte getKind() { return METHODVALUE; }
 
+  @Override
+  public final IValue initialize() {
+	  this.deepNormalize();
+	  // Do not call fingerprint as a MethodValue has no fingerprint.
+	  return this;
+  }
+  
+  @Override
   public final int compareTo(Object obj) {
     try {
       Assert.fail("Attempted to compare operator " + this.toString() +
@@ -87,6 +104,7 @@ public class MethodValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       Assert.fail("Attempted to check if the value:\n" + elem == null ? "null" : Values.ppr(elem.toString()) +
@@ -99,6 +117,7 @@ public class MethodValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       Assert.fail("Attempted to check if the operator " + this.toString() +
@@ -111,6 +130,7 @@ public class MethodValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value apply(Value arg, int control) {
     try {
       throw new WrongInvocationException("It is a TLC bug: Should use the other apply method.");
@@ -121,6 +141,7 @@ public class MethodValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value apply(Value[] args, int control) {
     try {
       Value res = null;
@@ -144,7 +165,15 @@ public class MethodValue extends OpValue implements Applicable {
         	  throw (EvalException) e;
           } else
           {
-              Assert.fail(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, new String[]{this.md.toString(), e.getMessage()});
+              String message = e.getMessage();
+              if (message == null) {
+				  // Try to pass some information along (i.e. the full stack-trace) in cases where
+				  // message is null.
+		          final StringWriter sw = new StringWriter();
+            	  e.printStackTrace(new PrintWriter(sw));
+            	  message = sw.toString();
+              }
+			Assert.fail(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, new String[]{this.md.toString(), message});
           }
       }
       return res;
@@ -155,6 +184,7 @@ public class MethodValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value select(Value arg) {
     try {
       throw new WrongInvocationException("It is a TLC bug: Attempted to call MethodValue.select().");
@@ -165,6 +195,7 @@ public class MethodValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       Assert.fail("Attempted to appy EXCEPT construct to the operator " +
@@ -177,6 +208,7 @@ public class MethodValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       Assert.fail("Attempted to apply EXCEPT construct to the operator " +
@@ -189,6 +221,7 @@ public class MethodValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value getDomain() {
     try {
       Assert.fail("Attempted to compute the domain of the operator " +
@@ -201,6 +234,7 @@ public class MethodValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final int size() {
     try {
       Assert.fail("Attempted to compute the number of elements in the operator " +
@@ -214,6 +248,7 @@ public class MethodValue extends OpValue implements Applicable {
   }
 
   /* Should never normalize an operator. */
+  @Override
   public final boolean isNormalized() {
     try {
       throw new WrongInvocationException("It is a TLC bug: Attempted to normalize an operator.");
@@ -224,6 +259,7 @@ public class MethodValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value normalize() {
     try {
       throw new WrongInvocationException("It is a TLC bug: Attempted to normalize an operator.");
@@ -234,10 +270,13 @@ public class MethodValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final boolean isDefined() { return true; }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       throw new WrongInvocationException("It is a TLC bug: Attempted to initialize an operator.");
@@ -249,6 +288,7 @@ public class MethodValue extends OpValue implements Applicable {
   }
 
   /* String representation of the value.  */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean ignored) {
     try {
       return sb.append("<Java Method: " + this.md + ">");
@@ -258,5 +298,8 @@ public class MethodValue extends OpValue implements Applicable {
       else { throw e; }
     }
   }
-
+  
+  public final int getMinLevel() {
+	  return minLevel;
+  }
 }
diff --git a/tlatools/src/tlc2/value/impl/ModelValue.java b/tlatools/src/tlc2/value/impl/ModelValue.java
index 7c87331751ed43d6578107d45a1e33e07e6f5ef2..a044fbeeb52d16b85e3b94c6dae6ba8c61ed5715 100644
--- a/tlatools/src/tlc2/value/impl/ModelValue.java
+++ b/tlatools/src/tlc2/value/impl/ModelValue.java
@@ -89,7 +89,7 @@ public class ModelValue extends Value implements IModelValue {
         && (val.charAt(1) == '_')) {
       this.type = val.charAt(0) ;
       }
-     else { this.type = 0 ; } ;
+     else { this.type = 0 ; }
   }
 
   /* Make str a new model value, if it is not one yet.  */
@@ -111,8 +111,10 @@ public class ModelValue extends Value implements IModelValue {
     }
   }
 
+  @Override
   public final byte getKind() { return MODELVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       if (obj instanceof ModelValue) {
@@ -131,7 +133,7 @@ public class ModelValue extends Value implements IModelValue {
       if (this.type == 0) {
         return (obj instanceof ModelValue &&
           this.val.equals(((ModelValue)obj).val));
-       };
+       }
       if (obj instanceof ModelValue) {
         ModelValue mobj = (ModelValue) obj ;
         if (   (mobj.type == this.type)
@@ -143,8 +145,8 @@ public class ModelValue extends Value implements IModelValue {
                       + "of the differently-typed model values "
                         + Values.ppr(this.toString()) + " and "
                         + Values.ppr(mobj.toString()));
-          } ;
-       } ;
+          }
+      }
       Assert.fail("Attempted to check equality of typed model value "
                    + Values.ppr(this.toString()) + " and non-model value\n"
                    + Values.ppr(obj.toString())) ;
@@ -168,7 +170,7 @@ public class ModelValue extends Value implements IModelValue {
                    + Values.ppr(this.toString()) + " and the non-model value\n"
                    + Values.ppr(obj.toString())) ;
 
-       } ;
+       }
       return false ;
     }
     catch (RuntimeException | OutOfMemoryError e) {
@@ -185,7 +187,7 @@ public class ModelValue extends Value implements IModelValue {
                    + " is an element of\n"
                    + Values.ppr(obj.toString())) ;
 
-       } ;
+       }
       return false ;
     }
     catch (RuntimeException | OutOfMemoryError e) {
@@ -194,6 +196,7 @@ public class ModelValue extends Value implements IModelValue {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) +
@@ -206,6 +209,7 @@ public class ModelValue extends Value implements IModelValue {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       Assert.fail("Attempted to check if the model value " + Values.ppr(this.toString()) +
@@ -218,6 +222,7 @@ public class ModelValue extends Value implements IModelValue {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -232,6 +237,7 @@ public class ModelValue extends Value implements IModelValue {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (exs.length != 0) {
@@ -246,6 +252,7 @@ public class ModelValue extends Value implements IModelValue {
     }
   }
 
+  @Override
   public final int size() {
     try {
       Assert.fail("Attempted to compute the number of elements in the model value " +
@@ -258,14 +265,24 @@ public class ModelValue extends Value implements IModelValue {
     }
   }
 
+  @Override
+  public boolean mutates() {
+	  return false;
+  }
+
+  @Override
   public final boolean isNormalized() { return true; }
 
+  @Override
   public final Value normalize() { /*nop*/return this; }
 
+  @Override
   public final boolean isDefined() { return true; }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       return ((val instanceof ModelValue) &&
@@ -284,6 +301,7 @@ public class ModelValue extends Value implements IModelValue {
 	}
 
   /* The fingerprint methods */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       return this.val.fingerPrint(FP64.Extend(fp, MODELVALUE));
@@ -294,6 +312,7 @@ public class ModelValue extends Value implements IModelValue {
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) {
     try {
       IValue res = perm.get(this);
@@ -307,6 +326,7 @@ public class ModelValue extends Value implements IModelValue {
   }
 
   /* The string representation. */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean ignored) {
     try {
       return sb.append(this.val);
diff --git a/tlatools/src/tlc2/value/impl/OpLambdaValue.java b/tlatools/src/tlc2/value/impl/OpLambdaValue.java
index a4356f8da11a1b9fd76ff10e18e83b69fadbac70..24c4d13bf63fadc8845da1ae0e3660894cbb7a53 100644
--- a/tlatools/src/tlc2/value/impl/OpLambdaValue.java
+++ b/tlatools/src/tlc2/value/impl/OpLambdaValue.java
@@ -40,9 +40,15 @@ public class OpLambdaValue extends OpValue implements Applicable {
 	this(op, tool, con, state, pstate);
 	this.cm = cm;
   }
+  
+  public OpLambdaValue(OpLambdaValue other, ITool tool) {
+	  this(other.opDef, tool, other.con, other.state, other.pstate);
+  }
 
+  @Override
   public final byte getKind() { return OPLAMBDAVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       Assert.fail("Attempted to compare operator " + Values.ppr(this.toString()) +
@@ -67,6 +73,7 @@ public class OpLambdaValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) +
@@ -79,6 +86,7 @@ public class OpLambdaValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       Assert.fail("Attempted to check if the operator " + Values.ppr(this.toString()) +
@@ -91,6 +99,7 @@ public class OpLambdaValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value apply(Value arg, int control) {
     try {
       throw new WrongInvocationException("Should use the other apply method.");
@@ -101,6 +110,7 @@ public class OpLambdaValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value apply(Value[] args, int control) {
     try {
       int alen = this.opDef.getArity();
@@ -122,6 +132,7 @@ public class OpLambdaValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value select(Value arg) {
     try {
       throw new WrongInvocationException("Error(TLC): attempted to call OpLambdaValue.select().");
@@ -132,6 +143,7 @@ public class OpLambdaValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       Assert.fail("Attempted to appy EXCEPT construct to the operator " +
@@ -144,6 +156,7 @@ public class OpLambdaValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       Assert.fail("Attempted to apply EXCEPT construct to the operator " +
@@ -156,6 +169,7 @@ public class OpLambdaValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value getDomain() {
     try {
       Assert.fail("Attempted to compute the domain of the operator " +
@@ -168,6 +182,7 @@ public class OpLambdaValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final int size() {
     try {
       Assert.fail("Attempted to compute the number of elements in the operator " +
@@ -181,6 +196,7 @@ public class OpLambdaValue extends OpValue implements Applicable {
   }
 
   /* Should never normalize an operator. */
+  @Override
   public final boolean isNormalized() {
     try {
       throw new WrongInvocationException("Should not normalize an operator.");
@@ -191,6 +207,7 @@ public class OpLambdaValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value normalize() {
     try {
       throw new WrongInvocationException("Should not normalize an operator.");
@@ -201,10 +218,13 @@ public class OpLambdaValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final boolean isDefined() { return true; }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       throw new WrongInvocationException("Should not initialize an operator.");
@@ -216,6 +236,7 @@ public class OpLambdaValue extends OpValue implements Applicable {
   }
 
   /* String representation of the value.  */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean ignored) {
     try {
       String opName = this.opDef.getName().toString();
diff --git a/tlatools/src/tlc2/value/impl/OpRcdValue.java b/tlatools/src/tlc2/value/impl/OpRcdValue.java
index 106e60b36a029262e32842f9f0c12e543010d2eb..132de719487848f99a2735e1428aaf048f945958 100644
--- a/tlatools/src/tlc2/value/impl/OpRcdValue.java
+++ b/tlatools/src/tlc2/value/impl/OpRcdValue.java
@@ -28,8 +28,10 @@ public class OpRcdValue extends OpValue implements Applicable {
     this.values = values;
   }
 
+  @Override
   public final byte getKind() { return OPRCDVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       Assert.fail("Attempted to compare operator " + Values.ppr(this.toString()) +
@@ -54,6 +56,7 @@ public class OpRcdValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) +
@@ -66,6 +69,7 @@ public class OpRcdValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       Assert.fail("Attempted to check if the operator " + Values.ppr(this.toString()) +
@@ -94,6 +98,7 @@ public class OpRcdValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value apply(Value arg, int control) {
     try {
       throw new WrongInvocationException("Should use the other apply method.");
@@ -104,6 +109,7 @@ public class OpRcdValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value apply(Value[] args, int control) {
     try {
       int sz = this.domain.size();
@@ -138,6 +144,7 @@ public class OpRcdValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value select(Value arg) {
     try {
       Assert.fail("Attempted to call OpRcdValue.select(). This is a TLC bug.");
@@ -149,6 +156,7 @@ public class OpRcdValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       Assert.fail("Attempted to appy EXCEPT construct to the operator " +
@@ -161,6 +169,7 @@ public class OpRcdValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       Assert.fail("Attempted to apply EXCEPT construct to the operator " +
@@ -173,6 +182,7 @@ public class OpRcdValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value getDomain() {
     try {
       Assert.fail("Attempted to compute the domain of the operator " +
@@ -185,6 +195,7 @@ public class OpRcdValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final int size() {
     try {
       Assert.fail("Attempted to compute the number of elements in the operator " +
@@ -198,6 +209,7 @@ public class OpRcdValue extends OpValue implements Applicable {
   }
 
   /* Should never normalize an operator. */
+  @Override
   public final boolean isNormalized() {
     try {
       throw new WrongInvocationException("Should not normalize an operator.");
@@ -208,6 +220,7 @@ public class OpRcdValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final Value normalize() {
     try {
       throw new WrongInvocationException("Should not normalize an operator.");
@@ -218,6 +231,7 @@ public class OpRcdValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final boolean isDefined() {
     try {
       boolean defined = true;
@@ -232,8 +246,10 @@ public class OpRcdValue extends OpValue implements Applicable {
     }
   }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       throw new WrongInvocationException("Should not initialize an operator.");
@@ -245,6 +261,7 @@ public class OpRcdValue extends OpValue implements Applicable {
   }
 
   /* Pretty-printing  */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       sb.append("{ ");
diff --git a/tlatools/src/tlc2/value/impl/RecordValue.java b/tlatools/src/tlc2/value/impl/RecordValue.java
index 094f312c798022cbda43920724713a2918b50e73..945f5b8fc8b2043f69d21ad69b842c89a8a87d24 100644
--- a/tlatools/src/tlc2/value/impl/RecordValue.java
+++ b/tlatools/src/tlc2/value/impl/RecordValue.java
@@ -9,25 +9,30 @@ package tlc2.value.impl;
 import java.io.EOFException;
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.Map;
 
+import tla2sany.semantic.OpDeclNode;
 import tlc2.output.EC;
 import tlc2.output.MP;
 import tlc2.tool.FingerprintException;
+import tlc2.tool.TLCState;
 import tlc2.tool.coverage.CostModel;
 import tlc2.util.FP64;
 import tlc2.value.IMVPerm;
 import tlc2.value.IValue;
 import tlc2.value.IValueInputStream;
 import tlc2.value.IValueOutputStream;
+import tlc2.value.ValueInputStream;
 import tlc2.value.Values;
 import util.Assert;
+import util.TLAConstants;
 import util.UniqueString;
 
 public class RecordValue extends Value implements Applicable {
   public final UniqueString[] names;   // the field names
   public final Value[] values;         // the field values
   private boolean isNorm;
-public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0], new Value[0], true);
+public static final RecordValue EmptyRcd = new RecordValue(new UniqueString[0], new Value[0], true);
 
   /* Constructor */
   public RecordValue(UniqueString[] names, Value[] values, boolean isNorm) {
@@ -40,9 +45,33 @@ public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0],
 	  this(names, values, isNorm);
 	  this.cm = cm;
   }
+  
+  public RecordValue(UniqueString name, Value v, boolean isNorm) {
+	  this(new UniqueString[] {name}, new Value[] {v}, isNorm);
+  }
+  
+  public RecordValue(UniqueString name, Value v) {
+	  this(new UniqueString[] {name}, new Value[] {v}, false);
+  }
+
+  public RecordValue(final TLCState state) {
+		final OpDeclNode[] vars = state.getVars();
+		
+		this.names = new UniqueString[vars.length];
+		this.values = new Value[vars.length];
+
+		for (int i = 0; i < vars.length; i++) {
+			this.names[i] = vars[i].getName();
+			this.values[i] = (Value) state.lookup(this.names[i]); 
+		}
 
+		this.isNorm = false;
+  }
+
+  @Override
   public final byte getKind() { return RECORDVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       RecordValue rcd = obj instanceof Value ? (RecordValue) ((Value)obj).toRcd() : null;
@@ -97,6 +126,7 @@ public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0],
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       Assert.fail("Attempted to check if element:\n" + Values.ppr(elem.toString()) +
@@ -109,8 +139,10 @@ public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0],
     }
   }
 
+  @Override
   public final boolean isFinite() { return true; }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -149,6 +181,7 @@ public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0],
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       Value res = this;
@@ -184,6 +217,7 @@ public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0],
         return new FcnRcdValue(dom, this.values, this.isNormalized(), cm);
 	}
 
+  @Override
   public final int size() {
     try {
       return this.names.length;
@@ -194,6 +228,7 @@ public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0],
     }
   }
 
+  @Override
   public final Value apply(Value arg, int control) {
     try {
       if (!(arg instanceof StringValue)) {
@@ -217,6 +252,7 @@ public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0],
     }
   }
 
+  @Override
   public final Value apply(Value[] args, int control) {
     try {
       if (args.length != 1) {
@@ -231,6 +267,7 @@ public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0],
   }
 
   /* This method returns the named component of the record. */
+  @Override
   public final Value select(Value arg) {
     try {
       if (!(arg instanceof StringValue)) {
@@ -252,6 +289,7 @@ public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0],
     }
   }
 
+  @Override
   public final Value getDomain() {
     try {
     	Value[] dElems = new Value[this.names.length];
@@ -287,8 +325,10 @@ public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0],
     }
   }
 
+  @Override
   public final boolean isNormalized() { return this.isNorm; }
 
+  @Override
   public final Value normalize() {
     try {
       if (!this.isNorm) {
@@ -347,6 +387,7 @@ public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0],
 	    }
   }
 
+  @Override
   public final boolean isDefined() {
     try {
       boolean defined = true;
@@ -361,6 +402,7 @@ public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0],
     }
   }
 
+  @Override
   public final IValue deepCopy() {
     try {
     	Value[] vals = new Value[this.values.length];
@@ -382,6 +424,7 @@ public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0],
     }
   }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       boolean canAssign = ((val instanceof RecordValue) &&
@@ -425,6 +468,7 @@ public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0],
 	}
 
   /* The fingerprint methods.  */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       this.normalize();
@@ -446,6 +490,7 @@ public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0],
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) {
     try {
       this.normalize();
@@ -468,18 +513,19 @@ public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0],
   }
 
   /* The string representation */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       int len = this.names.length;
 
       sb.append("[");
       if (len > 0) {
-        sb.append(this.names[0] + " |-> ");
+        sb.append(this.names[0] + TLAConstants.RECORD_ARROW);
         sb = this.values[0].toString(sb, offset, swallow);
       }
       for (int i = 1; i < len; i++) {
         sb.append(", ");
-        sb.append(this.names[i] + " |-> ");
+        sb.append(this.names[i] + TLAConstants.RECORD_ARROW);
         sb = this.values[i].toString(sb, offset, swallow);
       }
       return sb.append("]");
@@ -516,4 +562,31 @@ public final static RecordValue EmptyRcd = new RecordValue(new UniqueString[0],
 		vos.assign(res, index);
 		return res;
 	}
+
+	public static IValue createFrom(final ValueInputStream vos, final Map<String, UniqueString> tbl) throws EOFException, IOException {
+		final int index = vos.getIndex();
+		boolean isNorm = true;
+		int len = vos.readInt();
+		if (len < 0) {
+			len = -len;
+			isNorm = false;
+		}
+		final UniqueString[] names = new UniqueString[len];
+		final Value[] vals = new Value[len];
+		for (int i = 0; i < len; i++) {
+			final byte kind1 = vos.readByte();
+			if (kind1 == DUMMYVALUE) {
+				final int index1 = vos.readNat();
+				names[i] = vos.getValue(index1);
+			} else {
+				final int index1 = vos.getIndex();
+				names[i] = UniqueString.read(vos.getInputStream(), tbl);
+				vos.assign(names[i], index1);
+			}
+			vals[i] = (Value) vos.read(tbl);
+		}
+		final Value res = new RecordValue(names, vals, isNorm);
+		vos.assign(res, index);
+		return res;
+	}
 }
diff --git a/tlatools/src/tlc2/value/impl/Reducible.java b/tlatools/src/tlc2/value/impl/Reducible.java
index c44a2d1a5a2c59aa58420edd6522a4d4fd760d65..d9183d8d90e642e6c951d0fc2742a97a1a538f7a 100644
--- a/tlatools/src/tlc2/value/impl/Reducible.java
+++ b/tlatools/src/tlc2/value/impl/Reducible.java
@@ -7,12 +7,12 @@ package tlc2.value.impl;
 
 public interface Reducible {
 
-  public int size();
-  public boolean member(Value elem);
-  public Value diff(Value val);
-  public Value cap(Value val);
-  public Value cup(Value val);
+  int size();
+  boolean member(Value elem);
+  Value diff(Value val);
+  Value cap(Value val);
+  Value cup(Value val);
 
-  public ValueEnumeration elements();
+  ValueEnumeration elements();
 }
 
diff --git a/tlatools/src/tlc2/value/impl/SetCapValue.java b/tlatools/src/tlc2/value/impl/SetCapValue.java
index df1dc81c35c726627c4b87e59dcb3bef714a37f9..ed59231e3c0031b5d1b989dda90d1abe5d0c3756 100644
--- a/tlatools/src/tlc2/value/impl/SetCapValue.java
+++ b/tlatools/src/tlc2/value/impl/SetCapValue.java
@@ -28,8 +28,10 @@ public class SetCapValue extends EnumerableValue implements Enumerable {
     this.capSet = null;
   }
 
+  @Override
   public final byte getKind() { return SETCAPVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       this.convertAndCache();
@@ -52,6 +54,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       return (this.set1.member(elem) && this.set2.member(elem));
@@ -62,6 +65,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       if (!this.set1.isFinite() && !this.set2.isFinite()) {
@@ -75,6 +79,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -88,6 +93,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (exs.length != 0) {
@@ -101,6 +107,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final int size() {
     try {
       this.convertAndCache();
@@ -112,6 +119,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean isNormalized() {
     try {
       if (this.capSet == null || this.capSet == SetEnumValue.DummyEnum) {
@@ -125,6 +133,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value normalize() {
     try {
       if (this.capSet == null || this.capSet == SetEnumValue.DummyEnum) {
@@ -142,6 +151,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean isDefined() {
     try {
       return this.set1.isDefined() && this.set2.isDefined();
@@ -152,8 +162,10 @@ public class SetCapValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       return this.equals(val);
@@ -170,6 +182,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable {
 	}
 
   /* The fingerprint methods */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       this.convertAndCache();
@@ -181,6 +194,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) {
     try {
       this.convertAndCache();
@@ -244,6 +258,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable {
   }
 
   /* String representation of this value.  */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       try {
@@ -265,6 +280,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final ValueEnumeration elements() {
     try {
       if (this.capSet == null || this.capSet == SetEnumValue.DummyEnum) {
@@ -298,8 +314,10 @@ public class SetCapValue extends EnumerableValue implements Enumerable {
       }
     }
 
+    @Override
     public final void reset() { this.enum1.reset(); }
 
+    @Override
     public final Value nextElement() {
     	Value elem = this.enum1.nextElement();
       while (elem != null) {
diff --git a/tlatools/src/tlc2/value/impl/SetCupValue.java b/tlatools/src/tlc2/value/impl/SetCupValue.java
index 265140102d21593fb24a221d535386def7143f52..15a183ef9d68651291d2dc8161380c4018f75e0e 100644
--- a/tlatools/src/tlc2/value/impl/SetCupValue.java
+++ b/tlatools/src/tlc2/value/impl/SetCupValue.java
@@ -34,8 +34,10 @@ public class SetCupValue extends EnumerableValue implements Enumerable {
 	this.cm = cm;
   }
 
+  @Override
   public final byte getKind() { return SETCUPVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       this.convertAndCache();
@@ -58,6 +60,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       return this.set1.member(elem) || this.set2.member(elem);
@@ -68,6 +71,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       return this.set1.isFinite() && this.set2.isFinite();
@@ -78,6 +82,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -91,6 +96,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (exs.length != 0) {
@@ -104,6 +110,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final int size() {
     try {
       this.convertAndCache();
@@ -115,6 +122,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean isNormalized() {
     try {
       return (this.cupSet != null &&
@@ -127,6 +135,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value normalize() {
     try {
       if (this.cupSet != null && this.cupSet != SetEnumValue.DummyEnum) {
@@ -158,6 +167,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable {
 	    }
   }
   
+  @Override
   public final boolean isDefined() {
     try {
       return this.set1.isDefined() && this.set2.isDefined();
@@ -168,8 +178,10 @@ public class SetCupValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       return this.equals(val);
@@ -186,6 +198,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable {
 	}
 
   /* The fingerprint methods */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       this.convertAndCache();
@@ -197,6 +210,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) {
     try {
       this.convertAndCache();
@@ -242,6 +256,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable {
   }
 
   /* String representation of the value. */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       try {
@@ -263,6 +278,7 @@ public class SetCupValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final ValueEnumeration elements() {
     try {
       if (this.cupSet == null || this.cupSet == SetEnumValue.DummyEnum) {
@@ -294,11 +310,13 @@ public class SetCupValue extends EnumerableValue implements Enumerable {
       }
     }
 
+    @Override
     public final void reset() {
       this.enum1.reset();
       this.enum2.reset();
     }
 
+    @Override
     public final Value nextElement() {
   	  if (coverage) { cm.incSecondary(); }
   	Value elem = this.enum1.nextElement();
diff --git a/tlatools/src/tlc2/value/impl/SetDiffValue.java b/tlatools/src/tlc2/value/impl/SetDiffValue.java
index 89698c2b9fed1a53a49707b0170c196ccf522595..0778ce08b88f5f6b4af985386b8294955a606211 100644
--- a/tlatools/src/tlc2/value/impl/SetDiffValue.java
+++ b/tlatools/src/tlc2/value/impl/SetDiffValue.java
@@ -28,8 +28,10 @@ public class SetDiffValue extends EnumerableValue implements Enumerable {
     this.diffSet = null;
   }
 
+  @Override
   public final byte getKind() { return SETDIFFVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       this.convertAndCache();
@@ -52,6 +54,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       return (this.set1.member(elem) && !this.set2.member(elem));
@@ -62,6 +65,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       if (this.set1.isFinite()) {
@@ -78,6 +82,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -91,6 +96,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (exs.length != 0) {
@@ -104,6 +110,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final int size() {
     try {
       this.convertAndCache();
@@ -115,6 +122,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean isNormalized() {
     try {
       if (this.diffSet == null || this.diffSet == SetEnumValue.DummyEnum) {
@@ -128,6 +136,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value normalize() {
     try {
       if (this.diffSet == null || this.diffSet == SetEnumValue.DummyEnum) {
@@ -163,6 +172,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable {
 	    }
   }
 
+  @Override
   public final boolean isDefined() {
     try {
       return this.set1.isDefined() && this.set2.isDefined();
@@ -173,8 +183,10 @@ public class SetDiffValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       return this.equals(val);
@@ -191,6 +203,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable {
 	}
 
   /* The fingerprint methods */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       this.convertAndCache();
@@ -202,6 +215,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) {
     try {
       this.convertAndCache();
@@ -247,6 +261,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable {
   }
 
   /* The string representation  */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       try {
@@ -268,6 +283,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final ValueEnumeration elements() {
     try {
       if (this.diffSet == null || this.diffSet == SetEnumValue.DummyEnum) {
@@ -295,8 +311,10 @@ public class SetDiffValue extends EnumerableValue implements Enumerable {
       }
     }
 
+    @Override
     public final void reset() { this.enum1.reset(); }
 
+    @Override
     public final Value nextElement() {
     	Value elem = this.enum1.nextElement();
       while (elem != null) {
diff --git a/tlatools/src/tlc2/value/impl/SetEnumValue.java b/tlatools/src/tlc2/value/impl/SetEnumValue.java
index 213199f2526b1f0996c53d8d24bfcf15190104a0..18d8e2701a41e1de096d02b404d345f961660c61 100644
--- a/tlatools/src/tlc2/value/impl/SetEnumValue.java
+++ b/tlatools/src/tlc2/value/impl/SetEnumValue.java
@@ -7,6 +7,7 @@
 package tlc2.value.impl;
 
 import java.io.IOException;
+import java.util.Map;
 
 import tlc2.tool.FingerprintException;
 import tlc2.tool.coverage.CostModel;
@@ -16,15 +17,18 @@ import tlc2.value.IValue;
 import tlc2.value.IValueInputStream;
 import tlc2.value.IValueOutputStream;
 import tlc2.value.RandomEnumerableValues;
+import tlc2.value.ValueInputStream;
 import tlc2.value.Values;
 import util.Assert;
+import util.UniqueString;
 
+@SuppressWarnings("serial")
 public class SetEnumValue extends EnumerableValue
 implements Enumerable, Reducible {
   public ValueVec elems;         // the elements of the set
   private boolean isNorm;        // normalized?
-public final static SetEnumValue EmptySet = new SetEnumValue(new ValueVec(0), true);
-public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, true);
+public static final SetEnumValue EmptySet = new SetEnumValue(new ValueVec(0), true);
+public static final SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, true);
 
   /* Constructor */
   public SetEnumValue(Value[] elems, boolean isNorm) {
@@ -54,9 +58,29 @@ public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, tr
 	  this();
 	  this.cm = cm;
   }
+  
+  // See IValue#isAtom except that this is for sets of atoms.
+  public final boolean isSetOfAtoms() {
+      final int len = this.elems.size();
+      for (int i = 0; i < len; i++) {
+    	  final Value v = this.elems.elementAt(i);
+    	  if (v instanceof SetEnumValue) {
+    		  // Sets of sets of sets... of atoms.
+    		  final SetEnumValue sev = (SetEnumValue) v;
+    		  if (!sev.isSetOfAtoms()) {
+    			  return false;
+    		  }
+    	  } else if (!v.isAtom()) {
+    		  return false;
+    	  }
+      }
+      return true;
+  }
 
+  @Override
   public final byte getKind() { return SETENUMVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       SetEnumValue set = obj instanceof Value ? (SetEnumValue) ((Value)obj).toSetEnum() : null;
@@ -110,6 +134,7 @@ public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, tr
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       return this.elems.search(elem, this.isNorm);
@@ -120,8 +145,10 @@ public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, tr
     }
   }
 
+  @Override
   public final boolean isFinite() { return true; }
 
+  @Override
   public final Value diff(Value val) {
     try {
       int sz = this.elems.size();
@@ -140,6 +167,7 @@ public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, tr
     }
   }
 
+  @Override
   public final Value cap(Value val) {
     try {
       int sz = this.elems.size();
@@ -158,6 +186,7 @@ public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, tr
     }
   }
 
+  @Override
   public final Value cup(Value set) {
     try {
       int sz = this.elems.size();
@@ -184,6 +213,7 @@ public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, tr
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -197,6 +227,7 @@ public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, tr
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (exs.length != 0) {
@@ -210,6 +241,7 @@ public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, tr
     }
   }
 
+  @Override
   public final int size() {
     try {
       this.normalize();
@@ -222,8 +254,10 @@ public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, tr
   }
 
   /* This method normalizes (destructively) this set. */
+  @Override
   public final boolean isNormalized() { return this.isNorm; }
 
+  @Override
   public final Value normalize() {
     try {
       if (!this.isNorm) {
@@ -257,6 +291,7 @@ public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, tr
 	  return this;
   }
 
+  @Override
   public final boolean isDefined() {
     try {
       boolean defined = true;
@@ -272,8 +307,10 @@ public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, tr
     }
   }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       return this.equals(val);
@@ -301,6 +338,7 @@ public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, tr
 	}
 
   /* The fingerprint methods */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       this.normalize();
@@ -319,6 +357,7 @@ public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, tr
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) {
     try {
       int sz = this.elems.size();
@@ -340,6 +379,7 @@ public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, tr
   }
 
   /* The string representation */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       // If this SetEnumValue object is created by a union, at least one of
@@ -384,6 +424,7 @@ public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, tr
      return this.elems.elementAt(index);
   }
 
+  @Override
   public final ValueEnumeration elements() {
     try {
       return new Enumerator();
@@ -401,8 +442,10 @@ public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, tr
       normalize();
     }
 
+    @Override
     public final void reset() { this.index = 0; }
 
+    @Override
     public final Value nextElement() {
     	if (coverage) { cm.incSecondary(); }
       if (this.index < elems.size()) {
@@ -455,4 +498,21 @@ public final static SetEnumValue DummyEnum = new SetEnumValue((ValueVec)null, tr
 		vos.assign(res, index);
 		return res;
 	}
+
+	public static IValue createFrom(final ValueInputStream vos, final Map<String, UniqueString> tbl) throws IOException {
+		final int index = vos.getIndex();
+		boolean isNorm = true;
+		int len = vos.readInt();
+		if (len < 0) {
+			len = -len;
+			isNorm = false;
+		}
+		final Value[] elems = new Value[len];
+		for (int i = 0; i < len; i++) {
+			elems[i] = (Value) vos.read(tbl);
+		}
+		final Value res = new SetEnumValue(elems, isNorm);
+		vos.assign(res, index);
+		return res;
+	}
 }
diff --git a/tlatools/src/tlc2/value/impl/SetOfFcnsValue.java b/tlatools/src/tlc2/value/impl/SetOfFcnsValue.java
index b407c9599565e3f8cd567369eae1a5ccea2a7cd6..4498dd72263af7438cc1c2e10e25d38bb64d46fb 100644
--- a/tlatools/src/tlc2/value/impl/SetOfFcnsValue.java
+++ b/tlatools/src/tlc2/value/impl/SetOfFcnsValue.java
@@ -35,8 +35,10 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
 	  this.cm = cm;
   }
 
+  @Override
   public final byte getKind() { return SETOFFCNSVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       this.convertAndCache();
@@ -64,6 +66,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       FcnRcdValue fcn = (FcnRcdValue) elem.toFcnRcd();
@@ -101,6 +104,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       return this.domain.isFinite() && this.range.isFinite();
@@ -111,6 +115,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -125,6 +130,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (exs.length != 0) {
@@ -139,6 +145,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final int size() {
     try {
       int dsz = this.domain.size();
@@ -173,6 +180,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
 		return false;
 	}
 
+  @Override
   public final boolean isNormalized() {
     try {
       if (this.fcnSet == null || this.fcnSet == SetEnumValue.DummyEnum) {
@@ -186,6 +194,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value normalize() {
     try {
       if (this.fcnSet == null || this.fcnSet == SetEnumValue.DummyEnum) {
@@ -221,6 +230,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
 	    }
   }
 
+  @Override
   public final boolean isDefined() {
     try {
       return this.domain.isDefined() && this.range.isDefined();
@@ -231,8 +241,10 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       return this.equals(val);
@@ -244,6 +256,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
   }
 
   /* The fingerprint  */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       this.convertAndCache();
@@ -255,6 +268,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) {
     try {
       this.convertAndCache();
@@ -305,6 +319,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
   }
 
   /* The string representation of the value. */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       boolean unlazy = TLCGlobals.expand;
@@ -344,6 +359,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final ValueEnumeration elements() {
     try {
       if (this.fcnSet == null || this.fcnSet == SetEnumValue.DummyEnum) {
@@ -397,6 +413,7 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
       }
     }
 
+    @Override
     public final void reset() {
       if (this.enums != null) {
         for (int i = 0; i < this.enums.length; i++) {
@@ -407,7 +424,8 @@ public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
       }
     }
 
-		public final Value nextElement() {
+		@Override
+        public final Value nextElement() {
 			if (this.isDone) {
 				return null;
 			}
diff --git a/tlatools/src/tlc2/value/impl/SetOfRcdsValue.java b/tlatools/src/tlc2/value/impl/SetOfRcdsValue.java
index 9990059038dbb648758386785c61e2a60c1a2c8e..8cbff7cbc8b27c210b4b647cd42d92d7684e5c0b 100644
--- a/tlatools/src/tlc2/value/impl/SetOfRcdsValue.java
+++ b/tlatools/src/tlc2/value/impl/SetOfRcdsValue.java
@@ -41,8 +41,10 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
 	  this.cm = cm;
   }
 
+  @Override
   public final byte getKind() { return SETOFRCDSVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       this.convertAndCache();
@@ -83,6 +85,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       RecordValue rcd = (RecordValue) elem.toRcd();
@@ -110,6 +113,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       for (int i = 0; i < this.values.length; i++) {
@@ -123,6 +127,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -137,6 +142,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (exs.length != 0) {
@@ -151,6 +157,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final int size() {
     try {
       long sz = 1;
@@ -181,6 +188,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
 		return false;
 	}
 
+  @Override
   public final boolean isNormalized() {
     try {
       if (this.rcdSet == null || this.rcdSet == SetEnumValue.DummyEnum) {
@@ -199,6 +207,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value normalize() {
     try {
       if (this.rcdSet == null || this.rcdSet == SetEnumValue.DummyEnum) {
@@ -271,6 +280,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean isDefined() {
     try {
       boolean isDefined = true;
@@ -285,8 +295,10 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       return this.equals(val);
@@ -298,6 +310,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
   }
 
   /* The fingerprint  */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       this.convertAndCache();
@@ -309,6 +322,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) {
     try {
       this.convertAndCache();
@@ -359,6 +373,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
   }
 
   /* The string representation of the value. */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       boolean unlazy = TLCGlobals.expand;
@@ -403,6 +418,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
     }
   }
 
+  @Override
   public final ValueEnumeration elements() {
     try {
       if (this.rcdSet == null || this.rcdSet == SetEnumValue.DummyEnum) {
@@ -443,6 +459,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
       }
     }
 
+    @Override
     public final void reset() {
       if (this.enums != null) {
         for (int i = 0; i < this.enums.length; i++) {
@@ -453,6 +470,7 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
       }
     }
 
+    @Override
     public final Value nextElement() {
       if (this.isDone) return null;
       Value[] elems = new Value[this.currentElems.length];
@@ -499,7 +517,8 @@ public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable {
 			}
 		}
 
-		protected RecordValue elementAt(final int idx) {
+		@Override
+        protected RecordValue elementAt(final int idx) {
 			assert 0 <= idx && idx < size();
 			
 			final Value[] val = new Value[names.length];
diff --git a/tlatools/src/tlc2/value/impl/SetOfTuplesValue.java b/tlatools/src/tlc2/value/impl/SetOfTuplesValue.java
index 11a1a40e3d67be108bce416c9007633ce4d1b6ac..7a73ac078f3fe833c7fd228c95fae65fa741aeac 100644
--- a/tlatools/src/tlc2/value/impl/SetOfTuplesValue.java
+++ b/tlatools/src/tlc2/value/impl/SetOfTuplesValue.java
@@ -42,8 +42,10 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable {
     this.sets[1] = v2;
   }
 
+  @Override
   public final byte getKind() { return SETOFTUPLESVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       this.convertAndCache();
@@ -83,6 +85,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       TupleValue tv = (TupleValue) elem.toTuple();
@@ -118,6 +121,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       for (int i = 0; i < this.sets.length; i++) {
@@ -133,6 +137,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -147,6 +152,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (exs.length != 0) {
@@ -161,6 +167,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final int size() {
     try {
       long sz = 1;
@@ -179,6 +186,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean isNormalized() {
     try {
       if (this.tupleSet == null || this.tupleSet == SetEnumValue.DummyEnum) {
@@ -197,6 +205,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value normalize() {
     try {
       if (this.tupleSet == null || this.tupleSet == SetEnumValue.DummyEnum) {
@@ -234,6 +243,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable {
 	    }
   }
 
+  @Override
   public final boolean isDefined() {
     try {
       boolean defined = true;
@@ -248,8 +258,10 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       return this.equals(val);
@@ -261,6 +273,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable {
   }
 
   /* The fingerprint  */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       this.convertAndCache();
@@ -272,6 +285,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) {
     try {
       this.convertAndCache();
@@ -322,6 +336,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable {
   }
 
   /* The string representation of the value. */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       boolean unlazy = TLCGlobals.expand;
@@ -365,6 +380,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final ValueEnumeration elements() {
     try {
       if (this.tupleSet == null || this.tupleSet == SetEnumValue.DummyEnum) {
@@ -404,6 +420,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable {
       }
     }
 
+    @Override
     public final void reset() {
       if (this.enums != null) {
         for (int i = 0; i < this.enums.length; i++) {
@@ -414,6 +431,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable {
       }
     }
 
+    @Override
     public final Value nextElement() {
       if (this.isDone) return null;
       Value[] elems = new Value[this.currentElems.length];
diff --git a/tlatools/src/tlc2/value/impl/SetPredValue.java b/tlatools/src/tlc2/value/impl/SetPredValue.java
index e6a686e3191eb2ba150822bfa8cf22ad201e7c59..f3ac2bfa8d01838f753c67e5f419e623259fa1ee 100644
--- a/tlatools/src/tlc2/value/impl/SetPredValue.java
+++ b/tlatools/src/tlc2/value/impl/SetPredValue.java
@@ -33,7 +33,14 @@ public class SetPredValue extends EnumerableValue implements Enumerable {
     ***********************************************************************/
   public Value inVal;           // the in value or the real set
   public final SemanticNode pred;     // the predicate
-  public ITool tool;             // null iff inVal is the real set
+  public final ITool tool;             // null iff inVal is the real set
+  /**
+   * true after inVal has been converted to a SetEnumValue.  I assume this
+   * implies (inVal instanceof SetEnumValue) too but the serialization
+   * might interfere.
+   * MAK 07/18/2019
+   */
+  private boolean converted = false; 
   public final Context con;
   public final TLCState state;
   public final TLCState pstate;
@@ -68,13 +75,19 @@ public class SetPredValue extends EnumerableValue implements Enumerable {
 	  this(vars, inVal, pred, tool, con, s0, s1, control);
 	  this.cm = cm;
   }
+  
+	public SetPredValue(SetPredValue other, ITool tool) {
+		this(other.vars, other.inVal, other.pred, tool, other.con, other.state, other.pstate, other.control, other.cm);
+	}
 
+  @Override
   public final byte getKind() { return SETPREDVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       this.inVal = this.toSetEnum();
-      this.tool = null;
+      this.converted = true;
       return this.inVal.compareTo(obj);
     }
     catch (RuntimeException | OutOfMemoryError e) {
@@ -86,7 +99,7 @@ public class SetPredValue extends EnumerableValue implements Enumerable {
   public final boolean equals(Object obj) {
     try {
       this.inVal = this.toSetEnum();
-      this.tool = null;
+      this.converted = true;
       return this.inVal.equals(obj);
     }
     catch (RuntimeException | OutOfMemoryError e) {
@@ -95,9 +108,10 @@ public class SetPredValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
-      if (this.tool == null) {
+      if (this.converted) {
         return this.inVal.member(elem);
       }
       try {
@@ -141,6 +155,7 @@ public class SetPredValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       if (!(this.inVal.isFinite())) {
@@ -156,6 +171,7 @@ public class SetPredValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -169,6 +185,7 @@ public class SetPredValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (exs.length != 0) {
@@ -182,10 +199,11 @@ public class SetPredValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final int size() {
     try {
       this.inVal = this.toSetEnum();
-      this.tool = null;
+      this.converted = true;
       return this.inVal.size();
     }
     catch (RuntimeException | OutOfMemoryError e) {
@@ -196,18 +214,19 @@ public class SetPredValue extends EnumerableValue implements Enumerable {
 
   private final void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
     this.inVal = (Value )ois.readObject();
-    this.tool = null;
+    this.converted = true;
   }
 
   private final void writeObject(ObjectOutputStream oos) throws IOException {
-    if (this.tool != null) {
+    if (!this.converted) {
       this.inVal = this.toSetEnum();
-      this.tool = null;
+      this.converted = true;
     }
     oos.writeObject(this.inVal);
   }
 
   /* This method normalizes (destructively) this set. */
+  @Override
   public final boolean isNormalized() {
     try {
       return this.inVal.isNormalized();
@@ -218,6 +237,7 @@ public class SetPredValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value normalize() {
     try {
       this.inVal.normalize();
@@ -240,10 +260,13 @@ public class SetPredValue extends EnumerableValue implements Enumerable {
 	    }
   }
 
+  @Override
   public final boolean isDefined() { return true; }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       return this.equals(val);
@@ -255,10 +278,11 @@ public class SetPredValue extends EnumerableValue implements Enumerable {
   }
 
   /* The fingerprint method */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       this.inVal = this.toSetEnum();
-      this.tool = null;
+      this.converted = true;
       return this.inVal.fingerPrint(fp);
     }
     catch (RuntimeException | OutOfMemoryError e) {
@@ -267,10 +291,11 @@ public class SetPredValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) {
     try {
       this.inVal = this.toSetEnum();
-      this.tool = null;
+      this.converted = true;
       return this.inVal.permute(perm);
     }
     catch (RuntimeException | OutOfMemoryError e) {
@@ -281,7 +306,7 @@ public class SetPredValue extends EnumerableValue implements Enumerable {
 
   @Override
   public Value toSetEnum() {
-      if (this.tool == null) {
+      if (this.converted) {
     	  return (SetEnumValue) this.inVal;
       }
       ValueVec vals = new ValueVec();
@@ -300,6 +325,7 @@ public class SetPredValue extends EnumerableValue implements Enumerable {
   }
 
   /* The string representation of the value. */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       try {
@@ -331,9 +357,10 @@ public class SetPredValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final ValueEnumeration elements() {
     try {
-      if (this.tool == null) {
+      if (this.converted) {
         return ((SetEnumValue)this.inVal).elements();
       }
       return new Enumerator();
@@ -355,8 +382,10 @@ public class SetPredValue extends EnumerableValue implements Enumerable {
       this.Enum = ((Enumerable)inVal).elements();
     }
 
+    @Override
     public final void reset() { this.Enum.reset(); }
 
+    @Override
     public final Value nextElement() {
     	Value  elem;
       while ((elem = this.Enum.nextElement()) != null) {
diff --git a/tlatools/src/tlc2/value/impl/StringValue.java b/tlatools/src/tlc2/value/impl/StringValue.java
index 1ca046936acc6311d82737134375c2993d13c01f..5e3e203210b58749e2dcdd9d2466cdb83c255590 100644
--- a/tlatools/src/tlc2/value/impl/StringValue.java
+++ b/tlatools/src/tlc2/value/impl/StringValue.java
@@ -7,6 +7,7 @@
 package tlc2.value.impl;
 
 import java.io.IOException;
+import java.util.Map;
 
 import tlc2.tool.FingerprintException;
 import tlc2.tool.coverage.CostModel;
@@ -37,10 +38,12 @@ public class StringValue extends Value {
 	  this.cm = cm;
   }
 
+  @Override
   public final byte getKind() { return STRINGVALUE; }
 
   public final UniqueString getVal() { return this.val; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       if (obj instanceof StringValue) {
@@ -75,6 +78,7 @@ public class StringValue extends Value {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) +
@@ -87,6 +91,7 @@ public class StringValue extends Value {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       Assert.fail("Attempted to check if the string " + Values.ppr(this.toString()) +
@@ -99,6 +104,7 @@ public class StringValue extends Value {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -113,6 +119,7 @@ public class StringValue extends Value {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (exs.length != 0) {
@@ -127,6 +134,7 @@ public class StringValue extends Value {
     }
   }
 
+  @Override
   public final int size() {
     try {
       Assert.fail("Attempted to compute the number of elements in the string " +
@@ -139,14 +147,35 @@ public class StringValue extends Value {
     }
   }
 
+  @Override
+  public boolean mutates() {
+	  // finalized after construction.
+	  return true;
+  }
+  
+  @Override
+  public final Value toTuple() {
+		final String s = val.toString();
+		Value[] vals = new Value[s.length()];
+		for (int i = 0; i < s.length(); i++) {
+			vals[i] = new StringValue(Character.toString(s.charAt(i)));
+		}
+		return new TupleValue(vals);
+  }
+
+  @Override
   public final boolean isNormalized() { return true; }
 
+  @Override
   public final Value normalize() { /*SKIP*/return this; }
 
+  @Override
   public final boolean isDefined() { return true; }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       return ((val instanceof StringValue) &&
@@ -181,6 +210,7 @@ public class StringValue extends Value {
 	}
 
   /* The fingerprint method */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       fp = FP64.Extend(fp, STRINGVALUE) ;
@@ -194,6 +224,7 @@ public class StringValue extends Value {
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) { return this; }
 
   /*************************************************************************
@@ -227,7 +258,7 @@ public class StringValue extends Value {
             buf.append(str.charAt(i)) ;
             break ;
          } // switch
-       }; // for
+       }// for
       return buf.toString();
     }
     catch (RuntimeException | OutOfMemoryError e) {
@@ -238,6 +269,7 @@ public class StringValue extends Value {
 
 
   /* The string representation of the value. */
+  @Override
   public StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       return sb.append("\"" + PrintVersion(this.val.toString()) + "\"");
@@ -248,6 +280,12 @@ public class StringValue extends Value {
     }
   }
 
+  /* Same as toString. */
+  @Override
+  public final String toUnquotedString() {
+	  return PrintVersion(this.val.toString());
+  }
+
 	public static IValue createFrom(final IValueInputStream vos) throws IOException {
 		final UniqueString str = UniqueString.read(vos.getInputStream());
 		final IValue res = new StringValue(str);
@@ -255,5 +293,12 @@ public class StringValue extends Value {
 		vos.assign(res, index);
 		return res;
 	}
-
+	
+	public static IValue createFrom(final IValueInputStream vos, final Map<String, UniqueString> tbl) throws IOException {
+		final UniqueString str = UniqueString.read(vos.getInputStream(), tbl);
+		final IValue res = new StringValue(str);
+		final int index = vos.getIndex();
+		vos.assign(res, index);
+		return res;
+	}
 }
diff --git a/tlatools/src/tlc2/value/impl/SubsetValue.java b/tlatools/src/tlc2/value/impl/SubsetValue.java
index 21137a7611be318fa6bbb0f9fab69fd29014324e..c3e3d1776a155673ec5feffbca08468520903666 100644
--- a/tlatools/src/tlc2/value/impl/SubsetValue.java
+++ b/tlatools/src/tlc2/value/impl/SubsetValue.java
@@ -42,8 +42,10 @@ public class SubsetValue extends EnumerableValue implements Enumerable {
 	  this.cm = cm;
   }
 
+  @Override
   public final byte getKind() { return SUBSETVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       if (obj instanceof SubsetValue) {
@@ -72,6 +74,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean member(Value val) {
     try {
       if (val instanceof Enumerable) {
@@ -95,6 +98,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public Value isSubsetEq(Value other) {
     try {
       // Reduce (SUBSET A \subseteq SUBSET B) to (A \subseteq B) to avoid
@@ -111,6 +115,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       return this.set.isFinite();
@@ -121,6 +126,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -134,6 +140,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (exs.length != 0) {
@@ -147,6 +154,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final int size() {
     try {
       int sz = this.set.size();
@@ -162,6 +170,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean isNormalized() {
     try {
       return (this.pset != null &&
@@ -174,6 +183,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value normalize() {
     try {
       if (this.pset == null || this.pset == SetEnumValue.DummyEnum) {
@@ -207,6 +217,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable {
 	    }
   }
 
+  @Override
   public final boolean isDefined() {
     try {
       return this.set.isDefined();
@@ -217,8 +228,10 @@ public class SubsetValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       return this.equals(val);
@@ -235,6 +248,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable {
 	}
 
   /* The fingerprint  */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       this.convertAndCache();
@@ -246,6 +260,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) {
     try {
       this.convertAndCache();
@@ -294,6 +309,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable {
   }
 
   /* The string representation  */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       boolean unlazy = TLCGlobals.expand;
@@ -676,6 +692,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable {
 		return elements();
 	}
 
+  @Override
   public final ValueEnumeration elements() {
     try {
       if (this.pset == null || this.pset == SetEnumValue.DummyEnum) {
@@ -707,10 +724,12 @@ public class SubsetValue extends EnumerableValue implements Enumerable {
       this.descriptor = new BitSet(this.elems.size());
     }
 
+    @Override
     public final void reset() {
       this.descriptor = new BitSet(this.elems.size());
     }
 
+    @Override
     public final Value nextElement() {
 			if (this.descriptor == null)
 				return null;
@@ -819,7 +838,8 @@ public class SubsetValue extends EnumerableValue implements Enumerable {
 
 		// Repeated invocation can yield duplicate elements due to the probabilistic
 		// nature of CoinTossingSubsetEnumerator.
-		public Value nextElement() {
+		@Override
+        public Value nextElement() {
 			if (!hasNext()) {
 				return null;
 			}
diff --git a/tlatools/src/tlc2/value/impl/SubsetValue.tla b/tlatools/src/tlc2/value/impl/SubsetValue.tla
index 62e8d00ba8d90a49f024d167dc32e0217d48f4bb..d87d33e83d9e7f80782c17354762326bd719635b 100644
--- a/tlatools/src/tlc2/value/impl/SubsetValue.tla
+++ b/tlatools/src/tlc2/value/impl/SubsetValue.tla
@@ -38,7 +38,7 @@ ASSUME /\ \A nn \in N: nn \in Nat
    in TLC has an order. This is e.g. important to efficiently determine equality of two
    or more sets. If all sets adhere to a predefined order, equality can be determined
    in O(n) time by a single pass over both sets.
-   Let u and v be to k-Subsets for a given k. The (total) order defined by this algorithm
+   Let u and v be two k-Subsets for a given k. The (total) order defined by this algorithm
    is such that there exists a prefix p of u with length 0..Len(u)-1 s.t.
    \A i \in 1..p: u[i] <= v[i] /\ u[p+1] < v[p+1]  (see Sorted operator above).
 --algorithm EnumerateSubsets {
diff --git a/tlatools/src/tlc2/value/impl/TupleValue.java b/tlatools/src/tlc2/value/impl/TupleValue.java
index b35bed3544e1dd6d737b754bb505154714e4d86a..d0020e6098ce1d91712967e84a13971c7d931242 100644
--- a/tlatools/src/tlc2/value/impl/TupleValue.java
+++ b/tlatools/src/tlc2/value/impl/TupleValue.java
@@ -7,6 +7,7 @@
 package tlc2.value.impl;
 
 import java.io.IOException;
+import java.util.Map;
 
 import tlc2.output.EC;
 import tlc2.output.MP;
@@ -19,12 +20,14 @@ import tlc2.value.ITupleValue;
 import tlc2.value.IValue;
 import tlc2.value.IValueInputStream;
 import tlc2.value.IValueOutputStream;
+import tlc2.value.ValueInputStream;
 import tlc2.value.Values;
 import util.Assert;
+import util.UniqueString;
 
 public class TupleValue extends Value implements Applicable, ITupleValue {
   public final Value[] elems;          // the elements of this tuple.
-  public final static TupleValue EmptyTuple = new TupleValue(new Value[0]);
+  public static final TupleValue EmptyTuple = new TupleValue(new Value[0]);
 
   /* Constructor */
   public TupleValue(Value[] elems) { this.elems = elems; }
@@ -45,16 +48,20 @@ public class TupleValue extends Value implements Applicable, ITupleValue {
 	  this.cm = cm;
   }
 
+  @Override
   public IValue getElem(int idx) {
 	  return elems[idx];
   }
   
+  @Override
   public IValue[] getElems() {
 	  return elems;
   }
   
+  @Override
   public final byte getKind() { return TUPLEVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       TupleValue tv = obj instanceof Value ? (TupleValue) ((Value)obj).toTuple() : null;
@@ -100,6 +107,7 @@ public class TupleValue extends Value implements Applicable, ITupleValue {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       Assert.fail("Attempted to check set membership in a tuple value.");
@@ -111,8 +119,10 @@ public class TupleValue extends Value implements Applicable, ITupleValue {
     }
   }
 
+  @Override
   public final boolean isFinite() { return true; }
 
+  @Override
   public final Value apply(Value arg, int control) {
     try {
       if (!(arg instanceof IntValue)) {
@@ -131,6 +141,7 @@ public class TupleValue extends Value implements Applicable, ITupleValue {
     }
   }
 
+  @Override
   public final Value apply(Value[] args, int control) {
     try {
       if (args.length != 1) {
@@ -144,6 +155,7 @@ public class TupleValue extends Value implements Applicable, ITupleValue {
     }
   }
 
+  @Override
   public final Value select(Value arg) {
     try {
       if (!(arg instanceof IntValue)) {
@@ -162,6 +174,7 @@ public class TupleValue extends Value implements Applicable, ITupleValue {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -189,6 +202,7 @@ public class TupleValue extends Value implements Applicable, ITupleValue {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       Value val = this;
@@ -203,6 +217,7 @@ public class TupleValue extends Value implements Applicable, ITupleValue {
     }
   }
 
+  @Override
   public final Value getDomain() {
     try {
       return new IntervalValue(1, this.size());
@@ -213,6 +228,7 @@ public class TupleValue extends Value implements Applicable, ITupleValue {
     }
   }
 
+  @Override
   public final int size() { return this.elems.length; }
 
   @Override
@@ -246,10 +262,13 @@ public class TupleValue extends Value implements Applicable, ITupleValue {
 	}
 
   /* The normalization of the value. */
+  @Override
   public final boolean isNormalized() { return true; }
 
+  @Override
   public final Value normalize() { /*nop*/return this; }
 
+  @Override
   public final boolean isDefined() {
     try {
       boolean defined = true;
@@ -264,6 +283,7 @@ public class TupleValue extends Value implements Applicable, ITupleValue {
     }
   }
 
+  @Override
   public final IValue deepCopy() {
     try {
     	Value[] vals = new Value[this.elems.length];
@@ -278,6 +298,7 @@ public class TupleValue extends Value implements Applicable, ITupleValue {
     }
   }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       boolean canAssign = ((val instanceof TupleValue) &&
@@ -311,6 +332,7 @@ public class TupleValue extends Value implements Applicable, ITupleValue {
 	}
 
   /* The fingerprint method: tuples are functions. */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       int len = this.elems.length;
@@ -329,6 +351,7 @@ public class TupleValue extends Value implements Applicable, ITupleValue {
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) {
     try {
     	Value[] vals = new Value[this.elems.length];
@@ -349,6 +372,7 @@ public class TupleValue extends Value implements Applicable, ITupleValue {
   }
 
   /* The string representation of this value. */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       sb.append("<<");
@@ -380,4 +404,16 @@ public class TupleValue extends Value implements Applicable, ITupleValue {
 		vos.assign(res, index);
 		return res;
 	}
+
+	public static IValue createFrom(final ValueInputStream vos, final Map<String, UniqueString> tbl) throws IOException {
+		final int index = vos.getIndex();
+		final int len = vos.readNat();
+		final Value[] elems = new Value[len];
+		for (int i = 0; i < len; i++) {
+			elems[i] = (Value) vos.read(tbl);
+		}
+		final Value res = new TupleValue(elems);
+		vos.assign(res, index);
+		return res;
+	}
 }
diff --git a/tlatools/src/tlc2/value/impl/UndefValue.java b/tlatools/src/tlc2/value/impl/UndefValue.java
index a7ff40a913495b6b2f1938661adb0dd702cb2b1e..81d0062cf44eba330600da1f1d88f3d68b477de5 100644
--- a/tlatools/src/tlc2/value/impl/UndefValue.java
+++ b/tlatools/src/tlc2/value/impl/UndefValue.java
@@ -13,12 +13,14 @@ import util.Assert;
 
 public class UndefValue extends Value {
 
-  public final static UndefValue ValUndef = new UndefValue();
+  public static final UndefValue ValUndef = new UndefValue();
 
   public UndefValue() { /*SKIP*/ }
 
+  @Override
   public byte getKind() { return UNDEFVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       return (obj instanceof UndefValue) ? 0 : 1;
@@ -39,6 +41,7 @@ public class UndefValue extends Value {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       Assert.fail("Attempted to check if the value:\n" + Values.ppr(elem.toString()) +
@@ -51,6 +54,7 @@ public class UndefValue extends Value {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       Assert.fail("Attempted to check if the value " + Values.ppr(this.toString()) +
@@ -63,6 +67,7 @@ public class UndefValue extends Value {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -77,6 +82,7 @@ public class UndefValue extends Value {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (exs.length != 0) {
@@ -91,6 +97,7 @@ public class UndefValue extends Value {
     }
   }
 
+  @Override
   public final int size() {
     try {
       Assert.fail("Attempted to compute the number of elements in the value " +
@@ -103,17 +110,28 @@ public class UndefValue extends Value {
     }
   }
 
+  @Override
+  public boolean mutates() {
+	  return false;
+  }
+
+  @Override
   public final boolean isNormalized() { return true; }
 
+  @Override
   public final Value normalize() { /*nop*/return this; }
 
+  @Override
   public final boolean isDefined() { return false; }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) { return true; }
 
   /* The string representation. */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       return sb.append("UNDEF");
diff --git a/tlatools/src/tlc2/value/impl/UnionValue.java b/tlatools/src/tlc2/value/impl/UnionValue.java
index f694bf0a26fd481dd65b74c853dc7254bc2f885a..c3d78f9152251f14e582ee05dc026c89b41a9532 100644
--- a/tlatools/src/tlc2/value/impl/UnionValue.java
+++ b/tlatools/src/tlc2/value/impl/UnionValue.java
@@ -32,8 +32,10 @@ public class UnionValue extends EnumerableValue implements Enumerable {
 	  this.cm = cm;
   }
 
+  @Override
   public byte getKind() { return UNIONVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       this.convertAndCache();
@@ -56,6 +58,7 @@ public class UnionValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean member(Value elem) {
     try {
       if (!(this.set instanceof Enumerable)) {
@@ -76,6 +79,7 @@ public class UnionValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       if (!(this.set instanceof Enumerable)) {
@@ -95,6 +99,7 @@ public class UnionValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -108,6 +113,7 @@ public class UnionValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (exs.length != 0) {
@@ -121,6 +127,7 @@ public class UnionValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final int size() {
     try {
       this.convertAndCache();
@@ -132,6 +139,7 @@ public class UnionValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final boolean isNormalized() {
     try {
       return (this.realSet != null &&
@@ -144,6 +152,7 @@ public class UnionValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final Value normalize() {
     try {
       if (this.realSet != null && this.realSet != SetEnumValue.DummyEnum) {
@@ -160,6 +169,23 @@ public class UnionValue extends EnumerableValue implements Enumerable {
   @Override
   public final void deepNormalize() {
 	    try {
+			// MAK 09/17/2019: Added call to this.set.deepNormalize() to align with pattern
+			// generally found in overwrites of Value#deepNormalize.
+	    	// This omission surfaced through a race condition that led to a spurious
+	    	// safety violation (https://github.com/tlaplus/tlaplus/issues/361):
+	    	// 1) A TLA+ spec defines a (zero-arity) operator s.a. "Foo == UNION { ... }"
+	    	//    that appears in an invariant.
+	    	// 2) SpecProcessor#processConstantDefns eagerly evaluates the operator Foo at startup
+	    	//    and inserts its Value result UV into the corresponding node of the semantic graph.
+	    	// 3) Two workers check if two states violate the invariant which triggers UnionValue#member,
+	    	//    which internally causes this.set to be normalized.  Since Value instances are not thread-safe
+	    	//    because they are expected to be fully normalized during state space exploration, the
+	    	//    two workers race to normalize this.set.
+	    	// 4) Worker A gets ahead and loops over the elements in UV#member while worker B still normalizes UV.
+	    	//    Worker A reads inconsistent data and thus reports the invariant to be violated.
+	    	// Thanks to Calvin Loncaric for suggesting this fix.
+	    	this.set.deepNormalize();
+	    	
       if (realSet == null) {
         realSet = SetEnumValue.DummyEnum;
       }
@@ -173,6 +199,7 @@ public class UnionValue extends EnumerableValue implements Enumerable {
 	    }
   }
 
+  @Override
   public final boolean isDefined() {
     try {
       return this.set.isDefined();
@@ -183,8 +210,10 @@ public class UnionValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       return this.equals(val);
@@ -227,6 +256,7 @@ public class UnionValue extends EnumerableValue implements Enumerable {
 	}
 
   /* The fingerprint  */
+  @Override
   public final long fingerPrint(long fp) {
     try {
       this.convertAndCache();
@@ -238,6 +268,7 @@ public class UnionValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final IValue permute(IMVPerm perm) {
     try {
       this.convertAndCache();
@@ -283,6 +314,7 @@ public class UnionValue extends EnumerableValue implements Enumerable {
   }
 
   /* String representation of this value. */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       if (TLCGlobals.expand) {
@@ -302,6 +334,7 @@ public class UnionValue extends EnumerableValue implements Enumerable {
     }
   }
 
+  @Override
   public final ValueEnumeration elements() {
     try {
       if (this.realSet == null || this.realSet == SetEnumValue.DummyEnum) {
@@ -335,12 +368,14 @@ public class UnionValue extends EnumerableValue implements Enumerable {
       }
     }
 
+    @Override
     public final void reset() {
       this.Enum.reset();
       this.elemSet = this.Enum.nextElement();
       this.elemSetEnum = ((Enumerable)this.elemSet).elements();
     }
 
+    @Override
     public final Value nextElement() {
       if (this.elemSet == null) return null;
       Value val = this.elemSetEnum.nextElement();
diff --git a/tlatools/src/tlc2/value/impl/UserValue.java b/tlatools/src/tlc2/value/impl/UserValue.java
index 0b9e14a98cf877ea6b5b7b1d31f87480f5a03da5..9518af3f3c6e598bffbf6d22ccd6813d73b5b7ba 100644
--- a/tlatools/src/tlc2/value/impl/UserValue.java
+++ b/tlatools/src/tlc2/value/impl/UserValue.java
@@ -16,8 +16,10 @@ public class UserValue extends Value {
 
   public UserValue(UserObj obj) { this.userObj = obj; }
 
+  @Override
   public final byte getKind() { return USERVALUE; }
 
+  @Override
   public final int compareTo(Object obj) {
     try {
       if (obj instanceof UserValue) {
@@ -44,6 +46,7 @@ public class UserValue extends Value {
     }
   }
 
+  @Override
   public final boolean member(Value val) {
     try {
       return this.userObj.member(val);
@@ -54,6 +57,7 @@ public class UserValue extends Value {
     }
   }
 
+  @Override
   public final boolean isFinite() {
     try {
       return this.userObj.isFinite();
@@ -64,6 +68,7 @@ public class UserValue extends Value {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept ex) {
     try {
       if (ex.idx < ex.path.length) {
@@ -78,6 +83,7 @@ public class UserValue extends Value {
     }
   }
 
+  @Override
   public final Value takeExcept(ValueExcept[] exs) {
     try {
       if (exs.length != 0) {
@@ -92,6 +98,7 @@ public class UserValue extends Value {
     }
   }
 
+  @Override
   public final int size() {
     try {
       Assert.fail("Attempted to compute the number of elements in the overridden value " +
@@ -105,14 +112,19 @@ public class UserValue extends Value {
   }
 
   /* Nothing to normalize. */
+  @Override
   public final boolean isNormalized() { return true; }
 
+  @Override
   public final Value normalize() { /*SKIP*/return this; }
 
+  @Override
   public final boolean isDefined() { return true; }
 
+  @Override
   public final IValue deepCopy() { return this; }
 
+  @Override
   public final boolean assignable(Value val) {
     try {
       return this.equals(val);
@@ -124,6 +136,7 @@ public class UserValue extends Value {
   }
 
   /* The string representation. */
+  @Override
   public final StringBuffer toString(StringBuffer sb, int offset, boolean swallow) {
     try {
       return this.userObj.toString(sb, offset, swallow);
diff --git a/tlatools/src/tlc2/value/impl/Value.java b/tlatools/src/tlc2/value/impl/Value.java
index ab6741f63b9cc6efb5c81381f5556c906d6473af..f03c21f96746dc397b644a44fd5f03c6a2cb6672 100644
--- a/tlatools/src/tlc2/value/impl/Value.java
+++ b/tlatools/src/tlc2/value/impl/Value.java
@@ -316,6 +316,12 @@ public abstract class Value implements ValueConstants, Serializable, IValue {
 	  return toStringImpl("", false);
   }
 
+  /* Same as toString. */
+  @Override
+  public String toUnquotedString() {
+	  return toString();
+  }
+
   @Override
   public final String toString(final String delim) {
 	  return toStringImpl(delim, true);
diff --git a/tlatools/src/tlc2/value/impl/ValueEnumeration.java b/tlatools/src/tlc2/value/impl/ValueEnumeration.java
index 4e8037fb21e3ab647c7eadd34993a9d1d0ad787f..fc4d77947c3c249bb37c3fa89aebe4d09e5d9c96 100644
--- a/tlatools/src/tlc2/value/impl/ValueEnumeration.java
+++ b/tlatools/src/tlc2/value/impl/ValueEnumeration.java
@@ -11,10 +11,10 @@ import java.util.function.Consumer;
 
 public interface ValueEnumeration {
   /* Reset allows repeated use of this enumerator. */
-  public void reset();
+  void reset();
 
   /* Return the next element if there is one. Otherwise return null. */
-  public Value nextElement();
+  Value nextElement();
   
 	default List<Value> all() {
 		final List<Value> values = new ArrayList<Value>();
diff --git a/tlatools/src/tlc2/value/impl/ValueVec.java b/tlatools/src/tlc2/value/impl/ValueVec.java
index 8e0edc89d4956a823e5f16c1210d206f519390a4..e2c89fd9758eb24333e85809956c303013f8365b 100644
--- a/tlatools/src/tlc2/value/impl/ValueVec.java
+++ b/tlatools/src/tlc2/value/impl/ValueVec.java
@@ -15,7 +15,7 @@ public class ValueVec implements Cloneable, Serializable {
   private Value [] elementData;
   private int elementCount;
          
-  static private final Value [] empty = new Value [0];
+  private static final Value [] empty = new Value [0];
 
   public ValueVec() { this(10); }
 
@@ -73,6 +73,7 @@ public class ValueVec implements Cloneable, Serializable {
 
   public final int capacity() { return elementData.length; }
 
+  @Override
   public final Object clone() {
     ValueVec v = new ValueVec(this.elementData.length);
 	
diff --git a/tlatools/src/util/ExecutionStatisticsCollector.java b/tlatools/src/util/ExecutionStatisticsCollector.java
index e9393ae3392fb286a39040e503a69aa16c8e08f6..376f843fdc177790582f8d536b491aeb3880d76c 100644
--- a/tlatools/src/util/ExecutionStatisticsCollector.java
+++ b/tlatools/src/util/ExecutionStatisticsCollector.java
@@ -147,7 +147,8 @@ public class ExecutionStatisticsCollector {
 		}
 		
 		// truncate the identifier no matter what, but first remove leading and trailing whitespaces.
-		return identifier.trim().substring(0, 32);
+		final String trimmed = identifier.trim();
+		return trimmed.substring(0, Math.min(trimmed.length(), 32));
 	}
 
 	private boolean escFileExists() {
diff --git a/tlatools/src/util/ExecutionStatisticsCollector.md b/tlatools/src/util/ExecutionStatisticsCollector.md
new file mode 100644
index 0000000000000000000000000000000000000000..e4b51b4429217adba6d603c1dd923aeac9e6f43f
--- /dev/null
+++ b/tlatools/src/util/ExecutionStatisticsCollector.md
@@ -0,0 +1,14 @@
+You can help make the TLA+ tools better by allowing TLC to collect execution statistics. Execution statistics are made [publicly available](https://exec-stats.tlapl.us) on the web and contain the following information:
+
+* Total number of cores and cores assigned to TLC
+* Heap and off-heap memory allocated to TLC
+* TLC version  (git commit SHA)
+* If breadth-first search, depth-first search or simulation mode is active
+* TLC implemenation for the sets of seen and unseen states
+* If TLC has been launched from an IDE
+* Name, version, and architecture of the OS
+* Vendor, version, and architecture of JVM
+* The current date and time
+* An installation ID which allows to group execution statistic (optionally)
+
+Execution statistics do not contain personal information. You can opt-out any time.
diff --git a/tlatools/src/util/FileUtil.java b/tlatools/src/util/FileUtil.java
index c1c22d9585b41c143de8ab4291f069096dd20122..401984fb906e7e686996c08a9cd7082def0adb6a 100644
--- a/tlatools/src/util/FileUtil.java
+++ b/tlatools/src/util/FileUtil.java
@@ -195,19 +195,13 @@ public class FileUtil
         }
     }
 
-    public static void copyFile(String fromName, String toName) throws IOException
-    {
-        // REFACTOR
-        FileInputStream fis = new FileInputStream(fromName);
-        FileOutputStream fos = new FileOutputStream(toName);
-        byte[] buf = new byte[8192];
-        int n;
-        while ((n = fis.read(buf)) != -1)
-        {
-            fos.write(buf, 0, n);
-        }
-        fis.close();
-        fos.close();
+    public static void copyFile(final String fromName, final String toName) throws IOException {
+    	copyFile(new File(fromName), new File(toName));
+    }
+    
+    
+    public static void copyFile(final File source, final File destination) throws IOException {
+    	Files.copy(source.toPath(), destination.toPath(), StandardCopyOption.REPLACE_EXISTING);
     }
 
 	/**
@@ -255,10 +249,10 @@ public class FileUtil
         File filedir = new File(metadir);
 
         // ensure the non-existence
-        Assert.check(!filedir.exists(), EC.SYSTEM_METADIR_EXISTS, metadir);
+        Assert.check(!filedir.exists(), EC.SYSTEM_METADIR_EXISTS, filedir.getAbsolutePath());
 
         // ensure the dirs are created
-        Assert.check(filedir.mkdirs(), EC.SYSTEM_METADIR_CREATION_ERROR, metadir);
+        Assert.check(filedir.mkdirs(), EC.SYSTEM_METADIR_CREATION_ERROR, filedir.getAbsolutePath());
 
         return metadir;
     }
@@ -285,16 +279,16 @@ public class FileUtil
         // or name=/frob/bar/somemod
 
         // Make sure the file name ends with ".tla".
-        if (name.toLowerCase().endsWith(".tla"))
+        if (name.toLowerCase().endsWith(TLAConstants.Files.TLA_EXTENSION))
         {
-            name = name.substring(0, name.length() - 4);
+            name = name.substring(0, (name.length() - TLAConstants.Files.TLA_EXTENSION.length()));
         }
 
         // now name=/frob/bar/somemod
 
         // filename is a path ending with .tla
         // sourceFilename=/frob/bar/somemod
-        sourceFileName = name + ".tla";
+        sourceFileName = name + TLAConstants.Files.TLA_EXTENSION;
 
         // module name is =somemod
         sourceModuleName = name.substring(name.lastIndexOf(FileUtil.separator) + 1);
diff --git a/tlatools/src/util/FilenameToStream.java b/tlatools/src/util/FilenameToStream.java
index e026e9e5ead6403c966dc0fe138db0db298d546c..87dec15b19795182ce142de425b73aaea3966467 100644
--- a/tlatools/src/util/FilenameToStream.java
+++ b/tlatools/src/util/FilenameToStream.java
@@ -3,6 +3,7 @@
 package util;
 
 import java.io.File;
+import java.util.regex.Pattern;
 
 
 /**
@@ -14,11 +15,65 @@ import java.io.File;
  *
  * @author Leslie Lamport
  * @author Simon Zambrovski
- * @version $Id$
  */
 public interface FilenameToStream
 {
 
+	/*
+	 * Higher layers of TLC (and the Toolbox) have to determine if a module was
+	 * loaded from a library location s.a. those defined by TLA_LIBRARY (see
+	 * SimpleFilenameToStream). Thus, capture this information at module load
+	 * time when it is known where a module was loaded from.
+	 */
+	@SuppressWarnings("serial")
+	public static class TLAFile extends File {
+		// The following regex is concerned with determining whether the provided 'parent' string to our
+		//	parent/child constructor looks like the start of a legal absolute file path potentially including
+		//	a drive letter.
+		private static final String ROOT_PATH_REGEX
+								= "^([a-zA-Z]+:)?" + ((File.separatorChar == '\\') ? "\\\\" : File.separator);
+		private static final Pattern ROOT_PATH_PATTERN = Pattern.compile(ROOT_PATH_REGEX);
+		
+		
+		private final boolean isLibraryModule;
+		private transient final FilenameToStream resolver;
+
+		public TLAFile(String pathname, FilenameToStream fts) {
+			this(pathname, false, fts);
+		}
+
+		public TLAFile(String pathname, boolean isLibraryModule, FilenameToStream fts) {
+			super(pathname);
+			this.isLibraryModule = isLibraryModule;
+			this.resolver = fts;
+		}
+
+		public TLAFile(String parent, String child, FilenameToStream fts) {
+			super(parent,
+				  ((ROOT_PATH_PATTERN.matcher(parent).find() && child.startsWith(parent))
+						  ? child.substring(parent.length())
+					      : child));
+			this.isLibraryModule = false;
+			this.resolver = fts;
+		}
+
+		public boolean isLibraryModule() {
+			return isLibraryModule;
+		}
+
+		/**
+		 * @return null if no TLC module override for this module exists.
+		 */
+		public File getModuleOverride() {
+			final File moduleOverride = resolver.resolve(getName().replaceAll(".tla$", ".class"), false);
+			if (moduleOverride.exists()) {
+				// resolve(...) return a File instance even if the file doesn't exist.
+				return moduleOverride;
+			}
+			return null;
+		}
+	}
+	
     /**
      * This method resolves the logical name to the OS-resource
      * @param filename
@@ -39,9 +94,15 @@ public interface FilenameToStream
      *
      * @param moduleName
      * @return
+	 * @see tla2sany.modanalyzer.ParseUnit.isLibraryModule()
+	 * @see StandardModules.isDefinedInStandardModule()
      */
     public boolean isStandardModule(String moduleName) ;
-    
+
+	default boolean isLibraryModule(String moduleName) {
+		return isStandardModule(moduleName);
+	}
+   
 	static final String TMPDIR = System.getProperty("java.io.tmpdir");
 
 	static boolean isInJar(final String aString) {
diff --git a/tlatools/src/util/InternTable.java b/tlatools/src/util/InternTable.java
index aec111a2f4ac973b67ab766bd22d43e244f48945..92dba8b5348ee9d5c72ca5a59ebfff6131b478f3 100644
--- a/tlatools/src/util/InternTable.java
+++ b/tlatools/src/util/InternTable.java
@@ -6,6 +6,8 @@ import java.io.EOFException;
 import java.io.File;
 import java.io.IOException;
 import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
 
 import tlc2.output.EC;
 import tlc2.tool.distributed.InternRMI;
@@ -196,4 +198,26 @@ public final class InternTable implements Serializable
 		this.internSource = source;
 	}
 
+	public UniqueString find(final String str) {
+        for (int i = 0; i < this.table.length; i++)
+        {
+            UniqueString var = this.table[i];
+            if (var != null && str.equals(var.toString()))
+            {
+                return var;
+            }
+        }
+        return null;
+	}
+
+	public final Map<String, UniqueString> toMap() {
+		final Map<String, UniqueString> map = new HashMap<String, UniqueString>();
+		for (int i = 0; i < this.table.length; i++) {
+			UniqueString var = this.table[i];
+			if (var != null) {
+				map.put(var.toString(), var);
+			}
+		}
+		return map;
+	}
 }
diff --git a/tlatools/src/util/MailSender.java b/tlatools/src/util/MailSender.java
index bcec703dd1fa661fbd7cf66f754282ca608f8743..a9c36bfe5321db313506f7873261313ae0f93c96 100644
--- a/tlatools/src/util/MailSender.java
+++ b/tlatools/src/util/MailSender.java
@@ -101,9 +101,9 @@ public class MailSender {
 		if (mailto != null) {
 			// Record/Log output to later send it by email
 			final String tmpdir = System.getProperty("java.io.tmpdir");
-			this.out = new File(tmpdir + File.separator + "MC.out");
+			this.out = new File(tmpdir + File.separator + TLAConstants.Files.MODEL_CHECK_OUTPUT_FILE);
 			ToolIO.out = new LogPrintStream(out);
-			this.err = new File(tmpdir + File.separator + "MC.err");
+			this.err = new File(tmpdir + File.separator + TLAConstants.Files.MODEL_CHECK_ERROR_FILE);
 			ToolIO.err = new ErrLogPrintStream(err);
 		}
 	}
diff --git a/tlatools/src/util/SimpleFilenameToStream.java b/tlatools/src/util/SimpleFilenameToStream.java
index 3a8f22efc334c2e14380a49eb1392eb597543c77..e1a088cb9c7de6f49417e9eaf3c407ec3d28f931 100644
--- a/tlatools/src/util/SimpleFilenameToStream.java
+++ b/tlatools/src/util/SimpleFilenameToStream.java
@@ -192,7 +192,7 @@ public class SimpleFilenameToStream implements FilenameToStream {
     while (true)
     {
         if ((idx == 0) && (ToolIO.getUserDir() != null)) {
-            sourceFile = new File(ToolIO.getUserDir(), name );
+            sourceFile = new TLAFile(ToolIO.getUserDir(), name, this );
         }
         else
         {
@@ -208,7 +208,7 @@ public class SimpleFilenameToStream implements FilenameToStream {
 					sourceFile = read(name, is);
 				}
         	} else {
-        		sourceFile = new File( prefix + name );
+        		sourceFile = new TLAFile( prefix + name, true, this );
         	}
         }
         // Debug
@@ -235,7 +235,7 @@ public class SimpleFilenameToStream implements FilenameToStream {
   } // end locate()
 
   private File read(String name, InputStream is) {
-    final File sourceFile = new File(TMPDIR + File.separator + name);
+    final File sourceFile = new TLAFile(TMPDIR + File.separator + name, true, this);
 	sourceFile.deleteOnExit();
 	try {
 
@@ -280,11 +280,11 @@ public class SimpleFilenameToStream implements FilenameToStream {
       {
           // SZ Feb 20, 2009:
           // Make sure the file name ends with ".tla".
-          if (name.toLowerCase().endsWith(".tla"))
+          if (name.toLowerCase().endsWith(TLAConstants.Files.TLA_EXTENSION))
           {
-              name = name.substring(0, name.length() - 4);
+              name = name.substring(0, (name.length() - TLAConstants.Files.TLA_EXTENSION.length()));
           }
-          sourceFileName = name + ".tla";
+          sourceFileName = name + TLAConstants.Files.TLA_EXTENSION;
       } else
       {
           // SZ Feb 20, 2009: for other files
@@ -309,6 +309,8 @@ public class SimpleFilenameToStream implements FilenameToStream {
 	 * This method is used to set the isStandard field of the module's ModuleNode.
 	 * I don't know if this is every called with a module that
 	 * Added by LL on 24 July 2013.
+	 * @see tla2sany.modanalyzer.ParseUnit.isLibraryModule()
+	 * @see StandardModules.isDefinedInStandardModule()
 	 */
 	public boolean isStandardModule(String moduleName) {
 		 File file = this.resolve(moduleName, true) ;
diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/StringHelper.java b/tlatools/src/util/StringHelper.java
similarity index 82%
rename from org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/StringHelper.java
rename to tlatools/src/util/StringHelper.java
index 1685f3da1608036f486e0ea02651246ddb1b89d7..8c13a928c5400c3d163bbe5a7fd4fb4f18b75edc 100644
--- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/StringHelper.java
+++ b/tlatools/src/util/StringHelper.java
@@ -1,22 +1,16 @@
-/**
- * 
- */
-package org.lamport.tla.toolbox.util;
+package util;
 
 /**
  * Contains some useful methods for manipulating strings.
  * 
  * @author lamport
- *
  */
-public class StringHelper
-{
-    
+public class StringHelper {
     /*
      * The following defines newline to be a new-line character in whatever
      * system this is.
      */
-    public static String newline = System.getProperty("line.separator");
+    public static String PLATFORM_NEWLINE = System.getProperty("line.separator");
 
     /**
      * Returns the result of concatenating 'copies' copies of string str, 
@@ -41,7 +35,7 @@ public class StringHelper
      *   }
      * }
      */
-    public static final String copyString(String str, int copies) {
+    public static final String copyString(final String str, final int copies) {
         String result = "";
         String powerOf2Copies = str;
         int    remaining = copies;
@@ -57,18 +51,17 @@ public class StringHelper
         return result;
     }
     
-    
     /**
      *  Returns true if the string str contains only whitespace 
      */
-    public static final boolean onlySpaces(String str) {
+    public static final boolean onlySpaces(final String str) {
         return str.trim().equals("");
     }
     
     /**
      * Returns str with any leading whitespace removed. 
      */
-    public static final String trimFront(String str) {
+    public static final String trimFront(final String str) {
         int position = 0;
         while ((position < str.length()) && 
                 Character.isWhitespace(str.charAt(position))) {
@@ -83,7 +76,7 @@ public class StringHelper
     /**
      * Returns str with any terminating whitespace removed. 
      */
-    public static final String trimEnd(String str) {
+    public static final String trimEnd(final String str) {
         int position = str.length();
         while ((position > 0) && 
                 Character.isWhitespace(str.charAt(position - 1))) {
@@ -100,7 +93,7 @@ public class StringHelper
      * @param str
      * @return
      */
-    public static final int leadingSpaces(String str) {
+    public static final int leadingSpaces(final String str) {
         return str.length() - trimFront(str).length() ;
     }
     
@@ -108,7 +101,7 @@ public class StringHelper
      * Prints the elements of the array, one per line, enclosed between
      * *- and -*, except with the first line enclosed with 0- and -0.
      */
-    public static final void printArray(Object[] array) {
+    public static final void printArray(final Object[] array) {
         if (array == null) {
             System.out.println("null array");
             return;
@@ -129,8 +122,8 @@ public class StringHelper
      * @param str
      * @return
      */
-    public static final String[] getWords(String str) {
-        String[] result = trimFront(str).split("\\s+") ;
+    public static final String[] getWords(final String str) {
+    	final String[] result = trimFront(str).split("\\s+") ;
         return result;
     }
     
@@ -141,8 +134,7 @@ public class StringHelper
      * @param str
      * @return
      */
-    public static final boolean isIdentifier(String str) {
-        
+    public static final boolean isIdentifier(final String str) {
         boolean result = true ;
         boolean allChars = true ;
         int i = 0;
diff --git a/tlatools/src/util/TLAConstants.java b/tlatools/src/util/TLAConstants.java
new file mode 100644
index 0000000000000000000000000000000000000000..a8a4aaa1cae79d4bdd00da8a50ab447be472bf3a
--- /dev/null
+++ b/tlatools/src/util/TLAConstants.java
@@ -0,0 +1,143 @@
+package util;
+
+/**
+ * A class of bits of keywords, operators, and bears.
+ */
+public final class TLAConstants {
+	public final class ANSI {
+		public static final String BOLD_CODE = "\033[1m";
+		public static final String ITALIC_CODE = "\033[3m";
+		public static final String RESET_CODE = "\033[0m";
+	}
+	
+	public final class BuiltInModules {
+		public static final String TLC = "TLC";
+		public static final String TRACE_EXPRESSIONS = "Toolbox";
+	}
+	
+	public final class BuiltInOperators {
+		public static final String PERMUTATIONS = "Permutations";
+	}
+	
+	public final class Files {
+	    public static final String CONFIG_EXTENSION = ".cfg";
+	    public static final String ERROR_EXTENSION = ".err";
+	    public static final String OUTPUT_EXTENSION = ".out";
+	    public static final String TLA_EXTENSION = ".tla";
+		
+		public static final String MODEL_CHECK_FILE_BASENAME = "MC";
+		public static final String MODEL_CHECK_CONFIG_FILE = MODEL_CHECK_FILE_BASENAME + CONFIG_EXTENSION;
+		public static final String MODEL_CHECK_ERROR_FILE = MODEL_CHECK_FILE_BASENAME + ERROR_EXTENSION;
+		public static final String MODEL_CHECK_OUTPUT_FILE = MODEL_CHECK_FILE_BASENAME + OUTPUT_EXTENSION;
+		public static final String MODEL_CHECK_TLA_FILE = MODEL_CHECK_FILE_BASENAME + TLA_EXTENSION;
+	}
+	
+	public final class KeyWords {
+		public static final String ACTION_CONSTRAINT = "ACTION_CONSTRAINT";
+	    public static final String CONSTANT = "CONSTANT";
+	    public static final String CONSTANTS = CONSTANT + 'S';
+	    public static final String EXTENDS = "EXTENDS";
+	    public static final String INIT = "INIT";
+	    public static final String INVARIANT = "INVARIANT";
+	    public static final String MODULE = "MODULE";
+	    public static final String NEXT = "NEXT";
+	    public static final String PROPERTY = "PROPERTY";
+	    public static final String SPECIFICATION = "SPECIFICATION";
+	    public static final String SYMMETRY = "SYMMETRY";
+	    public static final String TRUE = "TRUE";
+	    public static final String UNION = "\\union";
+	    public static final String VARIABLE = "VARIABLE";
+	}
+	
+	public final class LoggingAtoms {
+		public static final String PARSING_FILE = "Parsing file";
+	}
+    
+	public final class Schemes {
+		public static final String SPEC_SCHEME = "spec";
+		public static final String INIT_SCHEME = "init";
+		public static final String NEXT_SCHEME = "next";
+		public static final String CONSTANT_SCHEME = "const";
+		public static final String SYMMETRY_SCHEME = "symm";
+		public static final String DEFOV_SCHEME = "def_ov";
+		public static final String CONSTRAINT_SCHEME = "constr";
+		public static final String ACTIONCONSTRAINT_SCHEME = "action_constr";
+		public static final String INVARIANT_SCHEME = "inv";
+		public static final String PROP_SCHEME = "prop";
+		public static final String VIEW_SCHEME = "view";
+		public static final String CONSTANTEXPR_SCHEME = "const_expr";
+		public static final String TRACE_EXPR_VAR_SCHEME = "__trace_var";
+		public static final String TRACE_EXPR_DEF_SCHEME = "trace_def";
+	}
+	
+	public final class TraceExplore {
+	    public static final String ERROR_STATES_MODULE_NAME = "SpecTE";
+	    public static final String EXPLORATION_MODULE_NAME = "TE";
+		public static final String ACTION = "_TEAction";
+		public static final String POSITION = "_TEPosition";
+		public static final String TRACE = "_TETrace";
+	    /**
+	     * expressions to be evaluated at each state of the trace
+	     * when the trace explorer is run
+	     */
+	    public static final String TRACE_EXPLORE_EXPRESSIONS = "traceExploreExpressions";
+	    /**
+	     * Conjunction of variable values in the initial state of a trace
+	     * Should only include spec variables, not trace expression variables.
+	     */
+	    public static final String TRACE_EXPLORE_INIT = "traceExploreInit";
+	    /**
+	     * Disjunction of actions used for trace exploration without the trace
+	     * expression variables.
+	     */
+	    public static final String TRACE_EXPLORE_NEXT = "traceExploreNext";
+	    /**
+	     * The tuple of ordered sub-action names representing the trace states. 
+	     */
+	    public static final String TRACE_EXPLORE_ACTION_CONSTRAINT = "traceExploreActionConstraint";
+	}
+
+	
+	public static final String BACK_TO_STATE = "Back to state";
+	public static final String GENERATION_TIMESTAMP_PREFIX = "\\* Generated on ";
+	public static final String LINE = "line ";
+	public static final String STUTTERING = " Stuttering";
+	
+	public static final String MODULE_OPENING_PREFIX_REGEX = "^([-]+ " + TLAConstants.KeyWords.MODULE + ") ";
+	public static final String MODULE_CLOSING_REGEX = "^[=]+$";
+
+    public static final String SPACE = " ";
+    public static final String INDENT = "    ";
+    public static final String CR = "\n";
+    public static final String SEP = "----";
+    public static final String EQ = " = ";
+    public static final String ARROW = " <- ";
+    public static final String RECORD_ARROW = " |-> ";
+    public static final String DEFINES = " == ";
+    public static final String DEFINES_CR = " ==\n";
+    public static final String COMMENT = "\\* ";
+    public static final String ATTRIBUTE = "@";
+    public static final String COLON = ":";
+    public static final String EMPTY_STRING = "";
+    public static final String CONSTANT_EXPRESSION_EVAL_IDENTIFIER = "\"$!@$!@$!@$!@$!\"";
+    public static final String COMMA = ",";
+    public static final String BEGIN_TUPLE = "<<";
+    public static final String END_TUPLE = ">>";
+    public static final String PRIME = "'";
+    public static final String QUOTE = "\"";
+    public static final String TLA_AND = "/\\";
+    public static final String TLA_OR = "\\/";
+    public static final String TLA_NOT = "~";
+    public static final String TLA_EVENTUALLY_ALWAYS = "<>[]";
+    public static final String TLA_INF_OFTEN = "[]<>";
+    public static final String TRACE_NA = "\"--\"";
+    public static final String L_PAREN = "(";
+    public static final String R_PAREN = ")";
+    public static final String L_SQUARE_BRACKET = "[";
+    public static final String R_SQUARE_BRACKET = "]";
+
+    public static final String INDENTED_CONJUNCTIVE = TLAConstants.INDENT + TLAConstants.TLA_AND + TLAConstants.SPACE;
+    public static final String INDENTED_DISJUNCTIVE = TLAConstants.INDENT + TLAConstants.TLA_OR + TLAConstants.SPACE;
+    
+	private TLAConstants() { }
+}
diff --git a/tlatools/src/util/TLAFlightRecorder.java b/tlatools/src/util/TLAFlightRecorder.java
new file mode 100644
index 0000000000000000000000000000000000000000..a2ca81232961c5b29e8cc5f14b244cdf9a82fbd1
--- /dev/null
+++ b/tlatools/src/util/TLAFlightRecorder.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package util;
+
+// Label is only used by Mission control but not relevant for the recording itself.
+public class TLAFlightRecorder {
+	
+    @jdk.jfr.Label("Progress")
+    @jdk.jfr.Category({"TLC", "Progress"})
+    @jdk.jfr.StackTrace(false)// No need to capture the stack of the reporting (main) thread when it emits the event.
+	private static class ProgressEvent extends jdk.jfr.Event {
+		@jdk.jfr.Label("States generated per minute")
+		@jdk.jfr.Unsigned
+		private long spm;
+		@jdk.jfr.Label("Distinct states generated per minute")
+		@jdk.jfr.Unsigned
+		private long dspm;
+		@jdk.jfr.Label("Unseen States")
+		@jdk.jfr.Unsigned
+		private long unseen;
+		@jdk.jfr.Label("Diameter")
+		@jdk.jfr.Unsigned
+		private int diameter;
+		@jdk.jfr.Label("States Generated")
+		@jdk.jfr.Unsigned
+		private long states;
+		@jdk.jfr.Label("Distinct States Generated")
+		@jdk.jfr.Unsigned
+		private long distStates;
+		@jdk.jfr.Label("Model Checking done")
+		private boolean isFinal;
+	}
+
+	public static void progress(boolean isFinal, final int diameter, final long states, final long distinctStates, final long unseen,
+			final long statesPerMinute, final long distinctStatesPerMinute) {
+		try {
+			final ProgressEvent e = new ProgressEvent();
+			e.isFinal = isFinal;
+			e.spm = statesPerMinute;
+			e.dspm = distinctStatesPerMinute;
+			e.diameter = diameter;
+			e.unseen = unseen;
+			e.states = states;
+			e.distStates = distinctStates;
+			e.commit();
+		} catch (NoClassDefFoundError e) {
+			// Java 1.8 doesn't have jdk.jfr.Event and thus this flight recording is broken.
+		}
+	}
+	
+    @jdk.jfr.Label("Message")
+    @jdk.jfr.Category({"TLC"})
+    @jdk.jfr.StackTrace(false)// No need to capture the stack of the reporting (main) thread when it emits the event.
+	private static class MessageEvent extends jdk.jfr.Event {
+		@jdk.jfr.Label("Message")
+		public String message;
+    }
+
+	public static String message(final String message) {
+		try {
+			final MessageEvent e = new MessageEvent();
+			e.message = message;
+			e.commit();
+		} catch (NoClassDefFoundError e) {
+			// Java 1.8 doesn't have jdk.jfr.Event and thus this flight recording is broken.
+		}
+		return message;
+	}
+}
\ No newline at end of file
diff --git a/tlatools/src/util/UniqueString.java b/tlatools/src/util/UniqueString.java
index f9b06ea0365d4b3489e57a3ef4bca04509cccd43..b2fcff0e504afec44953b644f227063d3d588601 100644
--- a/tlatools/src/util/UniqueString.java
+++ b/tlatools/src/util/UniqueString.java
@@ -4,6 +4,7 @@ package util;
 
 import java.io.IOException;
 import java.io.Serializable;
+import java.util.Map;
 
 import tlc2.tool.Defns;
 import tlc2.tool.TLCState;
@@ -304,6 +305,15 @@ public final class UniqueString implements Serializable
         String str = dis.readString(slen);
         return new UniqueString(str, tok1, loc1);
     }
+    
+    public static UniqueString read(IDataInputStream dis, final Map<String, UniqueString> tbl) throws IOException
+    {
+        dis.readInt(); // skip, because invalid for the given internTbl
+        dis.readInt(); // skip, because invalid for the given internTbl
+        final int slen = dis.readInt();
+        final String str = dis.readString(slen);
+        return tbl.get(str);
+    }
 
 
     /**
diff --git a/tlatools/src/util/UsageGenerator.java b/tlatools/src/util/UsageGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..6f00329bbc3999dd5c0742ab5520da602b4b5943
--- /dev/null
+++ b/tlatools/src/util/UsageGenerator.java
@@ -0,0 +1,373 @@
+package util;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A helper class to print usage text for a command-line-application in a motif reminiscent of manpages.
+ *  
+ * In a world where we were not concerned with jar size, i would import Apache Commons CLI and take advantage
+ * 	of those classes.
+ */
+public class UsageGenerator {
+	private static final String NAME = "NAME";
+	private static final String SYNOPSIS = "SYNOPSIS";
+	private static final String DESCRIPTION = "DESCRIPTION";
+	private static final String OPTIONS = "OPTIONS";
+	private static final String TIPS = "TIPS";
+	
+	private static Comparator<Argument> NAME_COMPARATOR = new Comparator<Argument>() {
+		@Override
+		public int compare(final Argument a, final Argument b) {
+			return a.getArgumentName().compareTo(b.getArgumentName());
+		}
+	};
+	
+	private static Comparator<Argument> NAME_DASH_COMPARATOR = new Comparator<Argument>() {
+		@Override
+		public int compare(final Argument a, final Argument b) {
+			final boolean aDash = a.isDashArgument();
+			final boolean bDash = b.isDashArgument();
+			
+			if (aDash != bDash) {
+				return aDash ? -1 : 1;
+			}
+			
+			return a.getArgumentName().compareTo(b.getArgumentName());
+		}
+	};
+	
+	
+	public static void displayUsage(final PrintStream ps, final String commandName, final String version,
+									final String commandShortSummary, final String commandDescription,
+									final List<List<Argument>> commandVariants, final List<String> tips,
+									final char valuedArgumentsSeparator) {
+		ps.println();
+		ps.println(generateSectionHeader(NAME));
+		ps.println('\t' + commandName + " - " + commandShortSummary
+						+ ((version != null) ? (" - " + version) : "") + "\n\n");
+
+		
+		final String boldName = markupWord(commandName, true);
+		
+		
+		final HashSet<Argument> arguments = new HashSet<>();
+		ps.println(generateSectionHeader(SYNOPSIS));
+		for (final List<Argument> variant : commandVariants) {
+			ps.println("\t" + generateCommandForVariant(boldName, variant, arguments, valuedArgumentsSeparator));
+		}
+		ps.println();
+		
+		
+		final String commandNameRegex = commandName + "(\\)|\\s|$)";
+		final Pattern p = Pattern.compile(commandNameRegex);
+		final Matcher m = p.matcher(commandDescription);
+		final String markedUpDescription;
+		if (m.find()) {
+			final StringBuilder sb = new StringBuilder();
+			
+			if (m.start() > 0) {
+				sb.append(commandDescription.substring(0, m.start()));
+			}
+			sb.append(boldName).append(m.group(1));
+			
+			int lastEnd = m.end();
+			while (m.find()) {
+				sb.append(commandDescription.substring(lastEnd, m.start())).append(boldName).append(m.group(1));
+				lastEnd = m.end();
+			}
+			sb.append(commandDescription.substring(lastEnd, commandDescription.length()));
+			
+			markedUpDescription = sb.toString();
+		} else {
+			markedUpDescription = commandDescription;
+		}
+		
+		ps.println(generateSectionHeader(DESCRIPTION));
+		ps.println("\t" + markedUpDescription.replaceAll("(\\r\\n|\\r|\\n)", "\n\t"));
+		ps.println();
+		
+		
+		final List<Argument> orderedArguments = new ArrayList<>(arguments);
+		Collections.sort(orderedArguments, NAME_COMPARATOR);
+		ps.println(generateSectionHeader(OPTIONS));
+		for (final Argument arg : orderedArguments) {
+			if (arg.expectsValue() || arg.isOptional() || (!arg.expectsValue() && arg.isDashArgument())) {
+				ps.println(generateOptionText(arg, valuedArgumentsSeparator));
+			}
+		}
+		ps.println();
+		
+		
+		if ((tips != null) && (tips.size() > 0)) {
+			ps.println(generateSectionHeader(TIPS));
+			for (final String tip : tips) {
+				ps.println("\t" + tip.replaceAll("(\\r\\n|\\r|\\n)", "\n\t") + "\n");
+			}
+		}
+	}
+	
+	private static String generateCommandForVariant(final String boldedCommandName, final List<Argument> variant,
+													final HashSet<Argument> arguments,
+													final char valuedArgumentsSeparator) {
+		final List<Argument> optionalSingleDashValueless = new ArrayList<>();
+		final List<Argument> optionalDoubleDashValueless = new ArrayList<>();
+		final List<Argument> optionalValued = new ArrayList<>();
+		final List<Argument> requiredValued = new ArrayList<>();
+		final List<Argument> requiredValueless = new ArrayList<>();
+		
+		for (final Argument arg : variant) {
+			if (arg.expectsValue()) {
+				if (arg.isOptional()) {
+					optionalValued.add(arg);
+				} else {
+					requiredValued.add(arg);
+				}
+			} else {
+				if (arg.isOptional()) {
+					if (arg.isDashArgument()) {
+						optionalSingleDashValueless.add(arg);
+					} else if (arg.isDashDashArgument()) {
+						optionalDoubleDashValueless.add(arg);
+					}
+				} else {
+					requiredValueless.add(arg);
+				}
+			}
+		}
+
+		Collections.sort(optionalSingleDashValueless, NAME_COMPARATOR);
+		Collections.sort(optionalDoubleDashValueless, NAME_COMPARATOR);
+		Collections.sort(optionalValued, NAME_COMPARATOR);
+		Collections.sort(requiredValued, NAME_COMPARATOR);
+		Collections.sort(requiredValueless, NAME_DASH_COMPARATOR);
+
+		final StringBuilder sb = new StringBuilder(boldedCommandName);
+		
+		if (optionalSingleDashValueless.size() > 0) {
+			final StringBuilder concatenation = new StringBuilder("-");
+			final List<Argument> nonShortArguments = new ArrayList<>();
+			for (final Argument arg : optionalSingleDashValueless) {
+				if (arg.isShortArgument()) {
+					concatenation.append(arg.getDashlessArgumentName());
+				} else {
+					nonShortArguments.add(arg);
+				}
+			}
+			if (concatenation.length() > 1) {
+				sb.append(" [").append(markupWord(concatenation.toString(), true)).append(']');
+			}
+			
+			for (final Argument arg : nonShortArguments) {
+				sb.append(" [").append(markupWord(("-" + arg.getDashlessArgumentName()), true));
+				if (arg.hasSubOptions()) {
+					sb.append(" [").append(arg.getSubOptions()).append("]");
+				}
+				sb.append(']');
+			}
+		}
+		
+		if (optionalDoubleDashValueless.size() > 0) {
+			for (final Argument arg : optionalDoubleDashValueless) {
+				sb.append(" [").append(markupWord(arg.getArgumentName(), true));
+				if (arg.hasSubOptions()) {
+					sb.append(" [").append(arg.getSubOptions()).append("]");
+				}
+				sb.append(']');
+			}
+		}
+		
+		if (optionalValued.size() > 0) {
+			for (final Argument arg : optionalValued) {
+				sb.append(" [").append(markupWord(arg.getArgumentName(), true)).append(valuedArgumentsSeparator);
+				if (arg.hasSubOptions()) {
+					sb.append("[").append(arg.getSubOptions()).append("] ");
+				}
+				sb.append(markupWord(arg.getSampleValue(), false)).append(']');
+			}
+		}
+		
+		if (requiredValued.size() > 0) {
+			for (final Argument arg : requiredValued) {
+				sb.append(" ").append(markupWord(arg.getArgumentName(), true)).append(valuedArgumentsSeparator);
+				sb.append(markupWord(arg.getSampleValue(), false));
+			}
+		}
+		
+		if (requiredValueless.size() > 0) {
+			for (final Argument arg : requiredValueless) {
+				sb.append(" ").append(arg.getArgumentName());
+				if (arg.hasSubOptions()) {
+					sb.append(" [").append(arg.getSubOptions()).append("]");
+				}
+			}
+		}
+		
+		arguments.addAll(variant);
+		
+		return sb.toString();
+	}
+	
+	private static String generateOptionText(final Argument argument, final char valuedArgumentsSeparator) {
+		final StringBuilder sb = new StringBuilder("\t");
+
+		sb.append(markupWord(argument.getArgumentName(), true));
+		if (argument.expectsValue()) {
+			sb.append(valuedArgumentsSeparator).append(markupWord(argument.getSampleValue(), false));
+		}
+		sb.append("\n\t\t").append(argument.getDescription().replaceAll("(\\r\\n|\\r|\\n)", "\n\t\t"));
+
+		return sb.toString();
+	}
+		
+	private static String generateSectionHeader(final String title) {
+		final StringBuilder sb = new StringBuilder(markupWord(title, true));
+		
+		sb.append('\n');
+		
+		return sb.toString();
+	}
+	
+	/**
+	 * @param bold if true, the word will be bolded; false, the word will be italicized
+	 */
+	private static String markupWord(final String word, final boolean bold) {
+		final StringBuilder sb = new StringBuilder(bold ? TLAConstants.ANSI.BOLD_CODE : TLAConstants.ANSI.ITALIC_CODE);
+		
+		sb.append(word).append(TLAConstants.ANSI.RESET_CODE);
+		
+		return sb.toString();
+	}
+	
+	
+	public static class Argument {
+		private final String argumentName;
+		private final String sampleValue;
+		private final String description;
+		private final boolean optional;
+		private final String subOptions;
+		
+		/**
+		 * This calls {@code this(key, optionDescription, false);}
+		 * 
+		 * @param key
+		 * @param optionDescription
+		 */
+		public Argument(final String key, final String optionDescription) {
+			this(key, optionDescription, false);
+		}
+		
+		public Argument(final String key, final String optionDescription, final boolean isOptional) {
+			this(key, null, optionDescription, isOptional);
+		}
+		
+		/**
+		 * This calls {@code this(key, exampleValue, optionDescription, false);}
+		 */
+		public Argument(final String key, final String exampleValue, final String optionDescription) {
+			this(key, exampleValue, optionDescription, false);
+		}
+		
+		public Argument(final String key, final String exampleValue, final String optionDescription,
+						final boolean isOptional) {
+			this(key, exampleValue, optionDescription, isOptional, null);
+		}
+		
+		public Argument(final String key, final String exampleValue, final String optionDescription,
+						final boolean isOptional, final String concatenatedSuboptions) {
+			argumentName = key;
+			sampleValue = exampleValue;
+			description = optionDescription;
+			optional = isOptional;
+			subOptions = concatenatedSuboptions;
+		}
+		
+		public boolean isOptional() {
+			return optional;
+		}
+		
+		public boolean expectsValue() {
+			return (sampleValue != null);
+		}
+		
+		/**
+		 * @return if the argument name starts with "-", but not "--", this returns true
+		 */
+		public boolean isDashArgument() {
+			return argumentName.startsWith("-") && !isDashDashArgument();
+		}
+		
+		public boolean isDashDashArgument() {
+			return argumentName.startsWith("--");
+		}
+		
+		/**
+		 * @return true if the argument name is of length 1 (two if this is a dash argument)
+		 */
+		public boolean isShortArgument() {
+			return ((isDashArgument() && (argumentName.length() == 2)) || (argumentName.length() == 1));
+		}
+		
+		public boolean hasSubOptions() {
+			return (subOptions != null);
+		}
+
+		public String getArgumentName() {
+			return argumentName;
+		}
+		
+		/**
+		 * @return if {@link #isDashArgument()} returns true, this retuns the argument name without the prefacing dash,
+		 * 				otherwise this returns the entire argument name
+		 */
+		public String getDashlessArgumentName() {
+			if (isDashArgument()) {
+				return argumentName.substring(1);
+			}
+			
+			return argumentName;
+		}
+
+		public String getSampleValue() {
+			return sampleValue;
+		}
+
+		public String getDescription() {
+			return description;
+		}
+		
+		public String getSubOptions() {
+			return subOptions;
+		}
+
+		@Override
+		public int hashCode() {
+			return Objects.hash(argumentName);
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			if (this == obj) {
+				return true;
+			}
+			
+			if (obj == null) {
+				return false;
+			}
+			
+			if (getClass() != obj.getClass()) {
+				return false;
+			}
+			
+			final Argument other = (Argument) obj;
+			return Objects.equals(argumentName, other.argumentName);
+		}
+	}
+}
diff --git a/tlatools/test-benchmark/tlc2/tool/ModuleOverwritesBenchmark.java b/tlatools/test-benchmark/tlc2/tool/ModuleOverwritesBenchmark.java
index 63cdafccd933b37374ac106c91349f1ecf544e8b..cbfe6e8b04fd90ab7052e18f6abc286760f00e97 100644
--- a/tlatools/test-benchmark/tlc2/tool/ModuleOverwritesBenchmark.java
+++ b/tlatools/test-benchmark/tlc2/tool/ModuleOverwritesBenchmark.java
@@ -34,7 +34,7 @@ import org.openjdk.jmh.annotations.Benchmark;
 import org.openjdk.jmh.annotations.Scope;
 import org.openjdk.jmh.annotations.State;
 
-import tlc2.tool.impl.Tool;
+import tlc2.tool.impl.FastTool;
 import tlc2.value.impl.FcnRcdValue;
 import tlc2.value.impl.Value;
 import util.SimpleFilenameToStream;
@@ -62,7 +62,7 @@ public class ModuleOverwritesBenchmark {
 		System.err.println(dir);
 		ToolIO.setUserDir(dir);
 
-		tool = new Tool("", "ModuleOverwrites", "ModuleOverwrites", new SimpleFilenameToStream());
+		tool = new FastTool("", "ModuleOverwrites", "ModuleOverwrites", new SimpleFilenameToStream());
 
 		state = (TLCStateMut) tool.getInitStates().elementAt(0);
 	}
diff --git a/tlatools/test-benchmark/tlc2/util/FP64Benchmark.java b/tlatools/test-benchmark/tlc2/util/FP64Benchmark.java
new file mode 100644
index 0000000000000000000000000000000000000000..c1c2010f55ce0eed05d59c78a00817e7a5fb625e
--- /dev/null
+++ b/tlatools/test-benchmark/tlc2/util/FP64Benchmark.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved.
+ *
+ * The MIT License (MIT)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.util;
+
+import java.io.IOException;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+
+@State(Scope.Benchmark)
+public class FP64Benchmark {
+
+	/*
+	 * Run with: java -jar target/benchmarks.jar -wi 2 -i 2 -f2 -rf json -rff
+	 * FP64Benchmark-$(date +%s)-$(git rev-parse --short HEAD).json
+	 * -jvmArgsPrepend "-Xms8192m -Xmx8192m" -jvmArgsAppend tlc2.util.FP64Benchmark "
+	 */
+
+    @Setup
+    public void up() throws IOException {
+    	FP64.Init();
+    }
+    
+    @Benchmark
+    public long extendIntLoop() {
+    	return FP64.ExtendLoop(72316478964978L, 3876421);
+    }
+
+    @Benchmark
+    public long extendIntUnrolled() {
+    	return FP64.Extend(72316478964978L, 3876421);
+    }
+
+}
diff --git a/tlatools/test-long/tlc2/tool/liveness/NoTableauSpecTest.java b/tlatools/test-long/tlc2/tool/liveness/NoTableauSpecTest.java
index 87779edbc369c33844c2c7f8da33fa437a98d23f..c4dd39a04c4bf1fc388abb9ea32d7c1c113a2ccb 100644
--- a/tlatools/test-long/tlc2/tool/liveness/NoTableauSpecTest.java
+++ b/tlatools/test-long/tlc2/tool/liveness/NoTableauSpecTest.java
@@ -25,9 +25,11 @@
  ******************************************************************************/
 package tlc2.tool.liveness;
 
+import util.TLAConstants;
+
 public class NoTableauSpecTest extends MultiThreadedSpecTest {
 
 	public NoTableauSpecTest() {
-		super("MC", "VoteProof", "137297983", "693930", 0.25d, 0.25d);
+		super(TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, "VoteProof", "137297983", "693930", 0.25d, 0.25d);
 	}
 }
diff --git a/tlatools/test-long/tlc2/tool/liveness/TableauSpecTest.java b/tlatools/test-long/tlc2/tool/liveness/TableauSpecTest.java
index a2789e1a5b8e91e542adddf8f6ac64fa0c3b58d5..332b7f4205975224cd3ad3525d44a244203b7ae7 100644
--- a/tlatools/test-long/tlc2/tool/liveness/TableauSpecTest.java
+++ b/tlatools/test-long/tlc2/tool/liveness/TableauSpecTest.java
@@ -25,9 +25,11 @@
  ******************************************************************************/
 package tlc2.tool.liveness;
 
+import util.TLAConstants;
+
 public class TableauSpecTest extends MultiThreadedSpecTest {
 
 	public TableauSpecTest() {
-		super("MC", "EWD840", new String[] {"-maxSetSize", "9000000"}, "540765192", "10487806", 0.3d, 0.3d);
+		super(TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, "EWD840", new String[] {"-maxSetSize", "9000000"}, "540765192", "10487806", 0.3d, 0.3d);
 	}
 }
diff --git a/tlatools/test-model/CallGotoUnlabeledTest.tla b/tlatools/test-model/CallGotoUnlabeledTest.tla
index f8eb948eef286115e24c5a588c3af372948a8e80..9fe0642ff8ab380047d4ae69554e538e56fd8cd7 100644
--- a/tlatools/test-model/CallGotoUnlabeledTest.tla
+++ b/tlatools/test-model/CallGotoUnlabeledTest.tla
@@ -22,7 +22,7 @@ C:
   goto A;
 
 end algorithm *)
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-4786c31224fe8555dc7ad50128a92fc6
 VARIABLES x, pc, stack
 
 vars == << x, pc, stack >>
@@ -66,6 +66,6 @@ Spec == Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-8ca0b91b1573d7c7ae4c4135afa5f61b
 
 ====
diff --git a/tlatools/test-model/CodePlexBug08/InlineMC.cfg b/tlatools/test-model/CodePlexBug08/InlineMC.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..a2b7e06f96db60091276304ced5553107b06b3ee
--- /dev/null
+++ b/tlatools/test-model/CodePlexBug08/InlineMC.cfg
@@ -0,0 +1,4 @@
+CONSTANT
+N = 6
+SPECIFICATION
+Spec
diff --git a/tlatools/test-model/CodePlexBug08/InlineMC.tla b/tlatools/test-model/CodePlexBug08/InlineMC.tla
new file mode 100644
index 0000000000000000000000000000000000000000..e9ff6750e51ebce262d9b91c52fa7e2c2df41324
--- /dev/null
+++ b/tlatools/test-model/CodePlexBug08/InlineMC.tla
@@ -0,0 +1,4 @@
+---- MODULE InlineMC ----
+EXTENDS EWD840, TLC
+
+===================
\ No newline at end of file
diff --git a/tlatools/test-model/Continue.cfg b/tlatools/test-model/Continue.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..b7702f14d2ece8edb2bf761738836a80877cd133
--- /dev/null
+++ b/tlatools/test-model/Continue.cfg
@@ -0,0 +1,7 @@
+INIT Init
+NEXT Next
+
+CONSTRAINT Constraint
+
+INVARIANT Inv1
+INVARIANT Inv2
\ No newline at end of file
diff --git a/tlatools/test-model/Continue.tla b/tlatools/test-model/Continue.tla
new file mode 100644
index 0000000000000000000000000000000000000000..c5330b9ccbe3159e083403d444ec771c0a179105
--- /dev/null
+++ b/tlatools/test-model/Continue.tla
@@ -0,0 +1,20 @@
+---- MODULE Continue ----
+EXTENDS Naturals
+
+VARIABLES x,y
+
+Init == x = 1 /\ y = 1
+
+Next == /\ x' = x + 1 
+        /\ \/ /\ x = 1
+              /\ y' \in {1,2}
+           \/ /\ UNCHANGED y
+
+\* For the test to meaningful, it is vital that workers
+\* actually continue state space exploration after the
+\* first invariant violation (for trace files to be written).
+Inv1 == y < 2
+Inv2 == x < 30
+
+Constraint == Inv1 /\ Inv2
+====
diff --git a/tlatools/test-model/Github361.cfg b/tlatools/test-model/Github361.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..3662e06f049e7c9069b5137ddfc038d9eb799c36
--- /dev/null
+++ b/tlatools/test-model/Github361.cfg
@@ -0,0 +1,4 @@
+INIT
+Init
+NEXT
+Next
\ No newline at end of file
diff --git a/tlatools/test-model/Github361.tla b/tlatools/test-model/Github361.tla
new file mode 100644
index 0000000000000000000000000000000000000000..ec06c2f5c467632330b2f8c671301d81f8186624
--- /dev/null
+++ b/tlatools/test-model/Github361.tla
@@ -0,0 +1,24 @@
+---- MODULE Github361 ----
+EXTENDS TLC, Naturals
+
+Nodes == {1, 2, 3, 4, 5}
+null == 6 \* not in Nodes
+
+Vertices == [nodes : SUBSET Nodes, succ : Nodes \cup {null}, dead : BOOLEAN]
+
+Partitions == {P \in SUBSET Vertices :
+                 /\ \A v1, v2 \in P : 
+                       (v1 # v2) => ((v1.nodes \cap v2.nodes) = {})
+                 /\ \A v \in P : /\ v.nodes # {}
+                                 /\ \E w \in P : \/ v.succ = null
+                                                 \/ v.succ \in w.nodes}     
+
+VARIABLES partition
+
+TypeOK == partition \in Partitions
+
+Init == partition = {}
+
+Next == UNCHANGED partition
+
+=============================================================================
diff --git a/tlatools/test-model/Github391.cfg b/tlatools/test-model/Github391.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tlatools/test-model/Github391.tla b/tlatools/test-model/Github391.tla
new file mode 100644
index 0000000000000000000000000000000000000000..896130f8d9e5fb75ef86f4318c5eb95f916bbbec
--- /dev/null
+++ b/tlatools/test-model/Github391.tla
@@ -0,0 +1,10 @@
+---- MODULE Github391 ----
+EXTENDS Integers
+
+\* IntValue
+x == {1157660672, -989822976}
+y == {-989822976, 1157660672}
+
+ASSUME x = y
+
+=============================================================================
diff --git a/tlatools/test-model/Github407.cfg b/tlatools/test-model/Github407.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..3662e06f049e7c9069b5137ddfc038d9eb799c36
--- /dev/null
+++ b/tlatools/test-model/Github407.cfg
@@ -0,0 +1,4 @@
+INIT
+Init
+NEXT
+Next
\ No newline at end of file
diff --git a/tlatools/test-model/Github407.tla b/tlatools/test-model/Github407.tla
new file mode 100644
index 0000000000000000000000000000000000000000..9e46fcdabd7f28edff63943883f0a1f1397f3b83
--- /dev/null
+++ b/tlatools/test-model/Github407.tla
@@ -0,0 +1,9 @@
+---- MODULE Github407 ----
+Data == {"d1", "d2"}
+
+VARIABLES state
+
+Init == state = {}
+
+Next == \E e \in Data: state' = state \union {e}
+=============================================================================
diff --git a/tlatools/test-model/Github429.tla b/tlatools/test-model/Github429.tla
new file mode 100644
index 0000000000000000000000000000000000000000..8ad0cd5b51170b7d00c1998a5979b9f1e1957d3c
--- /dev/null
+++ b/tlatools/test-model/Github429.tla
@@ -0,0 +1,14 @@
+---- MODULE Github429 ----
+
+---- MODULE Alpha ----
+
+======================
+
+---- MODULE Beta ----
+EXTENDS Alpha
+
+
+VARIABLE y
+======================
+
+==================================
diff --git a/tlatools/test-model/Github432.cfg b/tlatools/test-model/Github432.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..f7daf023446246482952679ff0fba218fdae092f
--- /dev/null
+++ b/tlatools/test-model/Github432.cfg
@@ -0,0 +1,8 @@
+CONSTANT Humans = {%1%}
+CONSTANT Others = {%2%}
+
+INIT Init
+NEXT Next
+SYMMETRY symmetry
+INVARIANT TypeOK
+
diff --git a/tlatools/test-model/Github432.tla b/tlatools/test-model/Github432.tla
new file mode 100644
index 0000000000000000000000000000000000000000..33e33e33fe7db82d0b0f7f9a6ab3c06605d98202
--- /dev/null
+++ b/tlatools/test-model/Github432.tla
@@ -0,0 +1,22 @@
+---- MODULE Github432 ----
+
+EXTENDS TLC
+
+CONSTANT Humans, Others
+
+symmetry == Permutations(Humans) \union Permutations(Others)
+
+VARIABLES set
+
+TypeOK ==
+    /\ set \subseteq Humans
+
+Init ==
+    /\ set = {}
+
+Next ==
+    \E h \in Humans:
+        set' = set \union {h}
+
+==================================
+
diff --git a/tlatools/test-model/LivenessConstraintWarning.cfg b/tlatools/test-model/LivenessConstraintWarning.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..b5dd13e7e5bd487b690bde48224c3aa13061a285
--- /dev/null
+++ b/tlatools/test-model/LivenessConstraintWarning.cfg
@@ -0,0 +1,8 @@
+CONSTRAINT
+Constraint
+
+SPECIFICATION
+Spec
+
+PROPERTY
+Prop
\ No newline at end of file
diff --git a/tlatools/test-model/LivenessConstraintWarning.tla b/tlatools/test-model/LivenessConstraintWarning.tla
new file mode 100644
index 0000000000000000000000000000000000000000..69a8e6a3071d8ce2ba0b9b442924d6f54719abc7
--- /dev/null
+++ b/tlatools/test-model/LivenessConstraintWarning.tla
@@ -0,0 +1,24 @@
+----------------------------- MODULE LivenessConstraintWarning -----------------------------
+EXTENDS Integers, Sequences
+
+VARIABLES pc, history
+vars == <<pc, history>>
+
+Init == /\ pc = "A" 
+        /\ history = <<>>
+
+A == /\ pc  = "A"
+     /\ pc' = "B"
+     /\ history' = history \o <<pc>>
+
+B == /\ pc  = "B"
+     /\ pc' = "A"
+     /\ UNCHANGED history 
+
+Spec == Init /\ [][A \/ B]_vars /\ WF_vars(A \/ B)
+
+Constraint == Len(history) < 3
+
+Prop == <>(pc = "Done")
+
+==============================================================================
diff --git a/tlatools/test-model/PlusCalOptions.cfg b/tlatools/test-model/PlusCalOptions.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..79662a1bb6a95c9fe61024917806a8412009a671
--- /dev/null
+++ b/tlatools/test-model/PlusCalOptions.cfg
@@ -0,0 +1,23 @@
+\* CONSTANT definitions
+CONSTANT
+N <- const_158025887640018000
+\* INVARIANT definition
+INVARIANT
+TypeInvariant
+Invariant
+\* PROPERTY definition
+PROPERTY
+Termination
+\* INIT definition
+INIT
+_SpecTEInit
+\* NEXT definition
+NEXT
+_SpecTENext
+\* Action Constraint definition
+\* ACTION_CONSTRAINT
+\* _SpecTEActionConstraint
+CONSTANT
+_TETrace <- def_ov_15802590929252000
+
+\* Generated on Tue Jan 28 16:51:32 PST 2020
diff --git a/tlatools/test-model/PlusCalOptions.tla b/tlatools/test-model/PlusCalOptions.tla
new file mode 100644
index 0000000000000000000000000000000000000000..30c8db874ee13bdd0b2c3488456448a58a8f8540
--- /dev/null
+++ b/tlatools/test-model/PlusCalOptions.tla
@@ -0,0 +1,597 @@
+@!@!@STARTMSG 1000:0 @!@!@
+Will generate a SpecTE file pair if error states are encountered.
+@!@!@ENDMSG 1000 @!@!@
+@!@!@STARTMSG 2262:0 @!@!@
+TLC2 Version 2.15 of Day Month 20??
+@!@!@ENDMSG 2262 @!@!@
+@!@!@STARTMSG 2187:0 @!@!@
+Running breadth-first search Model-Checking with fp 4 and seed 5688400317107100584 with 1 worker on 12 cores with 2428MB heap and 5460MB offheap memory [pid: 81433] (Mac OS X 10.13.6 x86_64, AdoptOpenJDK 13.0.1 x86_64, OffHeapDiskFPSet, DiskStateQueue).
+@!@!@ENDMSG 2187 @!@!@
+@!@!@STARTMSG 2220:0 @!@!@
+Starting SANY...
+@!@!@ENDMSG 2220 @!@!@
+Parsing file /Users/loki/arbeit/microsoft/dev/tlaplus/runtime-org.lamport.tla.toolbox.product.product.product/QueensPluscal_1579286757638/QueensPluscal.toolbox/FourQueens/MC.tla
+Parsing file /Users/loki/arbeit/microsoft/dev/tlaplus/runtime-org.lamport.tla.toolbox.product.product.product/QueensPluscal_1579286757638/QueensPluscal.toolbox/FourQueens/QueensPluscal.tla
+Parsing file /Users/loki/arbeit/microsoft/dev/quaeler_repo/tlaplus/tlatools/class/tla2sany/StandardModules/TLC.tla
+Parsing file /Users/loki/arbeit/microsoft/dev/quaeler_repo/tlaplus/tlatools/class/tla2sany/StandardModules/Naturals.tla
+Parsing file /Users/loki/arbeit/microsoft/dev/quaeler_repo/tlaplus/tlatools/class/tla2sany/StandardModules/Sequences.tla
+Parsing file /Users/loki/arbeit/microsoft/dev/quaeler_repo/tlaplus/tlatools/class/tla2sany/StandardModules/FiniteSets.tla
+Semantic processing of module Naturals
+Semantic processing of module Sequences
+Semantic processing of module QueensPluscal
+Semantic processing of module FiniteSets
+Semantic processing of module TLC
+Semantic processing of module MC
+@!@!@STARTMSG 2219:0 @!@!@
+SANY finished.
+@!@!@ENDMSG 2219 @!@!@
+@!@!@STARTMSG 2185:0 @!@!@
+Starting... (2020-01-28 16:51:31)
+@!@!@ENDMSG 2185 @!@!@
+@!@!@STARTMSG 2212:0 @!@!@
+Implied-temporal checking--satisfiability problem has 1 branches.
+@!@!@ENDMSG 2212 @!@!@
+@!@!@STARTMSG 2189:0 @!@!@
+Computing initial states...
+@!@!@ENDMSG 2189 @!@!@
+@!@!@STARTMSG 2190:0 @!@!@
+Finished computing initial states: 1 distinct state generated at 2020-01-28 16:51:32.
+@!@!@ENDMSG 2190 @!@!@
+@!@!@STARTMSG 2111:1 @!@!@
+Evaluating invariant Invariant failed.
+Attempted to apply function:
+<<1, 1, 1>>
+to argument 0, which is not in the domain of the function.
+@!@!@ENDMSG 2111 @!@!@
+@!@!@STARTMSG 2121:1 @!@!@
+The behavior up to this point is:
+@!@!@ENDMSG 2121 @!@!@
+@!@!@STARTMSG 2217:4 @!@!@
+1: <Initial predicate>
+/\ todo = {<<>>}
+/\ sols = {}
+/\ pc = "nxtQ"
+
+@!@!@ENDMSG 2217 @!@!@
+@!@!@STARTMSG 2217:4 @!@!@
+2: <nxtQ line 77, col 9 to line 91, col 48 of module QueensPluscal>
+/\ todo = {<<1>>, <<2>>, <<3>>}
+/\ sols = {}
+/\ pc = "nxtQ"
+
+@!@!@ENDMSG 2217 @!@!@
+@!@!@STARTMSG 2217:4 @!@!@
+3: <nxtQ line 77, col 9 to line 91, col 48 of module QueensPluscal>
+/\ todo = {<<2>>, <<3>>, <<1, 3>>}
+/\ sols = {}
+/\ pc = "nxtQ"
+
+@!@!@ENDMSG 2217 @!@!@
+@!@!@STARTMSG 2217:4 @!@!@
+4: <nxtQ line 77, col 9 to line 91, col 48 of module QueensPluscal>
+/\ todo = {<<3>>, <<1, 3>>}
+/\ sols = {}
+/\ pc = "nxtQ"
+
+@!@!@ENDMSG 2217 @!@!@
+@!@!@STARTMSG 2217:4 @!@!@
+5: <nxtQ line 77, col 9 to line 91, col 48 of module QueensPluscal>
+/\ todo = {<<1, 3>>, <<3, 1>>}
+/\ sols = {}
+/\ pc = "nxtQ"
+
+@!@!@ENDMSG 2217 @!@!@
+@!@!@STARTMSG 2217:4 @!@!@
+6: <nxtQ line 77, col 9 to line 91, col 48 of module QueensPluscal>
+/\ todo = {<<3, 1>>}
+/\ sols = {}
+/\ pc = "nxtQ"
+
+@!@!@ENDMSG 2217 @!@!@
+@!@!@STARTMSG 2217:4 @!@!@
+7: <nxtQ line 77, col 9 to line 91, col 48 of module QueensPluscal>
+/\ todo = {}
+/\ sols = {}
+/\ pc = "nxtQ"
+
+@!@!@ENDMSG 2217 @!@!@
+@!@!@STARTMSG 2201:0 @!@!@
+The coverage statistics at 2020-01-28 16:51:32
+@!@!@ENDMSG 2201 @!@!@
+@!@!@STARTMSG 2773:0 @!@!@
+<Init line 72, col 1 to line 72, col 4 of module QueensPluscal>: 2:2
+@!@!@ENDMSG 2773 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  line 73, col 9 to line 75, col 22 of module QueensPluscal: 2
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2772:0 @!@!@
+<nxtQ line 77, col 1 to line 77, col 4 of module QueensPluscal>: 18:45
+@!@!@ENDMSG 2772 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  line 77, col 12 to line 77, col 22 of module QueensPluscal: 45
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |line 77, col 12 to line 77, col 13 of module QueensPluscal: 23
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  line 78, col 15 to line 78, col 23 of module QueensPluscal: 23
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  line 84, col 35 to line 84, col 42 of module QueensPluscal: 45
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  line 85, col 42 to line 85, col 64 of module QueensPluscal: 16
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |line 85, col 50 to line 85, col 64 of module QueensPluscal: 17
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  line 86, col 42 to line 86, col 67 of module QueensPluscal: 16
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |line 86, col 51 to line 86, col 66 of module QueensPluscal: 17
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||line 86, col 51 to line 86, col 54 of module QueensPluscal: 17
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||line 86, col 63 to line 86, col 66 of module QueensPluscal: 17
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2775:0 @!@!@
+  |||line 83, col 41 to line 83, col 73 of module QueensPluscal: 17:30
+@!@!@ENDMSG 2775 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||||line 83, col 68 to line 83, col 71 of module QueensPluscal: 17
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2775:0 @!@!@
+  |||||line 81, col 39 to line 82, col 94 of module QueensPluscal: 17:17
+@!@!@ENDMSG 2775 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||||||line 81, col 54 to line 82, col 92 of module QueensPluscal: 51
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |||||||line 81, col 56 to line 82, col 92 of module QueensPluscal: 51
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||||||||line 82, col 56 to line 82, col 92 of module QueensPluscal: 68
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |||||||||line 20, col 3 to line 22, col 34 of module QueensPluscal: 68
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||||||||||line 20, col 6 to line 20, col 26 of module QueensPluscal: 68
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||||||||||line 21, col 6 to line 21, col 34 of module QueensPluscal: 51
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||||||||||line 22, col 6 to line 22, col 34 of module QueensPluscal: 34
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |||||||||line 82, col 65 to line 82, col 81 of module QueensPluscal: 68
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |||||||||line 82, col 84 to line 82, col 84 of module QueensPluscal: 68
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |||||||||line 82, col 87 to line 82, col 90 of module QueensPluscal: 68
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||||||||line 81, col 65 to line 81, col 80 of module QueensPluscal: 51
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||||||line 81, col 47 to line 81, col 50 of module QueensPluscal: 17
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  line 87, col 42 to line 87, col 80 of module QueensPluscal: 28
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |line 87, col 51 to line 87, col 79 of module QueensPluscal: 28
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||line 87, col 52 to line 87, col 66 of module QueensPluscal: 28
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||line 87, col 76 to line 87, col 79 of module QueensPluscal: 28
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2775:0 @!@!@
+  |||line 83, col 41 to line 83, col 73 of module QueensPluscal: 28:71
+@!@!@ENDMSG 2775 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||||line 83, col 43 to line 83, col 58 of module QueensPluscal: 22
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||||line 83, col 68 to line 83, col 71 of module QueensPluscal: 28
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2775:0 @!@!@
+  |||||line 81, col 39 to line 82, col 94 of module QueensPluscal: 28:50
+@!@!@ENDMSG 2775 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||||||line 81, col 54 to line 82, col 92 of module QueensPluscal: 84
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |||||||line 81, col 56 to line 82, col 92 of module QueensPluscal: 84
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||||||||line 82, col 56 to line 82, col 92 of module QueensPluscal: 78
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |||||||||line 20, col 3 to line 22, col 34 of module QueensPluscal: 78
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||||||||||line 20, col 6 to line 20, col 26 of module QueensPluscal: 78
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||||||||||line 21, col 6 to line 21, col 34 of module QueensPluscal: 52
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||||||||||line 22, col 6 to line 22, col 34 of module QueensPluscal: 35
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |||||||||line 82, col 65 to line 82, col 81 of module QueensPluscal: 78
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |||||||||line 82, col 84 to line 82, col 84 of module QueensPluscal: 78
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |||||||||line 82, col 87 to line 82, col 90 of module QueensPluscal: 78
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||||||||line 81, col 65 to line 81, col 80 of module QueensPluscal: 84
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||||||line 81, col 47 to line 81, col 50 of module QueensPluscal: 28
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  line 88, col 42 to line 88, col 53 of module QueensPluscal: 28
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  line 79, col 37 to line 79, col 40 of module QueensPluscal: 23
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  line 89, col 23 to line 89, col 34 of module QueensPluscal: 44
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  line 90, col 23 to line 90, col 34 of module QueensPluscal: 0
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  line 91, col 23 to line 91, col 48 of module QueensPluscal: 0
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2772:0 @!@!@
+<Terminating line 94, col 1 to line 94, col 11 of module QueensPluscal>: 0:0
+@!@!@ENDMSG 2772 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  line 94, col 16 to line 94, col 26 of module QueensPluscal: 16
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  line 94, col 31 to line 94, col 44 of module QueensPluscal: 0
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2774:0 @!@!@
+<TypeInvariant line 105, col 1 to line 105, col 13 of module QueensPluscal>
+@!@!@ENDMSG 2774 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  line 106, col 3 to line 107, col 62 of module QueensPluscal: 19
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |line 106, col 6 to line 106, col 62 of module QueensPluscal: 19
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||line 106, col 6 to line 106, col 32 of module QueensPluscal: 19
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||line 106, col 37 to line 106, col 62 of module QueensPluscal: 19
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |||line 106, col 53 to line 106, col 62 of module QueensPluscal: 34
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |||line 106, col 46 to line 106, col 49 of module QueensPluscal: 19
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |line 107, col 6 to line 107, col 62 of module QueensPluscal: 19
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2774:0 @!@!@
+<Invariant line 111, col 1 to line 111, col 9 of module QueensPluscal>
+@!@!@ENDMSG 2774 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  line 112, col 3 to line 113, col 42 of module QueensPluscal: 19
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |line 112, col 6 to line 112, col 29 of module QueensPluscal: 19
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  |line 113, col 6 to line 113, col 42 of module QueensPluscal: 19
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||line 113, col 6 to line 113, col 14 of module QueensPluscal: 19
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2221:0 @!@!@
+  ||line 113, col 19 to line 113, col 42 of module QueensPluscal: 1
+@!@!@ENDMSG 2221 @!@!@
+@!@!@STARTMSG 2202:0 @!@!@
+End of statistics.
+@!@!@ENDMSG 2202 @!@!@
+@!@!@STARTMSG 2200:0 @!@!@
+Progress(7) at 2020-01-28 16:51:32: 33 states generated (968 s/min), 19 distinct states found (557 ds/min), 2 states left on queue.
+@!@!@ENDMSG 2200 @!@!@
+@!@!@STARTMSG 2199:0 @!@!@
+33 states generated, 19 distinct states found, 2 states left on queue.
+@!@!@ENDMSG 2199 @!@!@
+@!@!@STARTMSG 2194:0 @!@!@
+The depth of the complete state graph search is 7.
+@!@!@ENDMSG 2194 @!@!@
+@!@!@STARTMSG 2268:0 @!@!@
+The average outdegree of the complete state graph is 1 (minimum is 0, the maximum 3 and the 95th percentile is 3).
+@!@!@ENDMSG 2268 @!@!@
+@!@!@STARTMSG 1000:0 @!@!@
+The model check run produced error-states - we will generate the SpecTE files now.
+@!@!@ENDMSG 1000 @!@!@
+@!@!@STARTMSG 1000:0 @!@!@
+The file /Users/loki/arbeit/microsoft/dev/tlaplus/runtime-org.lamport.tla.toolbox.product.product.product/QueensPluscal_1579286757638/QueensPluscal.toolbox/FourQueens/SpecTE.tla has been created.
+@!@!@ENDMSG 1000 @!@!@
+@!@!@STARTMSG 1000:0 @!@!@
+The file /Users/loki/arbeit/microsoft/dev/tlaplus/runtime-org.lamport.tla.toolbox.product.product.product/QueensPluscal_1579286757638/QueensPluscal.toolbox/FourQueens/SpecTE.cfg has been created.
+@!@!@ENDMSG 1000 @!@!@
+@!@!@STARTMSG 2186:0 @!@!@
+Finished in 2069ms at (2020-01-28 16:51:32)
+@!@!@ENDMSG 2186 @!@!@
+---- MODULE SpecTE ----
+EXTENDS Sequences, Toolbox, TLC, Naturals
+
+\* 
+\*  QueensPluscal follows
+\* 
+
+(***************************************************************************)
+(* Formulation of the N-queens problem and an iterative algorithm to solve *)
+(* the problem in TLA+. Since there must be exactly one queen in every row *)
+(* we represent placements of queens as functions of the form              *)
+(*    queens \in [ 1..N -> 1..N ]                                          *)
+(* where queens[i] gives the column of the queen in row i. Note that such  *)
+(* a function is just a sequence of length N.                              *)
+(* We will also consider partial solutions, also represented as sequences  *)
+(* of length \leq N.                                                       *)
+(***************************************************************************)
+
+CONSTANT N             \** number of queens and size of the board
+ASSUME N \in Nat \ {0}
+
+(* The following predicate determines if queens i and j attack each other
+   in a placement of queens (represented by a sequence as above). *)
+Attacks(queens,i,j) ==
+  \/ queens[i] = queens[j]                 \** same column
+  \/ queens[i] - queens[j] = i - j         \** first diagonal
+  \/ queens[j] - queens[i] = i - j         \** second diagonal
+
+(* A placement represents a (partial) solution if no two different queens
+   attack each other in it. *)
+IsSolution(queens) ==
+  \A i \in 1 .. Len(queens)-1 : \A j \in (i - 1) .. Len(queens) : 
+       ~ Attacks(queens,i,j) 
+
+(* Compute the set of solutions of the N-queens problem. *)
+Solutions == { queens \in [1..N -> 1..N] : IsSolution(queens) }
+
+(***************************************************************************)
+(* We now describe an algorithm that iteratively computes the set of       *)
+(* solutions of the N-queens problem by successively placing queens.       *)
+(* The current state of the algorithm is given by two variables:           *)
+(* - todo contains a set of partial solutions,                             *)
+(* - sols contains the set of full solutions found so far.                 *)
+(* At every step, the algorithm picks some partial solution and computes   *)
+(* all possible extensions by the next queen. If N queens have been placed *)
+(* these extensions are in fact full solutions, otherwise they are added   *)
+(* to the set todo.                                                        *)
+(***************************************************************************)
+
+(* --algorithm Queens
+     variables
+       todo = { << >> };
+       sols = {};
+
+     begin
+nxtQ:  while todo # {}
+       do
+         with queens \in todo,
+              nxtQ = Len(queens) + 1,
+              cols = { c \in 1..N : ~ \E i \in 1 .. Len(queens) :
+                                      Attacks( Append(queens, c), i, nxtQ ) },
+              exts = { Append(queens,q) : q \in cols }
+         do
+           if (nxtQ = N)
+           then todo := todo \ {queens}; sols := sols \union exts;
+           else todo := (todo \ {queens}) \union exts;
+           end if;
+         end with;
+       end while;
+     end algorithm
+*)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-2ed860b26a15ec8be61ed184eb8c9ae0
+VARIABLES todo, sols, pc
+
+vars == << todo, sols, pc >>
+
+Init == (* Global variables *)
+        /\ todo = { << >> }
+        /\ sols = {}
+        /\ pc = "nxtQ"
+
+nxtQ == /\ pc = "nxtQ"
+        /\ IF todo # {}
+              THEN /\ \E queens \in todo:
+                        LET nxtQ == Len(queens) + 1 IN
+                          LET cols == { c \in 1..N : ~ \E i \in 1 .. Len(queens) :
+                                                       Attacks( Append(queens, c), i, nxtQ ) } IN
+                            LET exts == { Append(queens,q) : q \in cols } IN
+                              IF (nxtQ = N)
+                                 THEN /\ todo' = todo \ {queens}
+                                      /\ sols' = (sols \union exts)
+                                 ELSE /\ todo' = ((todo \ {queens}) \union exts)
+                                      /\ sols' = sols
+                   /\ pc' = "nxtQ"
+              ELSE /\ pc' = "Done"
+                   /\ UNCHANGED << todo, sols >>
+
+(* Allow infinite stuttering to prevent deadlock on termination. *)
+Terminating == pc = "Done" /\ UNCHANGED vars
+
+Next == nxtQ
+           \/ Terminating
+
+Spec == Init /\ [][Next]_vars
+
+Termination == <>(pc = "Done")
+
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-fcc4c3104f960f6e4881fc76793c3cb5
+
+TypeInvariant ==
+  /\ todo \in SUBSET Seq(1 .. N) /\ \A s \in todo : Len(s) < N
+  /\ sols \in SUBSET Seq(1 .. N) /\ \A s \in sols : Len(s) = N
+
+(* The set of sols contains only solutions, and contains all solutions
+   when todo is empty. *)
+Invariant ==
+  /\ sols \subseteq Solutions
+  /\ todo = {} => Solutions \subseteq sols
+
+(* Assert that no solutions are ever computed so that TLC displays one *)
+NoSolutions == sols = {}
+
+(* Add a fairness condition to ensure progress as long as todo is nonempty *)
+Liveness == WF_vars(nxtQ)
+LiveSpec == Spec /\ Liveness
+
+
+\* 
+\*  SpecTE follows
+\* 
+
+
+\* CONSTANT definitions @modelParameterConstants:0N
+const_158025887640018000 == 
+3
+----
+
+\* TRACE Sub-Action definition 0
+LiveSpec_sa_0 ==
+    (
+        /\ todo = ({<<>>})
+        /\ sols = ({})
+        /\ pc = ("nxtQ")
+        /\ todo' = ({<<1>>, <<2>>, <<3>>})
+        /\ sols' = ({})
+        /\ pc' = ("nxtQ")
+    )
+
+\* TRACE Sub-Action definition 1
+LiveSpec_sa_1 ==
+    (
+        /\ todo = ({<<1>>, <<2>>, <<3>>})
+        /\ sols = ({})
+        /\ pc = ("nxtQ")
+        /\ todo' = ({<<2>>, <<3>>, <<1, 3>>})
+        /\ sols' = ({})
+        /\ pc' = ("nxtQ")
+    )
+
+\* TRACE Sub-Action definition 2
+LiveSpec_sa_2 ==
+    (
+        /\ todo = ({<<2>>, <<3>>, <<1, 3>>})
+        /\ sols = ({})
+        /\ pc = ("nxtQ")
+        /\ todo' = ({<<3>>, <<1, 3>>})
+        /\ sols' = ({})
+        /\ pc' = ("nxtQ")
+    )
+
+\* TRACE Sub-Action definition 3
+LiveSpec_sa_3 ==
+    (
+        /\ todo = ({<<3>>, <<1, 3>>})
+        /\ sols = ({})
+        /\ pc = ("nxtQ")
+        /\ todo' = ({<<1, 3>>, <<3, 1>>})
+        /\ sols' = ({})
+        /\ pc' = ("nxtQ")
+    )
+
+\* TRACE Sub-Action definition 4
+LiveSpec_sa_4 ==
+    (
+        /\ todo = ({<<1, 3>>, <<3, 1>>})
+        /\ sols = ({})
+        /\ pc = ("nxtQ")
+        /\ todo' = ({<<3, 1>>})
+        /\ sols' = ({})
+        /\ pc' = ("nxtQ")
+    )
+
+\* TRACE Sub-Action definition 5
+LiveSpec_sa_5 ==
+    (
+        /\ todo = ({<<3, 1>>})
+        /\ sols = ({})
+        /\ pc = ("nxtQ")
+        /\ todo' = ({})
+        /\ sols' = ({})
+        /\ pc' = ("nxtQ")
+    )
+
+\* TRACE Action Constraint definition traceExploreActionConstraint
+_SpecTEActionConstraint ==
+<<
+LiveSpec_sa_0,
+LiveSpec_sa_1,
+LiveSpec_sa_2,
+LiveSpec_sa_3,
+LiveSpec_sa_4,
+LiveSpec_sa_5
+>>[TLCGet("level")]
+----
+
+def_ov_15802590929252000 == 
+<<
+([todo |-> {<<>>},sols |-> {},pc |-> "nxtQ"]),
+([todo |-> {<<1>>, <<2>>, <<3>>},sols |-> {},pc |-> "nxtQ"]),
+([todo |-> {<<2>>, <<3>>, <<1, 3>>},sols |-> {},pc |-> "nxtQ"]),
+([todo |-> {<<3>>, <<1, 3>>},sols |-> {},pc |-> "nxtQ"]),
+([todo |-> {<<1, 3>>, <<3, 1>>},sols |-> {},pc |-> "nxtQ"]),
+([todo |-> {<<3, 1>>},sols |-> {},pc |-> "nxtQ"]),
+([todo |-> {},sols |-> {},pc |-> "nxtQ"])
+>>
+----
+
+
+\* VARIABLE TraceExp
+
+\* TRACE INIT definition traceExploreInit
+_SpecTEInit ==
+    /\ todo = (
+            {<<>>}
+        )
+    /\ sols = (
+            {}
+        )
+    /\ pc = (
+            "nxtQ"
+        )
+\*     /\ TraceExp = TRUE
+
+----
+
+\* TRACE NEXT definition traceExploreNext
+_SpecTENext ==
+/\  \/ LiveSpec_sa_0
+    \/ LiveSpec_sa_1
+    \/ LiveSpec_sa_2
+    \/ LiveSpec_sa_3
+    \/ LiveSpec_sa_4
+    \/ LiveSpec_sa_5
+\* /\ TraceExp' = TraceExp
+
+
+
+=============================================================================
+\* Modification History
+\* Created Tue Jan 28 16:47:56 PST 2020 by loki
diff --git a/tlatools/test-model/SetPredValue.cfg b/tlatools/test-model/SetPredValue.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tlatools/test-model/SetPredValue.tla b/tlatools/test-model/SetPredValue.tla
new file mode 100644
index 0000000000000000000000000000000000000000..dbdd30c5d8965f9a09a9ec0777c3e724b0f837a3
--- /dev/null
+++ b/tlatools/test-model/SetPredValue.tla
@@ -0,0 +1,13 @@
+---- MODULE SetPredValue ----
+EXTENDS TLC, FiniteSets, Integers
+
+Range(F) == { F[x] : x \in DOMAIN F }
+Min(n, m) == IF n < m THEN n ELSE m
+
+LP(S, T, p) == LET ss == { s \in SUBSET S : Cardinality(s) = p}
+                          IN { e \in [ T -> ss ] : 
+                                Cardinality(Range(e)) = Min(Cardinality(T), Cardinality(ss)) }
+
+ASSUME PrintT(LP(1..4, {"a","b","c"}, 2))
+
+=============================
diff --git a/tlatools/test-model/UserModuleOverrideAnnotation.cfg b/tlatools/test-model/UserModuleOverrideAnnotation.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..20524345c8bb1355485ae7282e49cd9a44301eca
--- /dev/null
+++ b/tlatools/test-model/UserModuleOverrideAnnotation.cfg
@@ -0,0 +1,4 @@
+SPECIFICATION
+Spec
+PROPERTY
+Prop
diff --git a/tlatools/test-model/UserModuleOverrideAnnotation.tla b/tlatools/test-model/UserModuleOverrideAnnotation.tla
new file mode 100644
index 0000000000000000000000000000000000000000..7e85bed2def057647cb62fe79593959cddb3be7a
--- /dev/null
+++ b/tlatools/test-model/UserModuleOverrideAnnotation.tla
@@ -0,0 +1,15 @@
+--------------------------- MODULE UserModuleOverrideAnnotation -----------------------
+EXTENDS Naturals
+VARIABLES x
+
+Get == FALSE
+Get2 == FALSE
+
+Init == x = Get
+
+Next == x' = Get2
+
+Spec == Init /\ [][Next]_<<x>>
+
+Prop == [](x = TRUE)
+=============================================================================
diff --git a/tlatools/test-model/coverage/Github377.cfg b/tlatools/test-model/coverage/Github377.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..5ace4490d0a5010629d4458e00586ad1a7fc3011
--- /dev/null
+++ b/tlatools/test-model/coverage/Github377.cfg
@@ -0,0 +1,11 @@
+SPECIFICATION
+Spec
+INVARIANT
+1Inv
+1InvNonRec
+2Inv
+2aInv
+2bInv
+3aInv
+3bInv
+4Inv
diff --git a/tlatools/test-model/coverage/Github377.tla b/tlatools/test-model/coverage/Github377.tla
new file mode 100644
index 0000000000000000000000000000000000000000..0f7b12a0fc32ec4ce7fbcfa1d30019dc485bdf5a
--- /dev/null
+++ b/tlatools/test-model/coverage/Github377.tla
@@ -0,0 +1,75 @@
+---- MODULE Github377 ----
+EXTENDS Integers
+VARIABLES x
+
+Spec == x = TRUE /\ [][UNCHANGED x]_x
+
+--------------
+
+1Inv ==
+ LET recfcn[ i \in {1,2,3} ] == IF i = 1 THEN x = TRUE ELSE recfcn[1]
+ IN recfcn[1]
+
+--------------
+
+1InvNonRec ==
+ LET recfcn[ i \in {1,2,3} ] == x = TRUE
+ IN recfcn[1]
+
+--------------
+
+2Inv ==
+  LET outer ==
+      LET innerA[ i \in {1} ] == IF i = 1 THEN x = TRUE ELSE innerA[i]
+          innerB[ i \in {1} ] == innerA[i] 
+      IN innerB[1] /\ 42 = 31 + 11 /\ innerA[1]
+  IN  outer
+
+2aInv ==
+  LET outer ==
+      LET innerA[ i \in {1} ] == IF i = 1 THEN x = TRUE ELSE innerA[i]
+          innerB[ i \in {1} ] == innerA[i]
+      IN /\ innerA[1]
+         /\ innerB[1] 
+  IN  outer
+  
+2bInv ==
+  LET outer ==
+      LET innerA[ i \in {1} ] == IF i = 1 THEN x = TRUE ELSE innerA[i]
+          innerB[ i \in {1} ] == innerA[i]
+      IN innerA[1] /\ innerB[1]
+  IN  outer
+--------------
+
+3aInv ==
+  LET outer ==
+      LET innerA[ i \in {1} ] == IF i = 1 THEN x = TRUE ELSE innerA[i]
+          innerB[ i \in {1} ] == innerA[1]
+      IN /\ LET foo(i) == innerA[i]
+            IN foo(1)
+         /\ innerB[1] 
+  IN  outer
+
+--------------
+
+3bInv ==
+  LET outer ==
+      LET innerA[ i \in {1} ] == IF i = 1 THEN x = TRUE ELSE innerA[i]
+          innerB[ i \in {1} ] == innerA[1]
+      IN LET foo(i) == innerA[i]
+         IN foo(1) /\ innerB[1] 
+  IN  outer
+  
+
+--------------
+
+4Inv ==
+  LET outer ==
+      LET inner[ i \in {1} ] ==
+          LET innerst[ j \in {1} ] == x = TRUE
+          IN  innerst[1]
+      IN  inner[1]
+  IN  outer
+  
+====
+  
\ No newline at end of file
diff --git a/tlatools/test-model/coverage/I.cfg b/tlatools/test-model/coverage/I.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..c8cffbe64c3dcc8bce148218f2e7b66a7537f573
--- /dev/null
+++ b/tlatools/test-model/coverage/I.cfg
@@ -0,0 +1,4 @@
+SPECIFICATION
+Spec
+INVARIANT
+Inv
\ No newline at end of file
diff --git a/tlatools/test-model/coverage/I.tla b/tlatools/test-model/coverage/I.tla
new file mode 100644
index 0000000000000000000000000000000000000000..b72e8a26860c80abda1862adfb64e61b1d5bc746
--- /dev/null
+++ b/tlatools/test-model/coverage/I.tla
@@ -0,0 +1,15 @@
+------------------------------ MODULE I ------------------------------
+EXTENDS Naturals
+VARIABLES x
+
+F[ i \in {1,2,3,4,5} ] == 
+   IF i = 1 THEN 1 ELSE F[i-1] + 1 \* Recursive Function Definition
+
+N[n \in {1,2,3}] == 
+    /\ UNCHANGED <<x>>
+
+Spec == x \in {1,2,3,4,5} /\ [][\E i \in {1,2,3} : N[i] ]_x
+
+Inv == \E i \in DOMAIN F: F[i] = x
+
+============
diff --git a/tlatools/test-model/coverage/J.cfg b/tlatools/test-model/coverage/J.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..bc224b9def594b0819de3f0b45ede63ea8213c7b
--- /dev/null
+++ b/tlatools/test-model/coverage/J.cfg
@@ -0,0 +1,2 @@
+SPECIFICATION
+Spec
diff --git a/tlatools/test-model/coverage/J.tla b/tlatools/test-model/coverage/J.tla
new file mode 100644
index 0000000000000000000000000000000000000000..34bb20b7f7c23456c35811cf5d08af79564299cb
--- /dev/null
+++ b/tlatools/test-model/coverage/J.tla
@@ -0,0 +1,16 @@
+------------------------------ MODULE J ------------------------------
+
+VARIABLES x, y
+
+Init == /\ x \in {1,2,3,4,5}
+        /\ y = [i \in {1,2,3,4,5} |-> 0]
+
+Foo(rcds) ==
+ CASE x = 1 -> [ rcds EXCEPT ![x] = 42 ]
+   [] OTHER -> rcds
+
+Next == /\ y' = Foo(y)
+        /\ UNCHANGED x 
+
+Spec == Init /\ [][Next]_<<x,y>>
+============
diff --git a/tlatools/test-model/coverage/K.cfg b/tlatools/test-model/coverage/K.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..bc224b9def594b0819de3f0b45ede63ea8213c7b
--- /dev/null
+++ b/tlatools/test-model/coverage/K.cfg
@@ -0,0 +1,2 @@
+SPECIFICATION
+Spec
diff --git a/tlatools/test-model/coverage/K.tla b/tlatools/test-model/coverage/K.tla
new file mode 100644
index 0000000000000000000000000000000000000000..dfbaa8c4ca1fdb2a3de733475931cd63cd5c6d80
--- /dev/null
+++ b/tlatools/test-model/coverage/K.tla
@@ -0,0 +1,12 @@
+------------------------------ MODULE K ------------------------------
+
+EXTENDS Naturals
+
+Foo(Op(_), S) == \A s \in S: Op(s)
+
+Bar(S) == Foo(LAMBDA e: e \in Nat, S)
+
+VARIABLE x
+
+Spec == x = Bar({1,2,3}) /\ [][UNCHANGED x]_x 
+============
diff --git a/tlatools/test-model/coverage/L.cfg b/tlatools/test-model/coverage/L.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..bc224b9def594b0819de3f0b45ede63ea8213c7b
--- /dev/null
+++ b/tlatools/test-model/coverage/L.cfg
@@ -0,0 +1,2 @@
+SPECIFICATION
+Spec
diff --git a/tlatools/test-model/coverage/L.tla b/tlatools/test-model/coverage/L.tla
new file mode 100644
index 0000000000000000000000000000000000000000..b0fd28896fcb930b0c72d80c2406e7278528fa5a
--- /dev/null
+++ b/tlatools/test-model/coverage/L.tla
@@ -0,0 +1,10 @@
+------------------------------ MODULE L ------------------------------
+EXTENDS Naturals
+
+VARIABLE v
+
+ChooseOne(S, P(_)) == CHOOSE x \in S : P(x) /\ \A y \in S : P(y)
+
+Spec == v = ChooseOne({1}, LAMBDA x : TRUE) /\ [][UNCHANGED v]_v
+
+============
diff --git a/tlatools/test-model/pcal/Bakery.tla b/tlatools/test-model/pcal/Bakery.tla
index b840cf6e69330a3a659351351e0c659b4795fa40..6eafbb39d21cc9c449463147344c19bac3d1c23b 100644
--- a/tlatools/test-model/pcal/Bakery.tla
+++ b/tlatools/test-model/pcal/Bakery.tla
@@ -48,7 +48,7 @@ Proc == 1..NumProcs  \* The set of processes
 
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-3787a86d71fe978e1e68a7e275a515ae
 VARIABLES num, choosing, pc, read, max, nxt
 
 vars == << num, choosing, pc, read, max, nxt >>
@@ -131,7 +131,7 @@ Next == (\E self \in Proc: proc(self))
 
 Spec == Init /\ [][Next]_vars
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-044cd15e6eddcf8edc1cfa67089d17cf
 
 Constraint == \A i \in Proc : num[i] \leq MaxNum
 
diff --git a/tlatools/test-model/pcal/CBakery.tla b/tlatools/test-model/pcal/CBakery.tla
index 86115029006d0a52e23fb4bfec8e4590fb847a3e..02cbf446cfc7880e483e2a18993961a5700422f3 100644
--- a/tlatools/test-model/pcal/CBakery.tla
+++ b/tlatools/test-model/pcal/CBakery.tla
@@ -37,7 +37,7 @@ Proc == 1..NumProcs  \* The set of processes
 ********)
 
   
-\******** BEGIN TRANSLATION ********
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-3787a86d71fe978e1e68a7e275a515ae
 VARIABLES num, choosing, pc, read, max, nxt
 
 vars == << num, choosing, pc, read, max, nxt >>
@@ -120,7 +120,7 @@ Next == (\E self \in Proc: proc(self))
 
 Spec == Init /\ [][Next]_vars
 
-\******** END TRANSLATION ********
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-044cd15e6eddcf8edc1cfa67089d17cf
 Constraint 
 == \A i \in Proc : num[i] \leq MaxNum
 
diff --git a/tlatools/test-model/pcal/CCallReturn1.tla b/tlatools/test-model/pcal/CCallReturn1.tla
index 68e80ddeb20d545f318a7f0b8d11187910508273..ea517740ba64277e804b33a30f45477f3f01c74f 100644
--- a/tlatools/test-model/pcal/CCallReturn1.tla
+++ b/tlatools/test-model/pcal/CCallReturn1.tla
@@ -29,7 +29,7 @@ EXTENDS Sequences, Naturals, TLC
 
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-eb6f25a53750950964fc51a79ea41da3
 VARIABLES pc, stack, arg1, u, arg2, v, arg3
 
 vars == << pc, stack, arg1, u, arg2, v, arg3 >>
@@ -120,5 +120,5 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-54b1efca8092525f1f0eb4eb06b502c9
 =============================================================================
diff --git a/tlatools/test-model/pcal/CDiningPhilosophers.tla b/tlatools/test-model/pcal/CDiningPhilosophers.tla
index 43ac828828221099d99ec2f28c487cecc3674c10..18522fc18cc980a20847f76880fa8d4c13162415 100644
--- a/tlatools/test-model/pcal/CDiningPhilosophers.tla
+++ b/tlatools/test-model/pcal/CDiningPhilosophers.tla
@@ -40,7 +40,7 @@ l01 : while (TRUE)
           }
 } }
 ********)
-\******** BEGIN TRANSLATION ********
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-d34a24305f241c923d0f8daa00682e02
 VARIABLES sem, pc
 
 vars == << sem, pc >>
@@ -109,7 +109,7 @@ Spec == /\ Init /\ [][Next]_vars
         /\ \A self \in 1..(N-1) : SF_vars(Proc(self))
         /\ SF_vars(Proc0)
 
-\******** END TRANSLATION ********
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-ff7acdd47d76382441ae75c392052170
 
 IsEating(i) == IF i = 0 THEN pc[i] = "e0"
                         ELSE pc[i] = "e"
diff --git a/tlatools/test-model/pcal/CEither1.tla b/tlatools/test-model/pcal/CEither1.tla
index 03213f7164dfdf028d53c74368244cbc95f4f943..4d93a0c8cbf49200ef8b12816dd9acc0271cf1aa 100644
--- a/tlatools/test-model/pcal/CEither1.tla
+++ b/tlatools/test-model/pcal/CEither1.tla
@@ -11,7 +11,7 @@ EXTENDS Naturals, Sequences, TLC
      
 *)
 
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-af9f3b0389ad56ee237e79295b3205ff
 VARIABLES x, y, pc
 
 vars == << x, y, pc >>
@@ -55,6 +55,6 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-91542970fa29f8acc63f0f9ca8f27be3
 
 =============================================================================
diff --git a/tlatools/test-model/pcal/CMultiprocDefine.tla b/tlatools/test-model/pcal/CMultiprocDefine.tla
index 67e90be869bc8363172fe21f546863ffd24fce84..9fa61fbdd4ea10881a818eb1184569114e50a685 100644
--- a/tlatools/test-model/pcal/CMultiprocDefine.tla
+++ b/tlatools/test-model/pcal/CMultiprocDefine.tla
@@ -14,7 +14,7 @@ EXTENDS Naturals, Sequences, TLC
   
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-9c797e1d4e2fc4c259c478fdea1bd5fa
 CONSTANT defaultInitValue
 VARIABLES n, pc
 
@@ -55,5 +55,5 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(\A self \in ProcSet: pc[self] = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-70c2856f6a2b2707884c9cedc014d866
 =============================================================================
diff --git a/tlatools/test-model/pcal/CallReturn1.tla b/tlatools/test-model/pcal/CallReturn1.tla
index 2ec4adf4bb1c1701cab7e6add941f72fd90eaa62..ac380f4eb70385c3d809de24998b1b2146c22780 100644
--- a/tlatools/test-model/pcal/CallReturn1.tla
+++ b/tlatools/test-model/pcal/CallReturn1.tla
@@ -28,7 +28,7 @@ EXTENDS Sequences, Naturals, TLC
     end algorithm
 *****)
   
-\******** BEGIN TRANSLATION ********
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-3e53299518ce546a0089212b525c3663
 CONSTANT defaultInitValue
 VARIABLES pc, stack, arg1, u, arg2, v, arg3
 
@@ -120,7 +120,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-\******** END TRANSLATION ********
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-21e32d8e366d103d73444c2307bf4aba
 
                                         
 =============================================================================
diff --git a/tlatools/test-model/pcal/CallReturn2.tla b/tlatools/test-model/pcal/CallReturn2.tla
index 287e0c983d450d78de9a92df16ac9c5c82c883a4..c0a5ec3e11faf1885928ebdea5a6219c0e27973e 100644
--- a/tlatools/test-model/pcal/CallReturn2.tla
+++ b/tlatools/test-model/pcal/CallReturn2.tla
@@ -48,7 +48,7 @@ EXTENDS Naturals, Sequences, TLC
   end algorithm
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-84a5cdf59d68214ad905732a585890ae
 \* Procedure variable x of procedure P at line 13 col 16 changed to x_
 CONSTANT defaultInitValue
 VARIABLES depth, pc, stack, a, x_, y, aa, xx, yy, r, x, s
@@ -195,5 +195,5 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-c8e76178d4d24aee35fa88a19dd439d8
 =============================================================================
diff --git a/tlatools/test-model/pcal/DetlefSpec.tla b/tlatools/test-model/pcal/DetlefSpec.tla
index d9222457c1515b8782bc1dd37facc10f11155259..923bd524312ce432ff4268489dee3515a1d8d111 100644
--- a/tlatools/test-model/pcal/DetlefSpec.tla
+++ b/tlatools/test-model/pcal/DetlefSpec.tla
@@ -29,7 +29,7 @@ L2:   rV := null
     } } }
 *)
 
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-1ffa57620b1dc5120c521caddbcfa0df
 VARIABLES queue, pc, rV
 
 vars == << queue, pc, rV >>
@@ -71,7 +71,7 @@ Next == (\E self \in Procs: P(self))
 Spec == /\ Init /\ [][Next]_vars
         /\ \A self \in Procs : WF_vars(P(self))
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-a5e9e9156ce3a9bf6c7fb3f657f54020
 
 CONSTANT N
 
diff --git a/tlatools/test-model/pcal/Dijkstra1.tla b/tlatools/test-model/pcal/Dijkstra1.tla
index f5c2cee2bfb03951522502fbfabad5e6ed3b89ab..c10721c98ca9a6e9177245f0188c09d41f654fd9 100644
--- a/tlatools/test-model/pcal/Dijkstra1.tla
+++ b/tlatools/test-model/pcal/Dijkstra1.tla
@@ -26,7 +26,7 @@ CONSTANT K, N
 
 ASSUME (K > N) /\ (N > 0) 
 
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-64143a14f748e286ec27eafe96303703
 VARIABLES M, pc
 
 vars == << M, pc >>
@@ -67,7 +67,7 @@ Spec == /\ Init /\ [][Next]_vars
         /\ WF_vars(P0)
         /\ \A self \in 1..(N-1) : WF_vars(Pi(self))
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-80735c28b54285a89ec67fce31b85c9d
 
 HasToken(self) == \/ (self = 0) /\ (M[0] = M[N - 1])
                   \/ (self > 0) /\ (M[self] # M[self - 1])
diff --git a/tlatools/test-model/pcal/DiningPhilosophers.tla b/tlatools/test-model/pcal/DiningPhilosophers.tla
index f5b59c19e34cd04c2dd26d425c82b4fcf599861e..17c4c87ed23087175780541c2f824bedb2d8b10d 100644
--- a/tlatools/test-model/pcal/DiningPhilosophers.tla
+++ b/tlatools/test-model/pcal/DiningPhilosophers.tla
@@ -47,7 +47,7 @@ end algorithm
 
 ***********************)
 
-(**************** BEGIN TRANSLATION *******************************)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-d34a24305f241c923d0f8daa00682e02
 VARIABLES sem, pc
 
 vars == << sem, pc >>
@@ -116,7 +116,7 @@ Spec == /\ Init /\ [][Next]_vars
         /\ \A self \in 1..(N-1) : SF_vars(Proc(self))
         /\ SF_vars(Proc0)
 
-(**************** END TRANSLATION *******************************)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-ff7acdd47d76382441ae75c392052170
 
 IsEating(i) == IF i = 0 THEN pc[i] = "e0"
                         ELSE pc[i] = "e"
diff --git a/tlatools/test-model/pcal/DiningPhilosophers2.tla b/tlatools/test-model/pcal/DiningPhilosophers2.tla
index 07b756ae789f0dd03fb3a489259c3d6c27095ff2..d6dac6d75951822b2036e79b90d08d1cb7c5a91c 100644
--- a/tlatools/test-model/pcal/DiningPhilosophers2.tla
+++ b/tlatools/test-model/pcal/DiningPhilosophers2.tla
@@ -70,7 +70,7 @@ end algorithm
 
 ***********************)
 
-(**************** BEGIN TRANSLATION *******************************)
+\* BEGIN TRANSLATION
 \* Label e of procedure foo at line 23 col 16 changed to e_
 \* Label l3 of procedure foo at line 24 col 17 changed to l3_
 \* Label dp1 of process DummyProcessSet at line 35 col 15 changed to dp1_
@@ -209,7 +209,7 @@ Spec == /\ Init /\ [][Next]_vars
            /\ WF_vars(foo(0))
            /\ SF_vars(l2(0)) /\ SF_vars(e_(0)) /\ SF_vars(l3_(0))
 
-(**************** END TRANSLATION *******************************)
+\* END TRANSLATION
 
 IsEating(i) == IF i = 0 THEN pc[i] = "e0"
                         ELSE pc[i] = "e"
diff --git a/tlatools/test-model/pcal/Either1.tla b/tlatools/test-model/pcal/Either1.tla
index 206eb4b2ca6ac15a68c96492cce40e63fd62f821..93aa90dd84337c5142b56a980d79e41760eaa25c 100644
--- a/tlatools/test-model/pcal/Either1.tla
+++ b/tlatools/test-model/pcal/Either1.tla
@@ -10,7 +10,7 @@ EXTENDS Naturals, Sequences, TLC
      end algorithm
 *)
 
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-af9f3b0389ad56ee237e79295b3205ff
 VARIABLES x, y, pc
 
 vars == << x, y, pc >>
@@ -54,6 +54,6 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-91542970fa29f8acc63f0f9ca8f27be3
 
 =============================================================================
diff --git a/tlatools/test-model/pcal/Either2.tla b/tlatools/test-model/pcal/Either2.tla
index f7f2bd8276e9e74609bce617ecc836b3e7cc2882..81d26103ae3dba9a3d4aebefa52c5d4960163212 100644
--- a/tlatools/test-model/pcal/Either2.tla
+++ b/tlatools/test-model/pcal/Either2.tla
@@ -15,7 +15,7 @@ EXTENDS Naturals, Sequences, TLC
      end algorithm
 *)
 
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-92c2a3ead1499974b8b837c3d25d0ccd
 VARIABLES x, y, z, pc
 
 vars == << x, y, z, pc >>
@@ -66,6 +66,6 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-dc9b13cd9fc5d96b6144b722cc2ffb3d
 
 =============================================================================
diff --git a/tlatools/test-model/pcal/Either3.tla b/tlatools/test-model/pcal/Either3.tla
index 508eafb54de362f623417ca2851e3c04e859153f..a1af934e141e141bacc0cce75e091a1ccc94927a 100644
--- a/tlatools/test-model/pcal/Either3.tla
+++ b/tlatools/test-model/pcal/Either3.tla
@@ -16,7 +16,7 @@ EXTENDS Naturals, Sequences, TLC
      end algorithm
 *)
 
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-d275a21163e8b7088902b968d404026a
 VARIABLES x, y, z, pc
 
 vars == << x, y, z, pc >>
@@ -71,6 +71,6 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-db7d9133d865d6309280098cc66b6a85
 
 =============================================================================
diff --git a/tlatools/test-model/pcal/Either4.tla b/tlatools/test-model/pcal/Either4.tla
index 6cda9f2556d3ab91ddd9646d8e381c865f32a4ea..926340197d1129ecf0f3250c1e5693cc0fce6103 100644
--- a/tlatools/test-model/pcal/Either4.tla
+++ b/tlatools/test-model/pcal/Either4.tla
@@ -18,7 +18,7 @@ EXTENDS Naturals, Sequences, TLC
      end algorithm
 *)
 
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-9a6afbc4f2a88a20f8db8f24ec88b676
 VARIABLES pc, x, y, z
 
 vars == << pc, x, y, z >>
@@ -78,6 +78,6 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(\A self \in ProcSet: pc[self] = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-8050fab129ad8ea32f6a8eefb5f96b57
 
 =============================================================================
diff --git a/tlatools/test-model/pcal/Either5.tla b/tlatools/test-model/pcal/Either5.tla
index 8fa1a72d7301e738002683f6cf6705f59c7aef8d..ef5123c6ef384edc676cebd2853aa8ff12b2f023 100644
--- a/tlatools/test-model/pcal/Either5.tla
+++ b/tlatools/test-model/pcal/Either5.tla
@@ -16,7 +16,7 @@ EXTENDS Naturals, Sequences, TLC
      end algorithm
 *)
 
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-be6b6d1cc0a0bacc6a419e686126c4c9
 \* Label a at line 10 col 16 changed to a_
 CONSTANT defaultInitValue
 VARIABLES x, y, z, pc, stack, a
@@ -79,6 +79,6 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-5c5a7c7b427cee2468d220b4a9fada35
 
 =============================================================================
diff --git a/tlatools/test-model/pcal/Euclid.tla b/tlatools/test-model/pcal/Euclid.tla
index b4e0381af90a7de778342bb7f9cafdb1136b1bce..f20dd1adbdbf04ec9421faf9b94da0ede4dff356 100644
--- a/tlatools/test-model/pcal/Euclid.tla
+++ b/tlatools/test-model/pcal/Euclid.tla
@@ -42,7 +42,7 @@ GCD(x, y) == CHOOSE i \in (1..x) \cap (1..y) :
                       
 
 
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-a069024aba51f10ce87a41824584b8ee
 VARIABLES u_ini, v_ini, u, v, pc
 
 vars == << u_ini, v_ini, u, v, pc >>
@@ -84,7 +84,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-969126b68f5e9c79e9cbf33f45804301
 
 
 Invariant == 
diff --git a/tlatools/test-model/pcal/Euclid2.tla b/tlatools/test-model/pcal/Euclid2.tla
index a0cd9e8b9e45f11442d82b044ad576feb14644b7..33b6272a3a0cf518bdd56abe65e2f5e14bae78f5 100644
--- a/tlatools/test-model/pcal/Euclid2.tla
+++ b/tlatools/test-model/pcal/Euclid2.tla
@@ -22,7 +22,7 @@ GCD(x, y) == CHOOSE i \in (1..x) \cap (1..y) :
                         /\ y % j = 0
                         => i \geq j
 
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-e89e843c1bd319cda8806c448153d025
 VARIABLES u, v, v_ini, pc
 
 vars == << u, v, v_ini, pc >>
@@ -63,6 +63,6 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-13d9c528c7c380488278c40608c11ba4
  
 =============================================================================
diff --git a/tlatools/test-model/pcal/Euclid3.tla b/tlatools/test-model/pcal/Euclid3.tla
index ab6e006224232c1a15d616abdea29718a2365597..b6484fc4a23a5d42e8b46ce7b2391a35d1ad91ba 100644
--- a/tlatools/test-model/pcal/Euclid3.tla
+++ b/tlatools/test-model/pcal/Euclid3.tla
@@ -21,7 +21,7 @@ GCD(x, y) == CHOOSE i \in (1..x) \cap (1..y) :
                         /\ y % j = 0
                         => i \geq j
 
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-309bc67718dab989f45f39e55b144a3e
 VARIABLES u, v, v_ini, pc
 
 vars == << u, v, v_ini, pc >>
@@ -61,6 +61,6 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-696f44302fe4977c6881615aedc0e885
  
 =============================================================================
diff --git a/tlatools/test-model/pcal/EvenOdd.tla b/tlatools/test-model/pcal/EvenOdd.tla
index d152527497cdf208265d266d6e1db4182d3cafe1..a3bc90d7e25d25838d93245d3bae94b21dbff66a 100644
--- a/tlatools/test-model/pcal/EvenOdd.tla
+++ b/tlatools/test-model/pcal/EvenOdd.tla
@@ -31,7 +31,7 @@ CONSTANT N
 ----------------------------------------------
 
 
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-a4673a20b45b60ed7b169b671068cf77
 VARIABLES result, pc, stack, xEven, xOdd
 
 vars == << result, pc, stack, xEven, xOdd >>
@@ -109,7 +109,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-c666315b11da5eecc32bda536975b934
 
 ==============================================
 
diff --git a/tlatools/test-model/pcal/EvenOddBad.tla b/tlatools/test-model/pcal/EvenOddBad.tla
index 540a32c817cc7a58f783c5e4b01d4a7c7039bd07..8adb3ecbf36e0264cfda3857947db2060a1088fb 100644
--- a/tlatools/test-model/pcal/EvenOddBad.tla
+++ b/tlatools/test-model/pcal/EvenOddBad.tla
@@ -25,7 +25,7 @@ begin
 end algorithm
 *)
 
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-4f4604590279cc4b2920a972bf28fdd0
 VARIABLES result, pc, stack, xEven, xOdd
 
 vars == << result, pc, stack, xEven, xOdd >>
@@ -108,6 +108,6 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-7dc8ff54d82fc57126829898458b6c6f
 
 =============================================================================
diff --git a/tlatools/test-model/pcal/Factorial.tla b/tlatools/test-model/pcal/Factorial.tla
index 08761dd309f4962785c3411100928ae929b4e55a..8d70425b20036104248a7f0a268084cf79488449 100644
--- a/tlatools/test-model/pcal/Factorial.tla
+++ b/tlatools/test-model/pcal/Factorial.tla
@@ -21,7 +21,7 @@ EXTENDS Naturals, Sequences, TLC
   end algorithm
 ***************************************************************************)
 
-(************** BEGIN TRANSLATION ********************)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-8354903ee5c9ddae0b8bb4f55d782009
 VARIABLES result, pc, stack, arg1, u
 
 vars == << result, pc, stack, arg1, u >>
@@ -76,7 +76,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(************* END TRANSLATION ********************)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-53ca468546a563a45762642894b2b2a3
 
 
 Invariant == result \in Nat
diff --git a/tlatools/test-model/pcal/Factorial2.tla b/tlatools/test-model/pcal/Factorial2.tla
index ffcfeebb766ebef16745fe87f16c5662506fb5ad..ea34ede1d2d1f2c688e49baf8cbcffb850e1d447 100644
--- a/tlatools/test-model/pcal/Factorial2.tla
+++ b/tlatools/test-model/pcal/Factorial2.tla
@@ -32,7 +32,7 @@ Factorial Algorithm with 2 procedures
   end algorithm
 ***************************************************************************)
 
-(************** BEGIN TRANSLATION ********************)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-7a6949afa2a72d41ea8a9ba97e423c98
 VARIABLES result, pc, stack, arg1, u, arg2, u2
 
 vars == << result, pc, stack, arg1, u, arg2, u2 >>
@@ -125,7 +125,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(************* END TRANSLATION ********************)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-6c949f27864a3ffc1d874b0a64419ab7
 
 
 Invariant == result \in Nat
diff --git a/tlatools/test-model/pcal/FairSeq.tla b/tlatools/test-model/pcal/FairSeq.tla
index 6bee108052f694f16dd2e56e7b7278ea4a625499..4eb048733aecb388e413825e685d891bbfb5d9dd 100644
--- a/tlatools/test-model/pcal/FairSeq.tla
+++ b/tlatools/test-model/pcal/FairSeq.tla
@@ -10,7 +10,7 @@ PlusCal options (version 1.5)
     }
 }
  ***************************************************************************)
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-07e0e68497291a78b07d8fb9d5597180
 VARIABLES x, pc
 
 vars == << x, pc >>
@@ -37,7 +37,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-8d9de25f8162fd0489585bc374dff964
 =============================================================================
 \* Modification History
 \* Last modified Sun Mar 20 10:13:11 PDT 2011 by lamport
diff --git a/tlatools/test-model/pcal/FairSeq2.tla b/tlatools/test-model/pcal/FairSeq2.tla
index 61377df601050883ce9a64637d8e8c9426921edd..e17d76d811ef7e0d76bbe19f8a1111515187f8c0 100644
--- a/tlatools/test-model/pcal/FairSeq2.tla
+++ b/tlatools/test-model/pcal/FairSeq2.tla
@@ -10,7 +10,7 @@ PlusCal options (version 1.5)
     }
 }
  ***************************************************************************)
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-07e0e68497291a78b07d8fb9d5597180
 VARIABLES x, pc
 
 vars == << x, pc >>
@@ -37,7 +37,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-8d9de25f8162fd0489585bc374dff964
 =============================================================================
 \* Modification History
 \* Last modified Sun Mar 20 10:13:11 PDT 2011 by lamport
diff --git a/tlatools/test-model/pcal/FastMutex.tla b/tlatools/test-model/pcal/FastMutex.tla
index cc83c392029882ba000d68c722d57efd45b7d1de..2c67388a8736b09879c3ca9fe0da4562206fbea4 100644
--- a/tlatools/test-model/pcal/FastMutex.tla
+++ b/tlatools/test-model/pcal/FastMutex.tla
@@ -44,7 +44,7 @@ end algorithm
 
 ***********************)
 
-(**************** BEGIN TRANSLATION *******************************)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-0bb63b56a09bbe2e9360c99d30162534
 CONSTANT defaultInitValue
 VARIABLES x, y, b, pc, j, failed
 
@@ -156,7 +156,7 @@ Next == (\E self \in 1..N: Proc(self))
 Spec == /\ Init /\ [][Next]_vars
         /\ \A self \in 1..N : WF_vars(Proc(self))
 
-(**************** END TRANSLATION *******************************)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-7588f44b8dba7eba3195a1299d84da82
 
 inCS(i) ==  (pc[i] = "cs") /\ (~failed[i])
 
diff --git a/tlatools/test-model/pcal/FastMutex2.tla b/tlatools/test-model/pcal/FastMutex2.tla
index 18fc2fde3074a3420caabe37571d29f4a23de3ef..1bae411bdf5778c6cf5f5ebe8fc7f0bc9d0eb521 100644
--- a/tlatools/test-model/pcal/FastMutex2.tla
+++ b/tlatools/test-model/pcal/FastMutex2.tla
@@ -77,7 +77,7 @@ end algorithm
 
 ***********************)
 
-(**************** BEGIN TRANSLATION *******************************)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-cc9279d759058abea504462b4ff084d7
 VARIABLES x, y, b, pc, j, failed, j2, failed2
 
 vars == << x, y, b, pc, j, failed, j2, failed2 >>
@@ -284,7 +284,7 @@ Spec == /\ Init /\ [][Next]_vars
         /\ \A self \in 1..M : WF_vars(Proc1(self))
         /\ \A self \in (M+1)..N : WF_vars(Proc2(self))
 
-(**************** END TRANSLATION *******************************)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-3862da72da966d861f548da308a59a9e
 
 ASSUME Print(<<"ProcSet =" , ProcSet>>, TRUE)
 inCS(i) ==  IF i \in 1..M 
diff --git a/tlatools/test-model/pcal/FastMutex3.tla b/tlatools/test-model/pcal/FastMutex3.tla
index 0cd07db1865b89c7f9003a24f58b14234b82b339..b18f8c509d586d505a943539fe877b33bd5d4ce9 100644
--- a/tlatools/test-model/pcal/FastMutex3.tla
+++ b/tlatools/test-model/pcal/FastMutex3.tla
@@ -77,7 +77,7 @@ end algorithm
 
 ***********************)
 
-(**************** BEGIN TRANSLATION *******************************)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-1901ed6bf685f13ebc84143ab4ef5b13
 VARIABLES x, y, b, pc, j, failed, j2, failed2
 
 vars == << x, y, b, pc, j, failed, j2, failed2 >>
@@ -282,7 +282,7 @@ Spec == /\ Init /\ [][Next]_vars
         /\ WF_vars(Proc1)
         /\ \A self \in 2..N : WF_vars(Proc2(self))
 
-(**************** END TRANSLATION *******************************)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-35555ac3cdd01367ca89de83ceeebd64
 
 ASSUME Print(<<"ProcSet =" , ProcSet>>, TRUE)
 inCS(i) ==  IF i = 1 THEN (pc[i] = "cs") /\ (~failed)
diff --git a/tlatools/test-model/pcal/FastMutexWithGoto.tla b/tlatools/test-model/pcal/FastMutexWithGoto.tla
index 45c12e33c46346073827d1b5124c9367ebb03e95..a39b53e28de250b045bb9971a2f725a584465b2e 100644
--- a/tlatools/test-model/pcal/FastMutexWithGoto.tla
+++ b/tlatools/test-model/pcal/FastMutexWithGoto.tla
@@ -44,7 +44,7 @@ end algorithm
 
 ***********************)
 
-(**************** BEGIN TRANSLATION *******************************)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-765a4c9fba722b8f4115732919fba3a0
 VARIABLES x, y, b, pc, j
 
 vars == << x, y, b, pc, j >>
@@ -151,7 +151,7 @@ Next == (\E self \in 1..N: Proc(self))
 
 Spec == Init /\ [][Next]_vars
 
-(**************** END TRANSLATION *******************************)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-556f4fffd8fac96ddb09d8c9c984f878
 
 inCS(i) ==  (pc[i] = "cs") 
 
diff --git a/tlatools/test-model/pcal/FastMutexWithGoto2.tla b/tlatools/test-model/pcal/FastMutexWithGoto2.tla
index ed71caf8a3d726ff8a69351b12d05d2c702dd931..cd98a524bd71a7899f4c6e3765b283c38e76b8b6 100644
--- a/tlatools/test-model/pcal/FastMutexWithGoto2.tla
+++ b/tlatools/test-model/pcal/FastMutexWithGoto2.tla
@@ -42,7 +42,7 @@ end algorithm
 
 ***********************)
 
-(**************** BEGIN TRANSLATION *******************************)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-d10cf42a8598db9135c9a3e8255fdc3c
 VARIABLES x, y, b, pc, S
 
 vars == << x, y, b, pc, S >>
@@ -150,7 +150,7 @@ Next == (\E self \in 1..N: Proc(self))
 Spec == /\ Init /\ [][Next]_vars
         /\ WF_vars(Next)
 
-(**************** END TRANSLATION *******************************)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-71043efb021aa260bc5d04181cce7e16
 
 inCS(i) ==  (pc[i] = "cs") 
 
diff --git a/tlatools/test-model/pcal/Fischer.tla b/tlatools/test-model/pcal/Fischer.tla
index e781d3c25669fb2dc8623a6459d4d0105e0fe68c..94f8697638adb3bf2d04c2434d69b960306e0e12 100644
--- a/tlatools/test-model/pcal/Fischer.tla
+++ b/tlatools/test-model/pcal/Fischer.tla
@@ -54,7 +54,7 @@ end algorithm
 
 ***********************)
 
-(**************** BEGIN TRANSLATION *******************************)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-fcd66548d87762ce6cd61f8b60ad89ec
 VARIABLES x, timer, pc, firstTime
 
 vars == << x, timer, pc, firstTime >>
@@ -127,7 +127,7 @@ Spec == /\ Init /\ [][Next]_vars
         /\ \A self \in 1..N : WF_vars(Proc(self))
         /\ WF_vars(Tick)
 
-(**************** END TRANSLATION *******************************)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-d8d38bac35efc64e68e3d99ac06a0837
 
 inCS(i) ==  pc[i] = "cs"
 
diff --git a/tlatools/test-model/pcal/InnerLabeledIf.tla b/tlatools/test-model/pcal/InnerLabeledIf.tla
index d9a4faba890a9f0956280f952f4431bac647e82a..a54b23102e1b97d993e92876aaac9531aa1d8d51 100644
--- a/tlatools/test-model/pcal/InnerLabeledIf.tla
+++ b/tlatools/test-model/pcal/InnerLabeledIf.tla
@@ -20,7 +20,7 @@ EXTENDS Sequences, Naturals, TLC
     end algorithm
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-8d605a76553c67cf0740a3d27b57470b
 VARIABLES x, pc
 
 vars == << x, pc >>
@@ -77,7 +77,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-c43944356bde2029519b5137bfd80466
 
 
 =============================================================================
diff --git a/tlatools/test-model/pcal/MPFactorial.tla b/tlatools/test-model/pcal/MPFactorial.tla
index 505034c02a9aee8a3fc3d1e2c95faca2ffc26b3c..99001e9dbad33069862700cf92da2fd71b97193c 100644
--- a/tlatools/test-model/pcal/MPFactorial.tla
+++ b/tlatools/test-model/pcal/MPFactorial.tla
@@ -28,7 +28,7 @@ EXTENDS Naturals, Sequences, TLC
   end algorithm
 ***************************************************************************)
 
-(************** BEGIN TRANSLATION ********************)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-1dbfa1687c2aacb174fffdcfcb1e6b08
 CONSTANT defaultInitValue
 VARIABLES result, pc, stack, arg1, u
 
@@ -113,7 +113,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(\A self \in ProcSet: pc[self] = "Done")
 
-(************* END TRANSLATION ********************)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-c530d8d4ac433df112955db00ba9f4a7
 
 
 Invariant == result \in Nat
diff --git a/tlatools/test-model/pcal/MPFactorial2.tla b/tlatools/test-model/pcal/MPFactorial2.tla
index 3c9d313e54cfbea343a01ae97404900790cc9aee..e0dd136dbf500ca5742603a140db4df97cc9bf51 100644
--- a/tlatools/test-model/pcal/MPFactorial2.tla
+++ b/tlatools/test-model/pcal/MPFactorial2.tla
@@ -37,7 +37,7 @@ Factorial Algorithm with 2 procedures
   end algorithm
 ***************************************************************************)
 
-(************** BEGIN TRANSLATION ********************)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-b4a39db84a865a6dcb14d3b14f4d88b3
 VARIABLES result, pc, stack, arg1, u, arg2, u2
 
 vars == << result, pc, stack, arg1, u, arg2, u2 >>
@@ -157,7 +157,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(\A self \in ProcSet: pc[self] = "Done")
 
-(************* END TRANSLATION ********************)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-81af4b8b8e1c44a573ab6b21fa7843b0
 
 
 Invariant == result \in Nat
diff --git a/tlatools/test-model/pcal/MPNoParams.tla b/tlatools/test-model/pcal/MPNoParams.tla
index 60ea4ff1f30ad01c9786fa830e84fe000e1e8765..8f71899be5288284eee52236b4c609caa119ce60 100644
--- a/tlatools/test-model/pcal/MPNoParams.tla
+++ b/tlatools/test-model/pcal/MPNoParams.tla
@@ -23,7 +23,7 @@ EXTENDS Sequences, Naturals, TLC
 
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-deb6c76a28ce9358817b0dff2194ebab
 VARIABLES sum, pc, stack
 
 vars == << sum, pc, stack >>
@@ -86,7 +86,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(\A self \in ProcSet: pc[self] = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-714bbad3547f7f99ec47cfca79fad75e
 
 
 =============================================================================
diff --git a/tlatools/test-model/pcal/MacroQuicksort.tla b/tlatools/test-model/pcal/MacroQuicksort.tla
index c6a92ae665f45712c7709e1cbaa7a026c2f2c8b3..42a91b4aa35418a765a8204c0c9057c507711575 100644
--- a/tlatools/test-model/pcal/MacroQuicksort.tla
+++ b/tlatools/test-model/pcal/MacroQuicksort.tla
@@ -43,7 +43,7 @@ PermsOf(Arr) ==
   end algorithm
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION
 VARIABLES Ainit, A, pc, stack, qlo, qhi, pivot
 
 vars == << Ainit, A, pc, stack, qlo, qhi, pivot >>
@@ -139,7 +139,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION
 =============================================================================
 Checked without termination on svc-lamport-2 with 2 workers:
   arrayLen = 4 in 15 sec, 32280 states, depth 22
diff --git a/tlatools/test-model/pcal/MacroRealQuicksort.tla b/tlatools/test-model/pcal/MacroRealQuicksort.tla
index eb45df5a589cf35fc75dbd55113961f2d554cc48..4c52cbc72a1d3a284942993e188479da9251f130 100644
--- a/tlatools/test-model/pcal/MacroRealQuicksort.tla
+++ b/tlatools/test-model/pcal/MacroRealQuicksort.tla
@@ -41,7 +41,7 @@ PermsOf(Arr) ==
   end algorithm
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION
 VARIABLES Ainit, A, S, pivot, pc
 
 vars == << Ainit, A, S, pivot, pc >>
@@ -83,7 +83,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION
 =============================================================================
 Checked without termination on svc-lamport-2 with 2 workers:
   arrayLen = 4 in 15 sec, 32280 states, depth 22
diff --git a/tlatools/test-model/pcal/MergeSort.tla b/tlatools/test-model/pcal/MergeSort.tla
index 07a03d9c6b2f0bd5f67cfb158085277a31fa68ec..a9df3645e7660041a3759abc9ab418acb1cab780 100644
--- a/tlatools/test-model/pcal/MergeSort.tla
+++ b/tlatools/test-model/pcal/MergeSort.tla
@@ -80,7 +80,7 @@ Copied from page 166 of the 2nd edition of Robert Sedgewick's "Algorithms".
   end algorithm
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-3f24d15c1de7a8bf341d55378b5a76c0
 CONSTANT defaultInitValue
 VARIABLES a, b, pc, stack, l, r, i, j, k, m
 
@@ -240,7 +240,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-ff6c7e89b9c9baac60a504f5cbacb5a2
 
 Invariant == 
    (pc = "Done") => \A x, y \in DOMAIN a :
diff --git a/tlatools/test-model/pcal/MultiAssignment.tla b/tlatools/test-model/pcal/MultiAssignment.tla
index 2f0085947e8c2a0aaf42b85869dc4d735d54f27b..2f2732c089d1af1913d7cd66c05b7cd5b4355224 100644
--- a/tlatools/test-model/pcal/MultiAssignment.tla
+++ b/tlatools/test-model/pcal/MultiAssignment.tla
@@ -21,7 +21,7 @@ EXTENDS Naturals, TLC
 
 ****)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-922bd40bbb66854d6ea0cf6dbef935cb
 VARIABLES pc, A, x
 
 vars == << pc, A, x >>
@@ -61,5 +61,5 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(\A self \in ProcSet: pc[self] = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-6c5ff91175ea2e80dc22b1dde5479e58
 =============================================================================
diff --git a/tlatools/test-model/pcal/MultiProc2.tla b/tlatools/test-model/pcal/MultiProc2.tla
index 1312740cf1c879f990b3a9084f960f32eccb1889..136c0c3110b13afedcb0b59737fbedcbd1a43f56 100644
--- a/tlatools/test-model/pcal/MultiProc2.tla
+++ b/tlatools/test-model/pcal/MultiProc2.tla
@@ -31,7 +31,7 @@ EXTENDS Sequences, Naturals, TLC
     end algorithm 
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-6a3f53faa6a08b14086cf6736a14399e
 VARIABLES x, sum, done, pc, stack, arg, u, y, z
 
 vars == << x, sum, done, pc, stack, arg, u, y, z >>
@@ -127,5 +127,5 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(\A self \in ProcSet: pc[self] = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-3f17bd1aee44cca22b14ef7de16f1390
 =============================================================================
diff --git a/tlatools/test-model/pcal/MultiprocDefine.tla b/tlatools/test-model/pcal/MultiprocDefine.tla
index 8cb8847a02b83755f894ea5c1364a75f2467bcb3..535bbde59c7a17b18e82800b5dbfe3a863ffab55 100644
--- a/tlatools/test-model/pcal/MultiprocDefine.tla
+++ b/tlatools/test-model/pcal/MultiprocDefine.tla
@@ -15,7 +15,7 @@ EXTENDS Naturals, Sequences, TLC
   end algorithm
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-255a10565612be8265861699149ea328
 CONSTANT defaultInitValue
 VARIABLES n, pc
 
@@ -55,5 +55,5 @@ Spec == Init /\ [][Next]_vars
 
 Termination == <>(\A self \in ProcSet: pc[self] = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-0c8f6e25783592e29e1972ef47f12501
 =============================================================================
diff --git a/tlatools/test-model/pcal/NestedMacros.tla b/tlatools/test-model/pcal/NestedMacros.tla
index 864b61c94eb58c3aa9c9c60e27012b64dcbc0841..b03dee89a8f9867321b4ff5679c1dba9b0709330 100644
--- a/tlatools/test-model/pcal/NestedMacros.tla
+++ b/tlatools/test-model/pcal/NestedMacros.tla
@@ -26,7 +26,7 @@ EXTENDS Naturals, TLC
   }
 }
  ***************************************************************************)
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-45eef21f51ec0ad28fe46e4b9a7b10ce
 CONSTANT defaultInitValue
 VARIABLES x, y, pc, z
 
@@ -68,5 +68,5 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(\A self \in ProcSet: pc[self] = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-5f6bcf611a462be83724e9522b1f4062
 =============================================================================
diff --git a/tlatools/test-model/pcal/NoLoop.tla b/tlatools/test-model/pcal/NoLoop.tla
index e52f005b97ae4459c7d90b32ed79c69d22704f3f..89678c0db0c904a3002c3f3d670827a0e517e5b5 100644
--- a/tlatools/test-model/pcal/NoLoop.tla
+++ b/tlatools/test-model/pcal/NoLoop.tla
@@ -11,7 +11,7 @@ EXTENDS Sequences, Naturals, TLC
     end algorithm
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-688f592294a3ad1b9996ea0f884f9746
 VARIABLES x, y, pc
 
 vars == << x, y, pc >>
@@ -52,5 +52,5 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-e78115b3384d72d09de2ad789d3620a6
 =============================================================================
diff --git a/tlatools/test-model/pcal/NoLoop2.tla b/tlatools/test-model/pcal/NoLoop2.tla
index 80e19d11af88016afe0b199703b4ae5d9bbd5ba5..b155e5aa7a428169bf86ae56279b73477caaa5f5 100644
--- a/tlatools/test-model/pcal/NoLoop2.tla
+++ b/tlatools/test-model/pcal/NoLoop2.tla
@@ -15,7 +15,7 @@ EXTENDS Naturals, TLC
 
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-a111e49229d06e75e660ee8777442285
 VARIABLES x, y, pc
 
 vars == << x, y, pc >>
@@ -66,5 +66,5 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-7bfbfdcfed4c1aea23c410420c1f4f9d
 =============================================================================
diff --git a/tlatools/test-model/pcal/NoParams.tla b/tlatools/test-model/pcal/NoParams.tla
index 9ab5db57e13e02b29e8d391bf0e4b6d13e2273df..ccb98c820452e034f16a870154adf2381414fe26 100644
--- a/tlatools/test-model/pcal/NoParams.tla
+++ b/tlatools/test-model/pcal/NoParams.tla
@@ -17,7 +17,7 @@ EXTENDS Sequences, Naturals, TLC
 
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-053c2fa748febe4e17ba5f50b599466c
 VARIABLES sum, pc, stack
 
 vars == << sum, pc, stack >>
@@ -64,6 +64,6 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-621925aa8b4c5ddf90178ffc7da092a5
 
 =============================================================================
diff --git a/tlatools/test-model/pcal/NotSoSimpleLoop.tla b/tlatools/test-model/pcal/NotSoSimpleLoop.tla
index a2f41b8e339f0c7016ee32beb9f57259ac2968b5..335e5a9bb18ea23539defbcb553d8a92cd9fbd8e 100644
--- a/tlatools/test-model/pcal/NotSoSimpleLoop.tla
+++ b/tlatools/test-model/pcal/NotSoSimpleLoop.tla
@@ -14,7 +14,7 @@ EXTENDS Naturals, TLC
      end algorithm                  *)
 
 					
-(****** BEGIN TRANSLATION ****)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-50f6f9a537b91874ce70a2eef129eb7f
 VARIABLES x, pc
 
 vars == << x, pc >>
@@ -51,5 +51,5 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(****** END TRANSLATION ****)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-0694bcde67f647179b7e22184415182a
 =============================================================================
diff --git a/tlatools/test-model/pcal/Peterson.tla b/tlatools/test-model/pcal/Peterson.tla
index 651f6c64c2abd213446bb7371cbe99143868e429..6c4bbb5aeb975899d291fb592b45c4e83cb4bb26 100644
--- a/tlatools/test-model/pcal/Peterson.tla
+++ b/tlatools/test-model/pcal/Peterson.tla
@@ -36,7 +36,7 @@ Here is the algorithm in +Cal (using the C syntax):
 (* assumes weak fairness of the next-state actions of both processes.      *)
 (* This fairness assumption is discussed below.                            *)
 (***************************************************************************)
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-9255d446219a56b97b6d3847e8a2c94c
 VARIABLES flag, turn, pc
 
 vars == << flag, turn, pc >>
@@ -86,7 +86,7 @@ Next == (\E self \in {0,1}: proc(self))
 
 Spec == Init /\ [][Next]_vars
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-3c75243f0ddf7b933ebf70f115d692f3
 
 (***************************************************************************)
 (* Here is the invariant property that the algorithm should satisfy.  It   *)
diff --git a/tlatools/test-model/pcal/Quicksort.tla b/tlatools/test-model/pcal/Quicksort.tla
index 8b2604f57d9b072694885b6ffc7a689624ce093d..4b8b7b46ad6561b9c4b98049fc455ef8c719e3ac 100644
--- a/tlatools/test-model/pcal/Quicksort.tla
+++ b/tlatools/test-model/pcal/Quicksort.tla
@@ -47,7 +47,7 @@ PermsOf(Arr) ==
   end algorithm
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-9360dabbf03d04fb938a53e6f43a0dc3
 CONSTANT defaultInitValue
 VARIABLES Ainit, A, returnVal, pc, stack, lo, hi, qlo, qhi, pivot
 
@@ -162,7 +162,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-c890d98935ff53e5f234680508ac16aa
 =============================================================================
 Checked without termination on svc-lamport-2 with 2 workers:
   arrayLen = 4 in 15 sec, 32280 states, depth 22
diff --git a/tlatools/test-model/pcal/Quicksort2Procs.tla b/tlatools/test-model/pcal/Quicksort2Procs.tla
index 5f6eab6552032bcf2a1237fac35ae8832a7c2e71..b0e2d4ff7bf1ae9bec80323fc77bcf39a4b5bed7 100644
--- a/tlatools/test-model/pcal/Quicksort2Procs.tla
+++ b/tlatools/test-model/pcal/Quicksort2Procs.tla
@@ -58,7 +58,7 @@ PermsOf(Arr) ==
   end algorithm
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-041626606cd9c50bd2700d7f84bf1f9c
 VARIABLES A, returnVal, pc, stack, lo, hi, qlo, qhi, pivot, qlo2, qhi2, 
           pivot2
 
@@ -231,7 +231,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-da193a603aa89ac5bf05f91d5ffaf922
 
 Invariant == 
    (pc = "Done") => \A i, j \in 1..ArrayLen :
diff --git a/tlatools/test-model/pcal/QuicksortMacro.tla b/tlatools/test-model/pcal/QuicksortMacro.tla
index d513cae2ea6c54e13d5cf61e2f613eac5531cc6f..ce284e9145de3934ad94bdee20943bbfe9b60476 100644
--- a/tlatools/test-model/pcal/QuicksortMacro.tla
+++ b/tlatools/test-model/pcal/QuicksortMacro.tla
@@ -43,7 +43,7 @@ PermsOf(Arr) ==
   end algorithm
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-f3c86b18c12d46dfb100d83f44bd15cc
 VARIABLES A, returnVal, pc, stack, qlo, qhi, pivot
 
 vars == << A, returnVal, pc, stack, qlo, qhi, pivot >>
@@ -128,7 +128,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-f36591cc8efd54110514a4b1f13d3500
 
 Invariant == 
    (pc = "Done") => \A i, j \in 1..ArrayLen :
diff --git a/tlatools/test-model/pcal/RAB.tla b/tlatools/test-model/pcal/RAB.tla
index b21b1bd7d5c2db8ec0e20f2ace7ff8e20bae60bb..4d920d96784b29b8da65505ca364931390bba4f3 100644
--- a/tlatools/test-model/pcal/RAB.tla
+++ b/tlatools/test-model/pcal/RAB.tla
@@ -145,7 +145,7 @@ end algorithm
 *)    
 
 
-(* BEGIN TRANSLATION *)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-36470f24ec099c641e8894d14dc1be7a
 VARIABLES flags, calc, pc, temp, myattr
 
 vars == << flags, calc, pc, temp, myattr >>
@@ -196,7 +196,7 @@ Next == (\E self \in Pid: work(self))
 
 Spec == Init /\ [][Next]_vars
 
-(* END TRANSLATION *)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-e0d61e0fb8a75ee2eb592e9a5b0f5f46
 
 
 Consistency ==
diff --git a/tlatools/test-model/pcal/RealQuicksort.tla b/tlatools/test-model/pcal/RealQuicksort.tla
index 02d8d8ec0bf421d3d70a8168506601ec1bd6e57f..3392236c96d5d5d470f179d399623a8be2a63dd8 100644
--- a/tlatools/test-model/pcal/RealQuicksort.tla
+++ b/tlatools/test-model/pcal/RealQuicksort.tla
@@ -50,7 +50,7 @@ Max(S) == CHOOSE i \in S : \A j \in S : i \geq j
 
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-1f05a46c32a9d2bb1934b39aad724eed
 CONSTANT defaultInitValue
 VARIABLES A, Uns, new, pc, stack, parg
 
@@ -116,7 +116,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-4de5033005d037379ed702fb72c5f705
 
 Invariant == 
    (pc = "Done") => \A i, j \in 1..Len(A) :
diff --git a/tlatools/test-model/pcal/RealQuicksort2.tla b/tlatools/test-model/pcal/RealQuicksort2.tla
index edf8a6b1d4b50156712207da62becd73cbbab524..c30fb7d371fe3cdf540e8fcef096b352600abd20 100644
--- a/tlatools/test-model/pcal/RealQuicksort2.tla
+++ b/tlatools/test-model/pcal/RealQuicksort2.tla
@@ -50,7 +50,7 @@ Max(S) == CHOOSE i \in S : \A j \in S : i \geq j
 
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-23d3f8a2c70b06b61c3d312c6981bc33
 CONSTANT defaultInitValue
 VARIABLES A, Uns, new, next, pc, stack, parg
 
@@ -116,7 +116,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-86e50a32c6061aae8bbd3a4da8513951
 
 Invariant == 
    (pc = "Done") => \A i, j \in 1..Len(A) :
diff --git a/tlatools/test-model/pcal/ReallySimpleMultiProc.tla b/tlatools/test-model/pcal/ReallySimpleMultiProc.tla
index 3a264e4b8252da809cd0716dfa29bd429ce7efd3..29501d33d7111b3f6840a6d11a65815e21105241 100644
--- a/tlatools/test-model/pcal/ReallySimpleMultiProc.tla
+++ b/tlatools/test-model/pcal/ReallySimpleMultiProc.tla
@@ -25,7 +25,7 @@ EXTENDS Naturals, TLC
 
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-489e6572dfcfeaa9e2ac64d8c5013ef0
 VARIABLES x, sum, done, pc, y, z
 
 vars == << x, sum, done, pc, y, z >>
@@ -85,5 +85,5 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(\A self \in ProcSet: pc[self] = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-9c6ea370932e887119161ccedba84a47
 =============================================================================
diff --git a/tlatools/test-model/pcal/SBB.tla b/tlatools/test-model/pcal/SBB.tla
index 44d5fb23dc2aae646e37fd8975dae866f713485e..9bb98be275aa2ee48342de98a3c649a054c5ab1f 100644
--- a/tlatools/test-model/pcal/SBB.tla
+++ b/tlatools/test-model/pcal/SBB.tla
@@ -68,7 +68,7 @@ end algorithm
 *)    
 
 
-(* BEGIN TRANSLATION *)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-28938b6571490e0f82ac59c63d6f47e4
 VARIABLES sb, availablebuffers, publishedbuffers, pc, buf, op
 
 vars == << sb, availablebuffers, publishedbuffers, pc, buf, op >>
@@ -140,7 +140,7 @@ Next == (\E self \in Pid: work(self))
 
 Spec == Init /\ [][Next]_vars
 
-(* END TRANSLATION *)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-0476e94d7836683a2a4a6e344c5a0a7b
 
 
 Immutability ==
diff --git a/tlatools/test-model/pcal/SemaphoreMutex.tla b/tlatools/test-model/pcal/SemaphoreMutex.tla
index c79eb9e7b9373ffd98d6c17bdba7a027d44953e7..d7332cbc3dbd083329985041c4b9ac6930f91ff3 100644
--- a/tlatools/test-model/pcal/SemaphoreMutex.tla
+++ b/tlatools/test-model/pcal/SemaphoreMutex.tla
@@ -29,7 +29,7 @@ end algorithm
 
 ***********************)
 
-(**************** BEGIN TRANSLATION *******************************)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-44c6b54854f894e836bedeb86826fe34
 VARIABLES sem, pc
 
 vars == << sem, pc >>
@@ -65,7 +65,7 @@ Next == (\E self \in 1..N: Proc(self))
 Spec == /\ Init /\ [][Next]_vars
         /\ \A self \in 1..N : SF_vars(Proc(self))
 
-(**************** END TRANSLATION *******************************)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-30232ad9c07579ad742b84411a6a279a
 
 inCS(i) ==  (pc[i] = "cs") 
 
diff --git a/tlatools/test-model/pcal/SimpleLoop.tla b/tlatools/test-model/pcal/SimpleLoop.tla
index 11fc1cc2736dc6d290740a1be8d4c208bb25dde7..53e5993f1429a48993c45f292576e69c15f78048 100644
--- a/tlatools/test-model/pcal/SimpleLoop.tla
+++ b/tlatools/test-model/pcal/SimpleLoop.tla
@@ -12,7 +12,7 @@ EXTENDS Naturals, TLC
      end algorithm                                                         
 *)
 					
-(******* BEGIN TRANSLATION *****)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-33bbd786fd9a21815a80c1c8d918b5c0
 VARIABLES x, pc
 
 vars == << x, pc >>
@@ -42,5 +42,5 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(******* END TRANSLATION *****)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-d8f87f4745585bbecc6137f522211233
 =============================================================================
diff --git a/tlatools/test-model/pcal/SimpleLoopWithProcedure.tla b/tlatools/test-model/pcal/SimpleLoopWithProcedure.tla
index 6b459d29d371ef5b700697ad589759dc4a5f5528..b69c62963c3830ea211473710cb900d28b19cd86 100644
--- a/tlatools/test-model/pcal/SimpleLoopWithProcedure.tla
+++ b/tlatools/test-model/pcal/SimpleLoopWithProcedure.tla
@@ -20,7 +20,7 @@ EXTENDS Naturals, Sequences, TLC
 *)
 
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-925d38ef233a8a8c33b34bb25ba0c30d
 VARIABLES x, y, n, i, pc, stack, incr, z
 
 vars == << x, y, n, i, pc, stack, incr, z >>
@@ -77,5 +77,5 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-1145b37773754e0c960b38596f8082a0
 =============================================================================
diff --git a/tlatools/test-model/pcal/SimpleMultiProc.tla b/tlatools/test-model/pcal/SimpleMultiProc.tla
index f90f6591fbaf46fab631bc5d54a352390e275f72..5c2a3165b83729971a9a55114e1eb8b026fb52e0 100644
--- a/tlatools/test-model/pcal/SimpleMultiProc.tla
+++ b/tlatools/test-model/pcal/SimpleMultiProc.tla
@@ -38,7 +38,7 @@ EXTENDS Naturals, Sequences, TLC
 
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION
 \* Process variable y of process ProcA at line 20 col 17 changed to y_
 \* Process variable z of process ProcB at line 27 col 17 changed to z_
 VARIABLES x, sum, done, pc, stack, me, y, y_, z_, z
@@ -158,5 +158,5 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(\A self \in ProcSet: pc[self] = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION
 =============================================================================
diff --git a/tlatools/test-model/pcal/SubSub.tla b/tlatools/test-model/pcal/SubSub.tla
index 30648976613f8ff4f493430ce6789d6d0db62ac8..fff5f6a594b5b94f0dbb7e5a664cce38951d4d17 100644
--- a/tlatools/test-model/pcal/SubSub.tla
+++ b/tlatools/test-model/pcal/SubSub.tla
@@ -24,7 +24,7 @@ ObjectID == {1}
 end algorithm
 *****)
 
-\******** BEGIN TRANSLATION ********
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-e4495880aa3211ed2f4c6f44d3918dc7
 CONSTANT defaultInitValue
 VARIABLES pc, x, y, z
 
@@ -61,7 +61,7 @@ Spec == Init /\ [][Next]_vars
 
 Termination == <>(\A self \in ProcSet: pc[self] = "Done")
 
-\******** END TRANSLATION ********
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-4eda2626bbd263ed274c0990ecc17263
 
 --------------------------------------------------------------------------
 
diff --git a/tlatools/test-model/pcal/SyncCons.tla b/tlatools/test-model/pcal/SyncCons.tla
index 8d9d44681e0a178afb01a8703054d0aeb573a238..63f32e354cbef760d5162bb0ae07dbde9b7d1d76 100644
--- a/tlatools/test-model/pcal/SyncCons.tla
+++ b/tlatools/test-model/pcal/SyncCons.tla
@@ -103,7 +103,7 @@ bot == CHOOSE v: v \notin Data
 
 Proc == 1..N
 
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-6c62906a7a71f4a60f9b9f0eecf7e59e
 \* Label clock of process Clock at line 77 col 12 changed to clock_
 VARIABLES clock, input, round, buffer, crashed, pc, output, procs, value, 
           recd
@@ -240,7 +240,7 @@ Spec == Init /\ [][Next]_vars
 
 Termination == <>(\A self \in ProcSet: pc[self] = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-166884a9c4ec2ab81b93439149dfdc07
 
 C1 == \A p1, p2 \in (1..N) \ crashed:
   (pc[p1] = "Done" /\ pc[p2] = "Done") => (output[p1] = output[p2])
diff --git a/tlatools/test-model/pcal/Test.tla b/tlatools/test-model/pcal/Test.tla
index 017d41b6eacfda45ee47ae481125488879713e57..cb68cd3b3f9ba05b447bf7428a293b9693cd8ea4 100644
--- a/tlatools/test-model/pcal/Test.tla
+++ b/tlatools/test-model/pcal/Test.tla
@@ -29,7 +29,7 @@ end algorithm
 EXTENDS Sequences, Naturals, TLC
 
 
-\* BEGIN TRANSLATION 			
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-648cb8f5989caacb85bf4050478c7a20
 VARIABLES x, y, pc, stack
 
 vars == << x, y, pc, stack >>
@@ -100,6 +100,6 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-\* END TRANSLATION 		
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-025c418c95de365cc2a03da9bdd7e60c
 
 ============================================
diff --git a/tlatools/test-model/pcal/TestReplace.tla b/tlatools/test-model/pcal/TestReplace.tla
index c9de9c214f76c634bcdabf1e8f496c73e5c74432..742eb25a62b72745aebaa295783d1d4655ce3c09 100644
--- a/tlatools/test-model/pcal/TestReplace.tla
+++ b/tlatools/test-model/pcal/TestReplace.tla
@@ -59,7 +59,7 @@ end algorithm
 
 ***********************)
 
-\* BEGIN TRANSLATION 
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-a373e52549e281416ed7cb70fa982188
 \* Label a of procedure Bar at line 12 col 11 changed to a_
 \* Label a of procedure Foo1 at line 19 col 6 changed to a_F
 \* Label b of procedure Foo1 at line 20 col 6 changed to b_
@@ -245,7 +245,7 @@ Spec == Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-\* END TRANSLATION 
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-424be35f7792f0f2c25e136cc792e4c5
 
 ==================================================
 
diff --git a/tlatools/test-model/pcal/TestTabs.tla b/tlatools/test-model/pcal/TestTabs.tla
index fa285849ce5f4019da5c2b1a50ef297a1daf4ee8..975cbbb3a07596aa22292bb2598c999728c34eaf 100644
--- a/tlatools/test-model/pcal/TestTabs.tla
+++ b/tlatools/test-model/pcal/TestTabs.tla
@@ -16,7 +16,7 @@ l:  x := IF /\ \A i \in {1} : 1 + 1 = 2
     assert x = 1 ;
   end algorithm
 *)
-(* BEGIN TRANSLATION *)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-df86b294351f95a8207d12196b3732f0
 VARIABLES x, pc
 
 vars == << x, pc >>
@@ -47,5 +47,5 @@ Spec == Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(* END TRANSLATION *)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-ec3da753015679c262e945265fc700f9
 =============================================================================
diff --git a/tlatools/test-model/pcal/TreeBarrier.tla b/tlatools/test-model/pcal/TreeBarrier.tla
index 63982b5eb5a558e25fa50475b54f8495fdd4bc01..a84d857a4fd0b8afe40e60fc640b0812233f0711 100644
--- a/tlatools/test-model/pcal/TreeBarrier.tla
+++ b/tlatools/test-model/pcal/TreeBarrier.tla
@@ -33,7 +33,7 @@ N == 2^exp-1
 
 --------------------------------------------------------------------
 
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-f8296f0cc6166098bc809c33e090e03e
 VARIABLES arrived, proceed, pc, b, p
 
 vars == << arrived, proceed, pc, b, p >>
@@ -127,7 +127,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(\A self \in ProcSet: pc[self] = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-cbb736d8ea82daa6b485e32bbe870840
 
 
 SafeBarrier == \A p1, p2 \in ProcSet:
diff --git a/tlatools/test-model/pcal/ULCallReturn1.tla b/tlatools/test-model/pcal/ULCallReturn1.tla
index 72326d407151714785865aff5044dfa90c1b2b46..20328512f989245d5215a1dd6d58388966d3dbe9 100644
--- a/tlatools/test-model/pcal/ULCallReturn1.tla
+++ b/tlatools/test-model/pcal/ULCallReturn1.tla
@@ -29,7 +29,7 @@ EXTENDS Sequences, Naturals, TLC
 
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-a699498c8513ed4e4423d961c35407b2
 VARIABLES pc, stack, arg1, u, arg2, v, arg3
 
 vars == << pc, stack, arg1, u, arg2, v, arg3 >>
@@ -120,5 +120,5 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-542b3dd4f4eee627dff4b0b877928865
 =============================================================================
diff --git a/tlatools/test-model/pcal/ULEuclid.tla b/tlatools/test-model/pcal/ULEuclid.tla
index a2b4d93e16157f36c219f0b1c1b841da6d0a4d62..53b0d05cd0106d40b220e174555e35b18314b24e 100644
--- a/tlatools/test-model/pcal/ULEuclid.tla
+++ b/tlatools/test-model/pcal/ULEuclid.tla
@@ -41,7 +41,7 @@ GCD(x, y) == CHOOSE i \in (1..x) \cap (1..y) :
                       
 
 
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-15a96a62d4bb94349f0b7e97b7877563
 VARIABLES u_ini, v_ini, u, v, pc
 
 vars == << u_ini, v_ini, u, v, pc >>
@@ -83,7 +83,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-42ac9bbadc686601495c6cb5a86d3d55
 
 
 Invariant == 
diff --git a/tlatools/test-model/pcal/ULEvenOdd.tla b/tlatools/test-model/pcal/ULEvenOdd.tla
index 555439fac10e32161a01235218537c86e8acfc85..0c3b6cdf01e7d69756c3ea47521c891085d1033d 100644
--- a/tlatools/test-model/pcal/ULEvenOdd.tla
+++ b/tlatools/test-model/pcal/ULEvenOdd.tla
@@ -31,7 +31,7 @@ CONSTANT N
 ----------------------------------------------
 
 
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-ead0453df43345041c6d46c21bad39b3
 VARIABLES result, pc, stack, xEven, xOdd
 
 vars == << result, pc, stack, xEven, xOdd >>
@@ -109,7 +109,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-20632e604e66ef1ac373dca4eac3efb3
 
 ==============================================
 
diff --git a/tlatools/test-model/pcal/ULFactorial2.tla b/tlatools/test-model/pcal/ULFactorial2.tla
index 08483d2867605f47495b68bd08b6411a09ef9727..3205ee538c10648f2caf9fd109ac01ca4c0d4774 100644
--- a/tlatools/test-model/pcal/ULFactorial2.tla
+++ b/tlatools/test-model/pcal/ULFactorial2.tla
@@ -32,7 +32,7 @@ Factorial Algorithm with 2 procedures
   end algorithm
 ***************************************************************************)
 
-(************** BEGIN TRANSLATION ********************)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-e543cee5733d328853b3f740967ffc6f
 VARIABLES result, pc, stack, arg1, u, arg2, u2
 
 vars == << result, pc, stack, arg1, u, arg2, u2 >>
@@ -119,7 +119,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(************* END TRANSLATION ********************)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-13df185bb6632a27d39dd317f4d5a749
 
 
 Invariant == result \in Nat
diff --git a/tlatools/test-model/pcal/ULQuicksortMacro.tla b/tlatools/test-model/pcal/ULQuicksortMacro.tla
index 7f8114840addb9329795f58d5566c73fd6a0e4e0..d99543dccafba75a8851a7581d5f2f3bfcc0cf8f 100644
--- a/tlatools/test-model/pcal/ULQuicksortMacro.tla
+++ b/tlatools/test-model/pcal/ULQuicksortMacro.tla
@@ -43,7 +43,7 @@ PermsOf(Arr) ==
   end algorithm
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-749f221938b5b2dde2ae6c5d6a23511d
 VARIABLES A, returnVal, pc, stack, qlo, qhi, pivot
 
 vars == << A, returnVal, pc, stack, qlo, qhi, pivot >>
@@ -124,7 +124,7 @@ Spec == /\ Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-d263fef6f518e6f97b673c4d40ca9921
 
 Invariant == 
    (pc = "Done") => \A i, j \in 1..ArrayLen :
diff --git a/tlatools/test-model/pcal/UniprocDefine.tla b/tlatools/test-model/pcal/UniprocDefine.tla
index cb74ba0bbfd83f18feacbef2e1f181a3f98d8618..8d3e3a52a71b5c343a8a65d4c28041dcc7cccd5e 100644
--- a/tlatools/test-model/pcal/UniprocDefine.tla
+++ b/tlatools/test-model/pcal/UniprocDefine.tla
@@ -17,7 +17,7 @@ EXTENDS Naturals, Sequences, TLC
   end algorithm
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-6a1ac8b08c9ed86b40d0f6e5ef5cbdb0
 CONSTANT defaultInitValue
 VARIABLES n, pc, stack
 
@@ -72,5 +72,5 @@ Spec == Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-bb2646c148c04705a11ba77b1f981f05
 =============================================================================
diff --git a/tlatools/test-model/pcal/bug_05_10_03.tla b/tlatools/test-model/pcal/bug_05_10_03.tla
index 78ee4dbbdbe18b648a14284c5aa4bee6b6dd2f2a..71d4d55ca983a26ad603c5b03f21607284236410 100644
--- a/tlatools/test-model/pcal/bug_05_10_03.tla
+++ b/tlatools/test-model/pcal/bug_05_10_03.tla
@@ -13,7 +13,7 @@ end algorithm
 ------------- MODULE bug_05_10_03 ------------
 EXTENDS Naturals, TLC, FiniteSets
 ------------------------------------------
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-b9dcdef1a5e6ce1735b61fe6aacca0f9
 VARIABLES pc, x
 
 vars == << pc, x >>
@@ -43,5 +43,5 @@ Spec == Init /\ [][Next]_vars
 
 Termination == <>(\A self \in ProcSet: pc[self] = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-50c9ab33ebfd9eb7e6aeb12b5bbb6bd1
 ==========================================
diff --git a/tlatools/test-model/pcal/bug_05_12_10a.tla b/tlatools/test-model/pcal/bug_05_12_10a.tla
index 0490c9d3a4dd283c5f894e419de09c7813f67eb2..bb525e1e1181f2eee1855a7c7ad3743e1bf81e9c 100644
--- a/tlatools/test-model/pcal/bug_05_12_10a.tla
+++ b/tlatools/test-model/pcal/bug_05_12_10a.tla
@@ -76,7 +76,7 @@ alg == [type |-> "uniprocess",
   end algorithm
 *)
 
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-019f5cd9d60f4235bafaf7162f8ed3b4
 \* Label IA5a of procedure IsAlgorithm at line 43 col 38 changed to IA5a_
 \* Procedure variable i of procedure IsAlgorithm at line 21 col 28 changed to i_
 CONSTANT defaultInitValue
@@ -305,5 +305,5 @@ Spec == Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-1e7f8dbaa6644662e3fa38b76045e01d
 =============================================================================
diff --git a/tlatools/test-model/pcal/bug_05_12_16b.tla b/tlatools/test-model/pcal/bug_05_12_16b.tla
index ba41ad8238a05a17668d9610580c7f47c582dcaa..9dcfff9d2890738f18223210558ea7d665839047 100644
--- a/tlatools/test-model/pcal/bug_05_12_16b.tla
+++ b/tlatools/test-model/pcal/bug_05_12_16b.tla
@@ -15,7 +15,7 @@
 ----------- MODULE bug_05_12_16b -----------
 EXTENDS Naturals, Sequences, TLC
  
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-7f01be0bd1e78f7ef9aee292dd8f66fc
 VARIABLES pc, stack, a, x, y
 
 vars == << pc, stack, a, x, y >>
@@ -71,6 +71,6 @@ Spec == Init /\ [][Next]_vars
 
 Termination == <>(\A self \in ProcSet: pc[self] = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-e3a05375e3bf2d3d55b6d92003f1f2fa
 
 ========================================
diff --git a/tlatools/test-model/pcal/bug_05_12_31.tla b/tlatools/test-model/pcal/bug_05_12_31.tla
index 928c3f2e9b0bdc0a12925b6e61bf5b5930cbad2b..79fbadc5e9de7a735bd9cac3f1b8679f1d75c268 100644
--- a/tlatools/test-model/pcal/bug_05_12_31.tla
+++ b/tlatools/test-model/pcal/bug_05_12_31.tla
@@ -16,7 +16,7 @@ EXTENDS Naturals, Sequences, TLC
   end algorithm
 *)
 					
-(***** BEGIN TRANSLATION ***)
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-1f8e16f0d9c2b45f0271cd3d8415f9b8
 VARIABLES pc, stack, a, x, y
 
 vars == << pc, stack, a, x, y >>
@@ -62,5 +62,5 @@ Spec == Init /\ [][Next]_vars
 
 Termination == <>(pc = "Done")
 
-(***** END TRANSLATION ***)
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-6df4c643b7934c47f1761b2b8aced244
 =============================================================================
diff --git a/tlatools/test-model/pcal/bug_06_01_25.tla b/tlatools/test-model/pcal/bug_06_01_25.tla
index 865b62cc687bc4566ccb82c70cb5fa64bdba85c2..5d52e83356e07bb122f08c19108898b4bd4f3709 100644
--- a/tlatools/test-model/pcal/bug_06_01_25.tla
+++ b/tlatools/test-model/pcal/bug_06_01_25.tla
@@ -80,7 +80,7 @@ EXTENDS Sequences, Naturals, TLC
 
 ASSUME \forall i \in {} : i \geq 1
 
-\* BEGIN TRANSLATION
+\* BEGIN TRANSLATION - the hash of the PCal code: PCal-9ef67f07b10dbbf43fc7d4cb2d8d7b02
 \* Label P1 of procedure P at line 22 col 17 changed to P1_
 CONSTANT defaultInitValue
 VARIABLES x, y, z, pc, stack
@@ -224,5 +224,5 @@ Spec == Init /\ [][Next]_vars
 
 Termination == <>(\A self \in ProcSet: pc[self] = "Done")
 
-\* END TRANSLATION
+\* END TRANSLATION - the hash of the generated TLA code (remove to silence divergence warnings): TLA-c0ae8bdf7ad8a969ed412d1b64210cb9
 ========================================
diff --git a/tlatools/test-model/tlc2/overrides/TLCOverrides.class b/tlatools/test-model/tlc2/overrides/TLCOverrides.class
new file mode 100644
index 0000000000000000000000000000000000000000..1fcc20ad58623ed04088c6795c58c9c1d0f98fe0
Binary files /dev/null and b/tlatools/test-model/tlc2/overrides/TLCOverrides.class differ
diff --git a/tlatools/test-model/tlc2/overrides/TLCOverrides.java b/tlatools/test-model/tlc2/overrides/TLCOverrides.java
new file mode 100644
index 0000000000000000000000000000000000000000..caed63a4a192cd843d7f3b3c66ddb5e25571d618
--- /dev/null
+++ b/tlatools/test-model/tlc2/overrides/TLCOverrides.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.overrides;
+
+public class TLCOverrides implements ITLCOverrides {
+
+	/* (non-Javadoc)
+	 * @see tlc2.overrides.ITLCOverrides#get()
+	 */
+	@Override
+	public Class[] get() {
+		return new Class[] { UserModuleOverrideAnnotationImpl.class };
+	}
+
+}
diff --git a/tlatools/test-model/tlc2/overrides/UserModuleOverrideAnnotationImpl.class b/tlatools/test-model/tlc2/overrides/UserModuleOverrideAnnotationImpl.class
new file mode 100644
index 0000000000000000000000000000000000000000..85c8b276ec1a5aca07f444c48612d972b18511c0
Binary files /dev/null and b/tlatools/test-model/tlc2/overrides/UserModuleOverrideAnnotationImpl.class differ
diff --git a/tlatools/test-model/tlc2/overrides/UserModuleOverrideAnnotationImpl.java b/tlatools/test-model/tlc2/overrides/UserModuleOverrideAnnotationImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..33048fa6d4d42e59e72e98bbbbdb33ef1025a843
--- /dev/null
+++ b/tlatools/test-model/tlc2/overrides/UserModuleOverrideAnnotationImpl.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.overrides;
+
+import tlc2.value.impl.BoolValue;
+import tlc2.value.impl.Value;
+
+public class UserModuleOverrideAnnotationImpl {
+
+	@TLAPlusOperator(identifier="Get", module="UserModuleOverrideAnnotation")
+	public static Value getNumberOne() {
+		return BoolValue.ValTrue;
+	}
+	
+	@TLAPlusOperator(identifier="Get2", module="UserModuleOverrideAnnotation")
+	public static Value Get2() {
+		return BoolValue.ValTrue;
+	}
+	
+	//************ The ones below will cause warnings because they don't match ************//
+	
+	@TLAPlusOperator(identifier="Get2", module="UserModuleOverrideAnnotation")
+	public static Value Get2(Value v1) {
+		return BoolValue.ValFalse;
+	}
+
+	@TLAPlusOperator(identifier="NoSuchIdentifier", module="UserModuleOverrideAnnotation")
+	public static Value noSuchIdentifier() {
+		return BoolValue.ValFalse;
+	}
+	
+	@TLAPlusOperator(identifier="Get", module="NoSuchModule")
+	public static Value noSuchModule() {
+		return BoolValue.ValFalse;
+	}
+}
diff --git a/tlatools/test/pcal/PCalModelCheckerTestCase.java b/tlatools/test/pcal/PCalModelCheckerTestCase.java
index 88a634b663ea1b8efc45df65c49424889074717d..d683d6576dbca9324c86251556047a26c122f387 100644
--- a/tlatools/test/pcal/PCalModelCheckerTestCase.java
+++ b/tlatools/test/pcal/PCalModelCheckerTestCase.java
@@ -39,6 +39,7 @@ import org.junit.Before;
 import tlc2.output.EC;
 import tlc2.tool.CommonTestCase;
 import tlc2.tool.liveness.ModelCheckerTestCase;
+import util.TLAConstants;
 import util.ToolIO;
 
 public abstract class PCalModelCheckerTestCase extends ModelCheckerTestCase {
@@ -70,7 +71,8 @@ public abstract class PCalModelCheckerTestCase extends ModelCheckerTestCase {
 		// the previous tests.
 		ToolIO.reset();
 		
-		this.pcalArgs.add(CommonTestCase.BASE_PATH + File.separator + path + File.separator + spec + ".tla");
+		this.pcalArgs.add(CommonTestCase.BASE_PATH + File.separator + path + File.separator + spec
+				+ TLAConstants.Files.TLA_EXTENSION);
 		
 		// Run PCal translator
 		assertEquals(0, trans.runMe(pcalArgs.toArray(new String[pcalArgs.size()])));
diff --git a/tlatools/test/pcal/PCalTest.java b/tlatools/test/pcal/PCalTest.java
index 0db4abf6133ed8f994caa29281c2a6bc98ee5596..8db29ff4c37eea12dcbbbd5e22b46c2d4206ce59 100644
--- a/tlatools/test/pcal/PCalTest.java
+++ b/tlatools/test/pcal/PCalTest.java
@@ -33,6 +33,7 @@ import java.nio.file.Paths;
 
 import org.junit.Before;
 
+import util.TLAConstants;
 import util.ToolIO;
 
 public abstract class PCalTest {
@@ -49,7 +50,7 @@ public abstract class PCalTest {
 	}
 
 	protected static String writeFile(String filename, String content) throws IOException {
-		final Path path = Files.createFile(Paths.get(filename + ".tla"));
+		final Path path = Files.createFile(Paths.get(filename + TLAConstants.Files.TLA_EXTENSION));
 		Files.write(path, content.getBytes());
 		
 		final File file = path.toFile();
@@ -58,7 +59,7 @@ public abstract class PCalTest {
 	}
 	
 	protected static String writeTempFile(String filename, String content) throws IOException {
-		final Path path = Files.createTempFile(filename, ".tla");
+		final Path path = Files.createTempFile(filename, TLAConstants.Files.TLA_EXTENSION);
 		Files.write(path, content.getBytes());
 		
 		final File file = path.toFile();
diff --git a/tlatools/test/pcal/ValidatorPerformance.java b/tlatools/test/pcal/ValidatorPerformance.java
new file mode 100644
index 0000000000000000000000000000000000000000..a84a6900004255dadcc1d9b9ed5f129a85fe32ee
--- /dev/null
+++ b/tlatools/test/pcal/ValidatorPerformance.java
@@ -0,0 +1,39 @@
+package pcal;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import tlc2.tool.CommonTestCase;
+
+public class ValidatorPerformance {
+	private static final String SPEC_FILE = CommonTestCase.BASE_PATH + "PlusCalOptions.tla";
+	
+	@Test
+	public void testTimings() throws IOException {
+		final long trimmedStart = System.currentTimeMillis();
+		for (int i = 0; i < 1000; i++) {
+			try (final FileInputStream fis = new FileInputStream(SPEC_FILE)) {
+				Validator.validate(fis);
+			}
+		}
+		final long trimmedEnd = System.currentTimeMillis();
+
+		Validator.PRE_TRIM_VALIDATION_CONTENT = false;
+		final long untrimmedStart = System.currentTimeMillis();
+		for (int i = 0; i < 1000; i++) {
+			try (final FileInputStream fis = new FileInputStream(SPEC_FILE)) {
+				Validator.validate(fis);
+			}
+		}
+		final long untrimmedEnd = System.currentTimeMillis();
+
+		final long trimmedDelta = trimmedEnd - trimmedStart;
+		final long untrimmedDelta = untrimmedEnd - untrimmedStart;
+		System.out.println("Trimmed run time was " + trimmedDelta + " and untrimmed was " + untrimmedDelta);
+		Assert.assertTrue("Untrimmed processing time (" + untrimmedDelta +") ran faster than trimmed (" + trimmedDelta + ").",
+						  (trimmedDelta < untrimmedDelta));
+	}
+}
diff --git a/tlatools/test/tla2sany/drivers/Github429Test.java b/tlatools/test/tla2sany/drivers/Github429Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..11d70a05f04fa397c890d70709fb7ee827080aaf
--- /dev/null
+++ b/tlatools/test/tla2sany/drivers/Github429Test.java
@@ -0,0 +1,33 @@
+package tla2sany.drivers;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import tla2sany.modanalyzer.SpecObj;
+import tlc2.tool.CommonTestCase;
+import util.SimpleFilenameToStream;
+import util.ToolIO;
+
+public class Github429Test {
+
+	private SpecObj moduleSpec;
+
+	@Before
+	public void setUp() throws Exception {
+		// create a model and initialize
+		moduleSpec = new SpecObj(CommonTestCase.BASE_PATH + "Github429.tla", new SimpleFilenameToStream());
+		SANY.frontEndInitialize(moduleSpec, ToolIO.out);
+	}
+
+	@Test
+	public void testForFailedParse() {
+        try {
+			SANY.frontEndParse(moduleSpec, ToolIO.out);
+			SANY.frontEndSemanticAnalysis(moduleSpec, ToolIO.out, false);
+		} catch (final Exception e) {
+			Assert.fail("No exception should occur during parse. Instead encountered [" + e.getClass()
+								+ "] with message: " + e.getMessage());
+		}
+	}
+}
diff --git a/tlatools/test/tlc2/TLCTest.java b/tlatools/test/tlc2/TLCTest.java
index 4b4adee6ee95c50ff9178c96054deb65d1bed12c..2cdc42cde9681233627b535c3491e95745d6fd76 100644
--- a/tlatools/test/tlc2/TLCTest.java
+++ b/tlatools/test/tlc2/TLCTest.java
@@ -9,6 +9,7 @@ import org.junit.Test;
 
 import tlc2.tool.fp.FPSetConfiguration;
 import tlc2.tool.fp.FPSetFactory;
+import util.TLAConstants;
 import util.TLCRuntime;
 
 public class TLCTest {
@@ -16,19 +17,19 @@ public class TLCTest {
 	@Test
 	public void testHandleParametersAbsoluteInvalid() {
 		final TLC tlc = new TLC();
-		assertFalse(tlc.handleParameters(new String[] {"-fpmem", "-1", "MC"}));
+		assertFalse(tlc.handleParameters(new String[] {"-fpmem", "-1", TLAConstants.Files.MODEL_CHECK_FILE_BASENAME}));
 	}
 	
 	@Test
 	public void testHandleParametersAbsoluteValid() {
 		final TLC tlc = new TLC();
-		assertTrue(tlc.handleParameters(new String[] {"-fpmem", "101", "MC"}));
+		assertTrue(tlc.handleParameters(new String[] {"-fpmem", "101", TLAConstants.Files.MODEL_CHECK_FILE_BASENAME}));
 	}
 	
 	@Test
 	public void testHandleParametersFractionInvalid() {
 		final TLC tlc = new TLC();
-		assertFalse(tlc.handleParameters(new String[] {"-fpmem", "-0.5", "MC"}));
+		assertFalse(tlc.handleParameters(new String[] {"-fpmem", "-0.5", TLAConstants.Files.MODEL_CHECK_FILE_BASENAME}));
 	}
 	
 	/**
@@ -37,7 +38,7 @@ public class TLCTest {
 	@Test
 	public void testHandleParametersAllocateLowerBound() {
 		final TLC tlc = new TLC();
-		assertTrue(tlc.handleParameters(new String[] {"-fpmem", "0", "MC"}));
+		assertTrue(tlc.handleParameters(new String[] {"-fpmem", "0", TLAConstants.Files.MODEL_CHECK_FILE_BASENAME}));
 		final FPSetConfiguration fpSetConfiguration = tlc.getFPSetConfiguration();
 		assumeTrue(FPSetFactory.allocatesOnHeap(fpSetConfiguration.getImplementation()));
 		assertEquals("Allocating to little should result in min default",
@@ -51,7 +52,8 @@ public class TLCTest {
 	@Test
 	public void testHandleParametersAllocateUpperBound() {
 		final TLC tlc = new TLC();
-		assertTrue(tlc.handleParameters(new String[] {"-fpmem", Long.toString(Long.MAX_VALUE), "MC"}));
+		assertTrue(tlc.handleParameters(new String[] {"-fpmem", Long.toString(Long.MAX_VALUE),
+				TLAConstants.Files.MODEL_CHECK_FILE_BASENAME}));
         final long maxMemory = (long) (Runtime.getRuntime().maxMemory() * 0.75d);
         final FPSetConfiguration fpSetConfiguration = tlc.getFPSetConfiguration();
 		assumeTrue(FPSetFactory.allocatesOnHeap(fpSetConfiguration.getImplementation()));
@@ -65,7 +67,7 @@ public class TLCTest {
 	@Test
 	public void testHandleParametersAllocateHalf() {
 		final TLC tlc = new TLC();
-		assertTrue(tlc.handleParameters(new String[] {"-fpmem", ".5", "MC"}));
+		assertTrue(tlc.handleParameters(new String[] {"-fpmem", ".5", TLAConstants.Files.MODEL_CHECK_FILE_BASENAME}));
         final long maxMemory = (long) (Runtime.getRuntime().maxMemory() * 0.50d);
         final FPSetConfiguration fpSetConfiguration = tlc.getFPSetConfiguration();
 		assumeTrue(FPSetFactory.allocatesOnHeap(fpSetConfiguration.getImplementation()));
@@ -79,7 +81,7 @@ public class TLCTest {
 	@Test
 	public void testHandleParametersAllocate90() {
 		final TLC tlc = new TLC();
-		assertTrue(tlc.handleParameters(new String[] {"-fpmem", ".99", "MC"}));
+		assertTrue(tlc.handleParameters(new String[] {"-fpmem", ".99", TLAConstants.Files.MODEL_CHECK_FILE_BASENAME}));
         final long maxMemory = (long) (Runtime.getRuntime().maxMemory() * 0.99d);
 		final FPSetConfiguration fpSetConfiguration = tlc.getFPSetConfiguration();
 		assumeTrue(FPSetFactory.allocatesOnHeap(fpSetConfiguration.getImplementation()));
@@ -95,26 +97,29 @@ public class TLCTest {
 		final int progDefault = TLCGlobals.setBound;
 		
 		TLC tlc = new TLC();
-		assertFalse(tlc.handleParameters(new String[] {"-maxSetSize", "NaN", "MC"}));
+		assertFalse(tlc.handleParameters(new String[] {"-maxSetSize", "NaN", TLAConstants.Files.MODEL_CHECK_FILE_BASENAME}));
 		
 		tlc = new TLC();
-		assertFalse(tlc.handleParameters(new String[] {"-maxSetSize", "0", "MC"}));
+		assertFalse(tlc.handleParameters(new String[] {"-maxSetSize", "0", TLAConstants.Files.MODEL_CHECK_FILE_BASENAME}));
 		tlc = new TLC();
-		assertFalse(tlc.handleParameters(new String[] {"-maxSetSize", "-1", "MC"}));
+		assertFalse(tlc.handleParameters(new String[] {"-maxSetSize", "-1", TLAConstants.Files.MODEL_CHECK_FILE_BASENAME}));
 		tlc = new TLC();
-		assertFalse(tlc.handleParameters(new String[] {"-maxSetSize", Integer.toString(Integer.MIN_VALUE), "MC"}));
+		assertFalse(tlc.handleParameters(new String[] { "-maxSetSize", Integer.toString(Integer.MIN_VALUE),
+				TLAConstants.Files.MODEL_CHECK_FILE_BASENAME }));
 		
 		tlc = new TLC();
-		assertTrue(tlc.handleParameters(new String[] {"-maxSetSize", "1", "MC"}));
+		assertTrue(tlc.handleParameters(new String[] {"-maxSetSize", "1", TLAConstants.Files.MODEL_CHECK_FILE_BASENAME}));
 		assertTrue(TLCGlobals.setBound == 1);
 		
 
 		tlc = new TLC();
-		assertTrue(tlc.handleParameters(new String[] {"-maxSetSize", Integer.toString(progDefault), "MC"}));
+		assertTrue(tlc.handleParameters(
+				new String[] { "-maxSetSize", Integer.toString(progDefault), TLAConstants.Files.MODEL_CHECK_FILE_BASENAME }));
 		assertTrue(TLCGlobals.setBound == progDefault);
 		
 		tlc = new TLC();
-		assertTrue(tlc.handleParameters(new String[] {"-maxSetSize", Integer.toString(Integer.MAX_VALUE), "MC"}));
+		assertTrue(tlc.handleParameters(new String[] { "-maxSetSize", Integer.toString(Integer.MAX_VALUE),
+				TLAConstants.Files.MODEL_CHECK_FILE_BASENAME }));
 		assertTrue(TLCGlobals.setBound == Integer.MAX_VALUE);
 	}
 	
diff --git a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/AssignmentTest.java b/tlatools/test/tlc2/model/AssignmentTest.java
similarity index 97%
rename from org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/AssignmentTest.java
rename to tlatools/test/tlc2/model/AssignmentTest.java
index b8979130fd2a58750a383f59677b2b537169451a..c3918f4d40ca19a9fb665caf10d0bc6c8a3fed40 100644
--- a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/AssignmentTest.java
+++ b/tlatools/test/tlc2/model/AssignmentTest.java
@@ -24,12 +24,14 @@
  *   Markus Alexander Kuppe - initial API and implementation
  ******************************************************************************/
 
-package org.lamport.tla.toolbox.tool.tlc.model;
+package tlc2.model;
 
 import static org.junit.Assert.assertEquals;
 
 import org.junit.Test;
 
+import tlc2.model.Assignment;
+
 public class AssignmentTest {
 
 	@Test
diff --git a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/FormulaTest.java b/tlatools/test/tlc2/model/FormulaTest.java
similarity index 97%
rename from org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/FormulaTest.java
rename to tlatools/test/tlc2/model/FormulaTest.java
index f01628c3d71a5c91f0188f074cdb8da218496195..cf4d97f1394db69ae6e56b2bbe61ac9b19d7b38d 100644
--- a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/FormulaTest.java
+++ b/tlatools/test/tlc2/model/FormulaTest.java
@@ -1,9 +1,11 @@
-package org.lamport.tla.toolbox.tool.tlc.model;
+package tlc2.model;
 
 import static org.junit.Assert.*;
 
 import org.junit.Test;
 
+import tlc2.model.Formula;
+
 public class FormulaTest {
 
 	@Test
diff --git a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/TypedSetTest.java b/tlatools/test/tlc2/model/TypedSetTest.java
similarity index 73%
rename from org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/TypedSetTest.java
rename to tlatools/test/tlc2/model/TypedSetTest.java
index b9027a0a54c6c3a86add3bc85458f75958bf774e..2388d72e75e1de1c0f529036b0172c18a9c3061c 100644
--- a/org.lamport.tla.toolbox.tool.tlc.test/src/org/lamport/tla/toolbox/tool/tlc/model/TypedSetTest.java
+++ b/tlatools/test/tlc2/model/TypedSetTest.java
@@ -1,6 +1,7 @@
-package org.lamport.tla.toolbox.tool.tlc.model;
+package tlc2.model;
 
 import junit.framework.TestCase;
+import tlc2.model.TypedSet;
 
 /**
  * Test of the typed set factory
@@ -11,7 +12,7 @@ public class TypedSetTest extends TestCase
 {
 
     /**
-     * Test method for {@link org.lamport.tla.toolbox.tool.tlc.model.TypedSet#parseSet(java.lang.String)}.
+     * Test method for {@link tlc2.model.TypedSet#parseSet(java.lang.String)}.
      */
     public void testParseSet1()
     {
@@ -22,7 +23,7 @@ public class TypedSetTest extends TestCase
     }
 
     /**
-     * Test method for {@link org.lamport.tla.toolbox.tool.tlc.model.TypedSet#parseSet(java.lang.String)}.
+     * Test method for {@link tlc2.model.TypedSet#parseSet(java.lang.String)}.
      */
     public void testParseSet2()
     {
@@ -32,7 +33,7 @@ public class TypedSetTest extends TestCase
     }
 
     /**
-     * Test method for {@link org.lamport.tla.toolbox.tool.tlc.model.TypedSet#parseSet(java.lang.String)}.
+     * Test method for {@link tlc2.model.TypedSet#parseSet(java.lang.String)}.
      */
     public void testParseSet3()
     {
@@ -46,7 +47,7 @@ public class TypedSetTest extends TestCase
 
     
     /**
-     * Test method for {@link org.lamport.tla.toolbox.tool.tlc.model.TypedSet#parseSet(java.lang.String)}.
+     * Test method for {@link tlc2.model.TypedSet#parseSet(java.lang.String)}.
      */
     public void testParseSet4()
     {
@@ -58,7 +59,7 @@ public class TypedSetTest extends TestCase
 
     
     /**
-     * Test method for {@link org.lamport.tla.toolbox.tool.tlc.model.TypedSet#parseSet(java.lang.String)}.
+     * Test method for {@link tlc2.model.TypedSet#parseSet(java.lang.String)}.
      */
     public void testParseSet5()
     {
@@ -69,7 +70,7 @@ public class TypedSetTest extends TestCase
     }
 
     /**
-     * Test method for {@link org.lamport.tla.toolbox.tool.tlc.model.TypedSet#parseSet(java.lang.String)}.
+     * Test method for {@link tlc2.model.TypedSet#parseSet(java.lang.String)}.
      */
     public void testParseSet6()
     {
diff --git a/tlatools/test/tlc2/module/SequencesTest.java b/tlatools/test/tlc2/module/SequencesTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b4c315bc2e41986aa61fb6b46139f92366520521
--- /dev/null
+++ b/tlatools/test/tlc2/module/SequencesTest.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved.
+ *
+ * The MIT License (MIT)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.module;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+import tlc2.output.EC;
+import tlc2.tool.EvalException;
+import tlc2.value.impl.IntValue;
+import tlc2.value.impl.StringValue;
+import tlc2.value.impl.Value;
+
+public class SequencesTest {
+
+	@Test
+	public void testHeadString() {
+		Value a = Sequences.Head(new StringValue("a"));
+		assertTrue(a instanceof StringValue);
+		assertEquals("a", ((StringValue) a).val.toString());
+
+		a = Sequences.Head(new StringValue("abc"));
+		assertTrue(a instanceof StringValue);
+		assertEquals("a", ((StringValue) a).val.toString());
+	}
+
+	@Test
+	public void testHeadStringEmpty() {
+		try {
+			Sequences.Head(new StringValue(""));
+		} catch (EvalException e) {
+			assertEquals(EC.TLC_MODULE_APPLY_EMPTY_SEQ, e.getErrorCode());
+			return;
+		}
+		fail();
+	}
+
+	@Test
+	public void testAppendString() {
+		Value a = Sequences.Append(new StringValue(""), new StringValue("a"));
+		assertTrue(a instanceof StringValue);
+		assertEquals("a", ((StringValue) a).val.toString());
+
+		a = Sequences.Append(new StringValue("abc"), new StringValue("d"));
+		assertTrue(a instanceof StringValue);
+		assertEquals("abcd", ((StringValue) a).val.toString());
+	}
+
+	@Test
+	public void testAppendStringNonString() {
+		try {
+			Sequences.Append(new StringValue(""), IntValue.ValZero);
+		} catch (EvalException e) {
+			assertEquals(EC.TLC_MODULE_EVALUATING, e.getErrorCode());
+			return;
+		}
+		fail();
+	}
+}
diff --git a/tlatools/test/tlc2/output/CFGCopierTest.java b/tlatools/test/tlc2/output/CFGCopierTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..eadeefc735e19b792bb827f07d2f838927b23cc3
--- /dev/null
+++ b/tlatools/test/tlc2/output/CFGCopierTest.java
@@ -0,0 +1,64 @@
+package tlc2.output;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class CFGCopierTest {
+	private static final String INIT_NEXT_CFG = "\\* INIT definition\n"
+			+ "INIT\n"
+			+ "init_15767838108312000\n"
+			+ "\\* NEXT definition\n"
+			+ "NEXT\n"
+			+ "next_15767838108313000\n"
+			+ "\\* Action Constraint definition\n"
+			+ "ACTION_CONSTRAINT\n"
+			+ "action_constr_15767838108314000\n";
+	// Yes, this is an illegal CFG as it specifies both SPECIFICATION and INIT/NEXT
+	private static final String ORIGINAL_CFG = "\\* CONSTANT definitions\n"
+			+ "CONSTANT\n"
+			+ "N <- const_157376354642853000\n"
+			+ "\\* SPECIFICATION definition\n"
+			+ "SPECIFICATION\n"
+			+ "Spec\n"
+			+ "\\* INIT definition\n"
+			+ "INIT\n"
+			+ "BigInit\n"
+			+ "\\* NEXT definition\n"
+			+ "NEXT\n"
+			+ "SmallNext\n"
+			+ "\\* INVARIANT definition\n"
+			+ "INVARIANT\n"
+			+ "TypeInvariant\n"
+			+ "Invariant\n"
+			+ "\\* PROPERTY definition\n"
+			+ "PROPERTY\n"
+			+ "Termination\n"
+			+ "\\* Generated on Thu Nov 14 12:32:26 PST 2019\n";
+	private static final String NEW_CFG = "\\* CONSTANT definitions\n"
+			+ "CONSTANT\n"
+			+ "N <- const_157376354642853000\n"
+			+ "\\* INVARIANT definition\n"
+			+ "INVARIANT\n"
+			+ "TypeInvariant\n"
+			+ "Invariant\n"
+			+ "\\* PROPERTY definition\n"
+			+ "PROPERTY\n"
+			+ "Termination\n"
+			+ INIT_NEXT_CFG
+			+ "\n";
+
+	@Test
+	public void testCopy() throws IOException {
+		final CFGCopier copier = new CFGCopier("doesn't", "matter", null, INIT_NEXT_CFG);
+		final StringReader sr = new StringReader(ORIGINAL_CFG);
+		final StringWriter sw = new StringWriter();
+		
+		copier.copy(sr, sw);
+		// We compare the substring because there is a new generation time stamp at the end of the newly created config
+		Assert.assertEquals(NEW_CFG, sw.getBuffer().toString().substring(0, NEW_CFG.length()));
+	}
+}
diff --git a/tlatools/test/tlc2/output/MPTest.java b/tlatools/test/tlc2/output/MPTest.java
index 3b40cfc3986cfae053dbed05fe58c9ee4532f8ab..43c199632945a8ccc640441b620e75451a849fcd 100644
--- a/tlatools/test/tlc2/output/MPTest.java
+++ b/tlatools/test/tlc2/output/MPTest.java
@@ -72,6 +72,9 @@ public class MPTest
         MP.printMessage(EC.TLC_PROGRESS_STATS, parameters);
         String[] allMessages = ToolIO.getAllMessages();
         assertEquals(1, allMessages.length);
-        assertTrue(allMessages[0], allMessages[0].contains("3,000,000 states generated (10,000 s/min), 5,000 distinct states found (1,234 ds/min), 1,222,333,444 states left on queue."));
+		assertTrue(allMessages[0], allMessages[0].contains(
+				"3,000,000 states generated (10,000 s/min), 5,000 distinct states found (1,234 ds/min), 1,222,333,444 states left on queue.")
+				|| allMessages[0].contains(
+						"3.000.000 states generated (10.000 s/min), 5.000 distinct states found (1.234 ds/min), 1.222.333.444 states left on queue."));
     }
 }
diff --git a/tlatools/test/tlc2/output/SpecTraceExpressionWriterTest.java b/tlatools/test/tlc2/output/SpecTraceExpressionWriterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f15520973b0e22532159a057d80540e864370321
--- /dev/null
+++ b/tlatools/test/tlc2/output/SpecTraceExpressionWriterTest.java
@@ -0,0 +1,131 @@
+package tlc2.output;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import tla2sany.drivers.FrontEndException;
+import tla2sany.drivers.SANY;
+import tla2sany.modanalyzer.SpecObj;
+import tlc2.model.Formula;
+import tlc2.model.MCState;
+import tlc2.model.TraceExpressionInformationHolder;
+import util.TLAConstants;
+import util.TestPrintStream;
+
+/**
+ * The genesis for these tests is regressions that were introduced by beautification changes made as part of #393.
+ * 
+ * As future spec-generation methods are touched, something implementing them should be added below.
+ */
+public class SpecTraceExpressionWriterTest {
+	static private final String TRIVIAL_TWO_STATE_DEADLOCK_PREAMBLE
+			= "VARIABLE x, y\n"
+					+ "XIncr == (x' = x * 2)\n"
+					+ "            /\\ (x < 8)\n"
+					+ "            /\\ UNCHANGED y\n"
+					+ "YIncr == (y' = x + y)\n"
+					+ "            /\\ (y < 15)\n"
+					+ "            /\\ UNCHANGED x\n";
+	static private final String[] TRIVIAL_TWO_STATE_DEADLOCK_INIT
+			= new String[] {
+					"TestInit",
+					"TestInit == x \\in 1 .. 10 /\\ y \\in 1 .. 10\n"
+				};
+	static private final String[] TRIVIAL_TWO_STATE_DEADLOCK_NEXT
+			= new String[] {
+					"TestNext",
+					"TestNext == YIncr \\/ XIncr\n"
+				};
+	static private final String ERROR_STATE_IP
+			= "1: <Initial predicate>\n"
+					+ "/\\ x = 8\n"
+					+ "/\\ y = 7\n";
+	static private final String ERROR_STATE_1
+			= "2: <YIncr line 8, col 10 to line 10, col 26 of module Bla>\n"
+					+ "/\\ x = 8\n"
+					+"/\\ y = 15\n";
+
+	
+	private SpecTraceExpressionWriter writer;
+	private File tlaFile;
+	private File cfgFile;
+	
+	@Before
+	public void setUp() throws IOException {
+		tlaFile = File.createTempFile("sptewt_", ".tla");
+		tlaFile.deleteOnExit();
+		cfgFile = File.createTempFile("sptewt_", ".cfg");
+		cfgFile.deleteOnExit();
+		
+		final String tlaFilename = tlaFile.getName();
+		final int baseNameLength = tlaFilename.length() - TLAConstants.Files.TLA_EXTENSION.length();
+		final String specName = tlaFilename.substring(0, baseNameLength);
+		writer = new SpecTraceExpressionWriter();
+		writer.addPrimer(specName, "Naturals");
+		writer.appendContentToBuffers(TRIVIAL_TWO_STATE_DEADLOCK_PREAMBLE, null);
+	}
+	
+	private void concludeTest() throws FrontEndException, IOException {
+		writer.writeFiles(tlaFile, cfgFile);
+		
+		final SpecObj so = new SpecObj(tlaFile.getAbsolutePath(), null);
+		final TestPrintStream printStream = new TestPrintStream();
+		
+		final int result = SANY.frontEndMain(so, tlaFile.getAbsolutePath(), printStream);
+		if (result != 0) {
+			throw new FrontEndException("Parsing returned a non-zero success code (" + result + ")");
+		}
+	}
+	
+	private List<MCState> generateStatesForDeadlockCondition() { 
+		final List<MCState> states = new ArrayList<>();
+		
+		states.add(MCState.parseState(ERROR_STATE_IP));
+		states.add(MCState.parseState(ERROR_STATE_1));
+
+		return states;
+	}
+	
+	@Test
+	public void testInitNextWithNoError() throws Exception {
+		writer.addInitNextDefinitions(TRIVIAL_TWO_STATE_DEADLOCK_INIT, TRIVIAL_TWO_STATE_DEADLOCK_NEXT,
+									  "writerTestInit", "writerTextNext");
+
+		concludeTest();
+	}
+	
+	@Test
+	public void testInitNextWithError() throws Exception {
+		final List<MCState> trace = generateStatesForDeadlockCondition();
+		final StringBuilder tempCFGBuffer = new StringBuilder();
+		final StringBuilder[] tlaBuffers
+				= SpecTraceExpressionWriter.addInitNextToBuffers(tempCFGBuffer, trace, null, "STEWInit", "STEWNext",
+						 										 "STEWAC", TRIVIAL_TWO_STATE_DEADLOCK_NEXT[0], true);
+		
+		writer.appendContentToBuffers(tlaBuffers[0].toString(), tempCFGBuffer.toString());
+		writer.addTraceFunction(trace);
+		writer.appendContentToBuffers(tlaBuffers[1].toString(), null);
+		
+		concludeTest();
+	}
+	
+	@Test
+	public void testInitNextWithErrorAndTraceExpression() throws Exception {
+		final List<MCState> trace = generateStatesForDeadlockCondition();
+		writer.addTraceFunction(trace);
+
+		final List<Formula> expressions = new ArrayList<>();
+		expressions.add(new Formula("ENABLED XIncr"));
+		expressions.add(new Formula("y # 7"));
+		final TraceExpressionInformationHolder[] traceExpressions
+						= writer.createAndAddVariablesAndDefinitions(expressions, "writerTestTraceExpressions");
+		writer.addInitNext(trace, traceExpressions, "STEWInit", "STEWNext", "STEWAC", TRIVIAL_TWO_STATE_DEADLOCK_NEXT[0]);
+		
+		concludeTest();
+	}
+}
diff --git a/tlatools/test/tlc2/output/TLACopierTest.java b/tlatools/test/tlc2/output/TLACopierTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..654553dd4004c333fce14915b71eb9fa8028ac1c
--- /dev/null
+++ b/tlatools/test/tlc2/output/TLACopierTest.java
@@ -0,0 +1,72 @@
+package tlc2.output;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TLACopierTest {
+	private static final String INIT_NEXT_DEFINITIONS = "init_ldq ==\n"
+			+ "	TRUE\n"
+			+ "	\\/ FALSE\n"
+			+ "	\n"
+			+ "next_ldq ==\n"
+			+ "	FALSE\n";
+	private static final String ORIGINAL_SPEC = "---- MODULE MC ----\n"
+			+ "EXTENDS Queens, TLC\n"
+			+ "\n"
+			+ "\\* CONSTANT definitions @modelParameterConstants:0N\n"
+			+ "const_157376354642853000 == \n"
+			+ "3\n"
+			+ "----\n"
+			+ "\n"
+			+ "=============================================================================\n"
+			+ "\\* Modification History\n"
+			+ "\\* Created Thu Nov 14 12:32:26 PST 2019 by loki\n";
+	private static final String NEW_SPEC_EXTENDED = "---- MODULE Spectacle ----\n"
+			+ "EXTENDS Queens, TLC\n"
+			+ "\n"
+			+ "\\* CONSTANT definitions @modelParameterConstants:0N\n"
+			+ "const_157376354642853000 == \n"
+			+ "3\n"
+			+ "----\n"
+			+ "\n"
+			+ INIT_NEXT_DEFINITIONS + "\n"
+			+ "=============================================================================\n"
+			+ "\\* Modification History\n"
+			+ "\\* Created Thu Nov 14 12:32:26 PST 2019 by loki\n";
+	private static final String NEW_SPEC_NONEXTENDED = "---- MODULE Spectacle ----\n"
+			+ "EXTENDS Queens, TLC, TLC, Toolbox\n"
+			+ "\n"
+			+ "\\* CONSTANT definitions @modelParameterConstants:0N\n"
+			+ "const_157376354642853000 == \n"
+			+ "3\n"
+			+ "----\n"
+			+ "\n"
+			+ INIT_NEXT_DEFINITIONS + "\n"
+			+ "=============================================================================\n"
+			+ "\\* Modification History\n"
+			+ "\\* Created Thu Nov 14 12:32:26 PST 2019 by loki\n";
+	
+	@Test
+	public void testNonExtending() throws IOException {
+		final TLACopier copier = new TLACopier("MC", "Spectacle", null, INIT_NEXT_DEFINITIONS, false, false);
+		final StringReader sr = new StringReader(ORIGINAL_SPEC);
+		final StringWriter sw = new StringWriter();
+		
+		copier.copy(sr, sw);
+		Assert.assertEquals(NEW_SPEC_NONEXTENDED, sw.getBuffer().toString());
+	}
+	
+	@Test
+	public void testExtending() throws IOException {
+		final TLACopier copier = new TLACopier("MC", "Spectacle", null, INIT_NEXT_DEFINITIONS, true, true);
+		final StringReader sr = new StringReader(ORIGINAL_SPEC);
+		final StringWriter sw = new StringWriter();
+		
+		copier.copy(sr, sw);
+		Assert.assertEquals(NEW_SPEC_EXTENDED, sw.getBuffer().toString());
+	}
+}
diff --git a/tlatools/test/tlc2/tool/CommonTestCase.java b/tlatools/test/tlc2/tool/CommonTestCase.java
index b6453ec86fcafdccdb01037daa99e73d7991197c..ef430379929639a5718c2f5c711f07094fd935d0 100644
--- a/tlatools/test/tlc2/tool/CommonTestCase.java
+++ b/tlatools/test/tlc2/tool/CommonTestCase.java
@@ -57,7 +57,11 @@ public abstract class CommonTestCase {
 
 	protected final TestMPRecorder recorder;
 
-	public CommonTestCase(TestMPRecorder testMPRecorder) {
+	public CommonTestCase() {
+		this(new TestMPRecorder());
+	}
+	
+	public CommonTestCase(final TestMPRecorder testMPRecorder) {
 		recorder = testMPRecorder;
 	}
 
diff --git a/tlatools/test/tlc2/tool/ContinueTest.java b/tlatools/test/tlc2/tool/ContinueTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9129418a3313b93f77481eca055085f71418ac26
--- /dev/null
+++ b/tlatools/test/tlc2/tool/ContinueTest.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import org.junit.Test;
+
+import tlc2.output.EC;
+import tlc2.output.EC.ExitStatus;
+import tlc2.tool.liveness.ModelCheckerTestCase;
+
+public class ContinueTest extends ModelCheckerTestCase {
+
+	public ContinueTest() {
+		super("Continue", new String[] { "-continue" }, ExitStatus.SUCCESS);
+	}
+
+	@Test
+	public void testSpec() throws FileNotFoundException, IOException {
+		assertTrue(recorder.recorded(EC.TLC_FINISHED));
+		assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "32", "29", "0"));
+		assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "29"));
+
+		assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2));
+		
+		// With -continue, TLC simply prints two or more consecutive traces in no given
+		// order (determined by concurrent BFS) to stdout. This means that the
+		// MPRecorder just concatenates the traces and it is difficult to check them.
+		// For now we check that the concatenated trace has the expected number of states.
+		assertEquals(32, recorder.getRecords(EC.TLC_STATE_PRINT2).size());
+//		// Trace 1
+//		final List<String> expectedTrace = new ArrayList<String>(2);
+//		expectedTrace.add("/\\ x = 1\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 2\n/\\ y = 2");
+//		assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace);
+//		// Trace 2
+//		final List<String> expectedTrace = new ArrayList<String>(30);
+//		expectedTrace.add("/\\ x = 1\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 2\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 3\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 4\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 5\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 6\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 7\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 8\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 9\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 10\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 11\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 12\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 13\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 14\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 15\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 16\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 17\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 18\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 19\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 20\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 21\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 22\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 23\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 24\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 25\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 26\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 27\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 28\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 29\n/\\ y = 1");
+//		expectedTrace.add("/\\ x = 30\n/\\ y = 1");
+//		assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace);
+
+		assertZeroUncovered();
+	}
+
+	@Override
+	protected int getNumberOfThreads() {
+		return 3;
+	}
+}
diff --git a/tlatools/test/tlc2/tool/DumpAsDotTest.java b/tlatools/test/tlc2/tool/DumpAsDotTest.java
index 314d42d6a1c4aba93db91ec5c3622255fe8e713f..51400037d040a5367066f979d874470a63b65e57 100644
--- a/tlatools/test/tlc2/tool/DumpAsDotTest.java
+++ b/tlatools/test/tlc2/tool/DumpAsDotTest.java
@@ -67,7 +67,7 @@ public class DumpAsDotTest extends ModelCheckerTestCase {
 	}
 	
 	// http://stackoverflow.com/a/17861016
-	private static byte[] getBytes(InputStream is) throws IOException {
+	public static byte[] getBytes(InputStream is) throws IOException {
 		final ByteArrayOutputStream os = new ByteArrayOutputStream();
 		try {
 			byte[] buffer = new byte[0xFFFF];
diff --git a/tlatools/test/tlc2/tool/Github361Test.java b/tlatools/test/tlc2/tool/Github361Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..0124a26dd6b0630dc28d6de35223b51820ea0071
--- /dev/null
+++ b/tlatools/test/tlc2/tool/Github361Test.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import tlc2.output.EC;
+import tlc2.output.EC.ExitStatus;
+import tlc2.tool.liveness.ModelCheckerTestCase;
+
+public class Github361Test extends ModelCheckerTestCase {
+
+	public Github361Test() {
+		super("Github361", ExitStatus.SUCCESS);
+	}
+
+	@Test
+	public void testSpec() {
+		// This implicitly tests SpecProcessor#processConstantDefns(ModuleNode), which
+		// must not fully initialize (fingerprint) values because it is for some
+		// definitions (such as Partitions in Github361.tla) too expensive.  This is
+		// the reason why it runs with multiple threads to make sure optimizations for
+		// single-threaded TLC hide bugs.
+		assertTrue(recorder.recorded(EC.TLC_FINISHED));
+		assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "1", "0"));
+		assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1"));
+	}
+
+	@Override
+	protected int getNumberOfThreads() {
+		// See comment above.
+		return 2;
+	}
+}
diff --git a/tlatools/test/tlc2/tool/Github391Test.java b/tlatools/test/tlc2/tool/Github391Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..d699b05247c25739931d5dbae64ee6ff01d08811
--- /dev/null
+++ b/tlatools/test/tlc2/tool/Github391Test.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import tlc2.output.EC;
+import tlc2.output.EC.ExitStatus;
+import tlc2.tool.liveness.ModelCheckerTestCase;
+
+public class Github391Test extends ModelCheckerTestCase {
+
+	public Github391Test() {
+		super("Github391", ExitStatus.SUCCESS);
+	}
+
+	@Test
+	public void testSpec() {
+		assertTrue(recorder.recorded(EC.TLC_FINISHED));
+		assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "0", "0", "0"));
+		assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "1"));
+	}
+}
diff --git a/tlatools/test/tlc2/tool/Github407.dump b/tlatools/test/tlc2/tool/Github407.dump
new file mode 100644
index 0000000000000000000000000000000000000000..c1dd5569b6d74802ca058a19b2fabae520f94548
--- /dev/null
+++ b/tlatools/test/tlc2/tool/Github407.dump
@@ -0,0 +1,12 @@
+State 1:
+state = {}
+
+State 2:
+state = {"d1"}
+
+State 3:
+state = {"d2"}
+
+State 4:
+state = {"d1", "d2"}
+
diff --git a/tlatools/test/tlc2/tool/Github407Test.java b/tlatools/test/tlc2/tool/Github407Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..65a842dd80f9fc82ba84733fa6db427d7de07835
--- /dev/null
+++ b/tlatools/test/tlc2/tool/Github407Test.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import tlc2.output.EC;
+import tlc2.output.EC.ExitStatus;
+import tlc2.tool.liveness.ModelCheckerTestCase;
+
+public class Github407Test extends ModelCheckerTestCase {
+
+	public Github407Test() {
+		super("Github407",
+				new String[] { "-dump", System.getProperty("java.io.tmpdir") + File.separator + "Github407" },
+				ExitStatus.SUCCESS);
+	}
+
+	@Test
+	public void testSpec() throws FileNotFoundException, IOException {
+		assertTrue(recorder.recorded(EC.TLC_FINISHED));
+		assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "9", "4", "0"));
+		assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "3"));
+		
+		final File dumpFile = new File(System.getProperty("java.io.tmpdir") + File.separator + "Github407.dump");
+		assertTrue(dumpFile.exists());
+		
+		// If the file exist, simply compare it to a correct and manually checked version.
+		final InputStream master = getClass().getResourceAsStream("Github407.dump");
+		assertTrue(Arrays.equals(DumpAsDotTest.getBytes(master), DumpAsDotTest.getBytes(new FileInputStream(dumpFile))));
+
+		assertZeroUncovered();
+		
+	}
+
+	@Override
+	protected boolean doDump() {
+		// Create the non-dot dump explicitly through constructor above.
+		return false;
+	}
+}
diff --git a/tlatools/test/tlc2/tool/Github432Test.java b/tlatools/test/tlc2/tool/Github432Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..fc871cff6da493c86e21a2d258af29ca7a1dd327
--- /dev/null
+++ b/tlatools/test/tlc2/tool/Github432Test.java
@@ -0,0 +1,222 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import tlc2.output.EC;
+import tlc2.tool.liveness.ModelCheckerTestCase;
+
+public class Github432Test extends ModelCheckerTestCase {
+	private static final AtomicInteger TEST_COUNTER = new AtomicInteger(0);
+	
+	private static final String CONFIG_FILE = "Github432.cfg";
+	private static final String CONFIG_FILE_BACKUP = "Github432.cfg_bak";
+	
+	private static final String HUMANS_TOKEN = "%1%";
+	private static final String OTHERS_TOKEN = "%2%";
+	
+	
+	private String[] expectedWarnings;
+	
+	public Github432Test() {
+		super("Github432");
+	}
+
+	@Override
+	protected void beforeSetUp() {
+		final int testNumber = TEST_COUNTER.getAndIncrement();
+		final String humans;
+		final String others;
+		
+		switch (testNumber) {
+			case 0:
+				humans = "Alice";
+				others = "Cat, Dog";
+				expectedWarnings = new String[] {"", "Humans", "has", "s"};
+				break;
+			case 1:
+				humans = "";
+				others = "Emu";
+				expectedWarnings = new String[] {"s", "Humans, and Others", "have", ""};
+				break;
+			case 2:
+				humans = "Frank, Glenda";
+				others = "";
+				expectedWarnings = new String[] {"", "Others", "has", "s"};
+				break;
+			default:
+				humans = "Hauser, Ignatio";
+				others = "Jackal, Kangaroo";
+				expectedWarnings = null;
+				break;
+		}
+		
+		try {
+			createConfigFile(humans, others);
+		} catch (final Exception e) {
+			revertConfigFile();
+			
+			Assert.fail(e.getMessage());
+		}
+	}
+	
+	@Override
+	protected void beforeTearDown() {
+		revertConfigFile();
+	}
+	
+	@Override
+	protected void assertExitStatus() {
+		// We don't care - and the spec actually fails for test-b
+	}
+	
+	private void compareToExpectedResults(final String[] array) {
+		Assert.assertNotNull("Reported parameters should not be null.", array);
+		Assert.assertEquals("Expected warnings should be the same cardinality of the reported parameters encountered.",
+							expectedWarnings.length, array.length);
+		for (int i = 0; i < array.length; i++) {
+			Assert.assertEquals(expectedWarnings[i], array[i]);
+		}
+	}
+	
+	@Test
+	public void testA() throws FileNotFoundException, IOException {
+		if (expectedWarnings != null) {
+			compareToExpectedResults((String[])recorder.getRecords(EC.TLC_SYMMETRY_SET_TOO_SMALL).get(0));
+		} else {
+			Assert.assertFalse(recorder.recorded(EC.TLC_SYMMETRY_SET_TOO_SMALL));
+		}
+	}
+	
+	@Test
+	public void testB() throws FileNotFoundException, IOException {
+		if (expectedWarnings != null) {
+			compareToExpectedResults((String[])recorder.getRecords(EC.TLC_SYMMETRY_SET_TOO_SMALL).get(0));
+		} else {
+			Assert.assertFalse(recorder.recorded(EC.TLC_SYMMETRY_SET_TOO_SMALL));
+		}
+	}
+	
+	@Test
+	public void testC() throws FileNotFoundException, IOException {
+		if (expectedWarnings != null) {
+			compareToExpectedResults((String[])recorder.getRecords(EC.TLC_SYMMETRY_SET_TOO_SMALL).get(0));
+		} else {
+			Assert.assertFalse(recorder.recorded(EC.TLC_SYMMETRY_SET_TOO_SMALL));
+		}
+	}
+	
+	@Test
+	public void testD() throws FileNotFoundException, IOException {
+		if (expectedWarnings != null) {
+			compareToExpectedResults((String[])recorder.getRecords(EC.TLC_SYMMETRY_SET_TOO_SMALL).get(0));
+		} else {
+			Assert.assertFalse(recorder.recorded(EC.TLC_SYMMETRY_SET_TOO_SMALL));
+		}
+	}
+	
+	private void createConfigFile(final String humans, final String others) throws IOException {
+		final File configFile = new File(BASE_DIR + TEST_MODEL + CONFIG_FILE);
+		final File backup = new File(BASE_DIR + TEST_MODEL + CONFIG_FILE_BACKUP);
+		
+		if (backup.exists()) {
+			Assert.fail("Github432 test state is incoherent: the backup file already exists at "
+							+ backup.getAbsolutePath());
+		}
+		
+		try {
+			Files.move(configFile.toPath(), backup.toPath(), StandardCopyOption.ATOMIC_MOVE);
+		} catch (final IOException e) {
+			Assert.fail(e.getMessage());
+		}
+		
+		try {
+			try (final BufferedWriter bw = new BufferedWriter(new FileWriter(configFile))) {
+				try (final BufferedReader br = new BufferedReader(new FileReader(backup))) {
+					boolean humansFound = false;
+					boolean othersFound = false;
+					String line;
+					while ((line = br.readLine()) != null) {
+						int index = humansFound ? -1 : line.indexOf(HUMANS_TOKEN);
+						if (index == -1) {
+							index = othersFound ? -1 : line.indexOf(OTHERS_TOKEN);
+
+							if (index == -1) {
+								bw.write(line);
+							} else {
+								final int secondStart = index + OTHERS_TOKEN.length();
+								final String convertedLine = line.substring(0, index) + others
+																	+ line.substring(secondStart);
+								bw.write(convertedLine);
+								othersFound = true;
+							}
+						} else {
+							final int secondStart = index + HUMANS_TOKEN.length();
+							final String convertedLine = line.substring(0, index) + humans
+																+ line.substring(secondStart);
+							bw.write(convertedLine);
+							humansFound = true;
+						}
+						
+						bw.newLine();
+					}
+				}
+			}
+		} catch (final IOException e) {
+			
+			revertConfigFile();
+			
+			Assert.fail(e.getMessage());
+		}
+	}
+	
+	private void revertConfigFile() {
+		final File backup = new File(BASE_DIR + TEST_MODEL + CONFIG_FILE_BACKUP);
+		
+		if (backup.exists()) {
+			final File configFile = new File(BASE_DIR + TEST_MODEL + CONFIG_FILE);
+
+			try {
+				Files.move(backup.toPath(), configFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
+			} catch (final IOException e) {
+				Assert.fail(e.getMessage());
+			}
+		}
+	}
+}
diff --git a/tlatools/test/tlc2/tool/InliningTest.java b/tlatools/test/tlc2/tool/InliningTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e980ade6d7da40cadea6fa526ee9bcb872e2ee6b
--- /dev/null
+++ b/tlatools/test/tlc2/tool/InliningTest.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.junit.Test;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.jfr.consumer.RecordedObject;
+import jdk.jfr.consumer.RecordingFile;
+import tlc2.output.EC;
+import tlc2.output.EC.ExitStatus;
+import tlc2.tool.impl.FastTool;
+import tlc2.tool.impl.Tool;
+import tlc2.tool.liveness.ModelCheckerTestCase;
+import tlc2.util.ExpectInlined;
+
+@SuppressWarnings("restriction")
+public class InliningTest extends ModelCheckerTestCase {
+
+	/*
+	 * The high-level idea is that we record the JVM's CompilerInlining while the
+	 * JVM executes the test case. Afterwards, we check that a bunch of methods that
+	 * are annotated with a marker have been correctly inlined.  For this to work,
+	 * the test has to run long enough for the JVM to warm up.
+	 * Thanks to https://twitter.com/ErikGahlin/status/1207018011674185728 for showing
+	 * how to use the JFR API.
+	 */
+	
+	private final Recording r = new Recording(); 
+
+	public InliningTest() {
+		super("InlineMC", "CodePlexBug08", ExitStatus.SUCCESS);
+	}
+	
+	@Override
+	protected void beforeSetUp() {
+		r.enable("jdk.CompilerInlining"); 
+		r.start(); 
+	}
+	
+	// testSpec runs after model-checking.
+	@Test
+	public void testSpec() throws IOException {
+		// ModelChecker has finished at this point.
+		assertTrue(recorder.recorded(EC.TLC_FINISHED));
+		assertFalse(recorder.recorded(EC.GENERAL));
+		assertZeroUncovered();
+		
+		// stop recording and read the jfr from from disk. Close the recording
+		// afterwards.
+		r.stop();
+		Path p = Paths.get("test.jfr"); // test.jfr is the default file name.
+		r.dump(p); 
+		final List<RecordedEvent> recordedEvents = RecordingFile.readAllEvents(p);
+		r.close();
+
+		// "hot method too big" and not for "callee is too large":
+		// https://www.lmax.com/blog/staff-blogs/2016/03/30/notes-hotspot-compiler-flags/
+		final Set<RecordedObject> notInlined = recordedEvents.stream()
+				.filter(ev -> ev.hasField("message"))
+				.filter(ev -> "hot method too big".equals(ev.getString("message")))
+				.map(ev -> (RecordedObject) ev.getValue("callee"))
+				.filter(ro -> ro.getString("type").startsWith("tlc2/tool/impl/Tool")
+						|| ro.getString("type").startsWith("tlc2/tool/impl/FastTool"))
+				.collect(Collectors.toSet());
+		
+		// Make sure the test ran long enough for compilation to detect methods as hot.
+		assertFalse(notInlined.isEmpty());
+		
+		// For now we only care that methods in Tool get correctly inlined
+		// because its methods are guaranteed to be on the hot path.
+		Method[] dm = Tool.class.getDeclaredMethods();
+		for (int i = 0; i < dm.length; i++) {
+			if (dm[i].getAnnotation(ExpectInlined.class) != null) {
+				notIn(dm[i], notInlined);
+			}
+		}
+		dm = FastTool.class.getDeclaredMethods();
+		for (int i = 0; i < dm.length; i++) {
+			if (dm[i].getAnnotation(ExpectInlined.class) != null) {
+				notIn(dm[i], notInlined);
+			}
+		}
+	}
+
+	// This matching is likely brittle and will fail in ways that everybody will
+	// agree should have been accounted for. When it does, please check if
+	// RecordedObject has finally been changed to RecordedMethod
+	// (https://twitter.com/ErikGahlin/status/1207536016858505217).
+	private void notIn(final Method method, final Set<RecordedObject> notInlined) {
+		final List<RecordedObject> methodNameMatches = notInlined.stream()
+				.filter(ro -> method.getName().equals(ro.getString("name"))).collect(Collectors.toList());
+		for (RecordedObject methodNameMatch : methodNameMatches) {
+			assertTrue(isNoMatch(methodNameMatch, method));
+		}
+	}
+
+	// I warned you that this doesn't work.
+	private boolean isNoMatch(RecordedObject methodNameMatch, Method method) {
+		final String desc = methodNameMatch.getString("descriptor");
+		final String[] params = desc.substring(1, desc.indexOf(")")).split(";");
+		if (method.getParameterCount() == params.length) {
+			Class<?>[] parameters = method.getParameterTypes();
+			for (int j = 0; j < params.length; j++) {
+				final String paramType = parameters[j].toString().replace(".", "/").replaceFirst("^(class|interface) ",
+						"L");
+				if (!params[j].equals(paramType)) {
+					return true;
+				}
+			}
+			System.out.println(methodNameMatch);
+//			return false;
+		}
+		return true;
+	}
+
+	@Override
+	protected boolean doCoverage() {
+		return false;
+	}
+
+	@Override
+	protected boolean doDump() {
+		return false;
+	}
+}
diff --git a/tlatools/test/tlc2/tool/PrintTraceRaceTest.java b/tlatools/test/tlc2/tool/PrintTraceRaceTest.java
index 88aee752c450a52d9be67084a7e2b46fe0482371..c602aa8b19f37fea26169bd943aea1185864b67e 100644
--- a/tlatools/test/tlc2/tool/PrintTraceRaceTest.java
+++ b/tlatools/test/tlc2/tool/PrintTraceRaceTest.java
@@ -37,11 +37,12 @@ import org.junit.Test;
 import tlc2.output.EC;
 import tlc2.output.EC.ExitStatus;
 import tlc2.tool.liveness.ModelCheckerTestCase;
+import util.TLAConstants;
 
 public class PrintTraceRaceTest extends ModelCheckerTestCase {
 
 	public PrintTraceRaceTest() {
-		super("MC", "PrintTraceRace", ExitStatus.FAILURE_SAFETY_EVAL);
+		super(TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, "PrintTraceRace", ExitStatus.FAILURE_SAFETY_EVAL);
 	}
 	
 	@Test
diff --git a/tlatools/test/tlc2/tool/RandomElementTest.java b/tlatools/test/tlc2/tool/RandomElementTest.java
index d118507c7142fed88856c652b492667d40c389f9..0066f0134a4f9f857f151b2c3aa17ebc44e5a9af 100644
--- a/tlatools/test/tlc2/tool/RandomElementTest.java
+++ b/tlatools/test/tlc2/tool/RandomElementTest.java
@@ -47,7 +47,7 @@ public class RandomElementTest extends ModelCheckerTestCase {
 	public void test() {
 		assertTrue(recorder.recorded(EC.TLC_FINISHED));
 		assertFalse(recorder.recorded(EC.TLC_BUG));
-		assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "933", "855", "388"));
+		assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "932", "855", "388"));
 
 		assertTrue(recorder.recorded(EC.TLC_BEHAVIOR_UP_TO_THIS_POINT));
 		
diff --git a/tlatools/test/tlc2/tool/RandomSubsetNextTest.java b/tlatools/test/tlc2/tool/RandomSubsetNextTest.java
index 3b7bef50eef93328be779dd9bda57a634e4b824b..81618cee0ff1b46affe9c6748f18bd8db05f2fe5 100644
--- a/tlatools/test/tlc2/tool/RandomSubsetNextTest.java
+++ b/tlatools/test/tlc2/tool/RandomSubsetNextTest.java
@@ -47,7 +47,7 @@ public class RandomSubsetNextTest extends ModelCheckerTestCase {
 	public void testSpec() {
 		assertTrue(recorder.recorded(EC.TLC_FINISHED));
 		assertFalse(recorder.recorded(EC.TLC_BUG));
-		assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "67330", "7732", "999"));
+		assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "67321", "7732", "999"));
 
 		assertTrue(recorder.recorded(EC.TLC_BEHAVIOR_UP_TO_THIS_POINT));
 		
diff --git a/tlatools/test/tlc2/tool/SetPredValueTest.java b/tlatools/test/tlc2/tool/SetPredValueTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e38a9fb931b9c848a9d3df6701ac4f634390eb0
--- /dev/null
+++ b/tlatools/test/tlc2/tool/SetPredValueTest.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import tlc2.output.EC;
+import tlc2.tool.liveness.ModelCheckerTestCase;
+
+public class SetPredValueTest extends ModelCheckerTestCase {
+
+	public SetPredValueTest() {
+		super("SetPredValue");
+	}
+
+	@Test
+	public void testSpec() {
+		assertTrue(recorder.recorded(EC.TLC_FINISHED));
+		assertFalse(recorder.recorded(EC.GENERAL));
+		assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "0", "0", "0"));
+	}
+}
diff --git a/tlatools/test/tlc2/tool/TSnapShotTest.java b/tlatools/test/tlc2/tool/TSnapShotTest.java
index fd9f94b84a9166a8afaa1237d7c697e200a6be39..55bf3cde2d2ee7a976f926c2bfb0e8f114dd9b9c 100644
--- a/tlatools/test/tlc2/tool/TSnapShotTest.java
+++ b/tlatools/test/tlc2/tool/TSnapShotTest.java
@@ -34,11 +34,12 @@ import org.junit.Test;
 import tlc2.output.EC;
 import tlc2.output.EC.ExitStatus;
 import tlc2.tool.liveness.ModelCheckerTestCase;
+import util.TLAConstants;
 
 public class TSnapShotTest extends ModelCheckerTestCase {
 
 	public TSnapShotTest() {
-		super("MC", "TSnapShot", ExitStatus.FAILURE_SAFETY_EVAL);
+		super(TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, "TSnapShot", ExitStatus.FAILURE_SAFETY_EVAL);
 	}
 	
 	@Test
diff --git a/tlatools/test/tlc2/tool/UserModuleOverrideAnnotationTest.java b/tlatools/test/tlc2/tool/UserModuleOverrideAnnotationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d2239121bb4b23fbe306b134677f1a8a26c267e0
--- /dev/null
+++ b/tlatools/test/tlc2/tool/UserModuleOverrideAnnotationTest.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+import tlc2.output.EC;
+import tlc2.tool.liveness.ModelCheckerTestCase;
+
+@RunWith(BlockJUnit4ClassRunner.class)
+public class UserModuleOverrideAnnotationTest extends ModelCheckerTestCase {
+
+	public UserModuleOverrideAnnotationTest() {
+		super("UserModuleOverrideAnnotation");
+	}
+	
+	@Test
+	public void testSpec() {
+		recorder.recorded(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_MODULE_MISMATCH);
+		recorder.recorded(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_IDENTIFIER_MISMATCH);
+		recorder.recorded(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE_MISMATCH);
+
+		// ModelChecker has finished and generated the expected amount of states
+		assertTrue(recorder.recorded(EC.TLC_FINISHED));
+		assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "1", "0"));
+		assertFalse(recorder.recorded(EC.GENERAL));
+
+		assertZeroUncovered();
+	}
+}
diff --git a/tlatools/test/tlc2/tool/coverage/Github377CoverageTest.java b/tlatools/test/tlc2/tool/coverage/Github377CoverageTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d23707671092dd8bc8d71cf08f9c27c65dddc5e9
--- /dev/null
+++ b/tlatools/test/tlc2/tool/coverage/Github377CoverageTest.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool.coverage;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import tlc2.output.EC;
+
+public class Github377CoverageTest extends AbstractCoverageTest {
+
+    public Github377CoverageTest () {
+        super("Github377");
+    }
+
+    @Test
+    public void testSpec () {
+		// ModelChecker has finished and generated the expected amount of states
+		assertTrue(recorder.recorded(EC.TLC_FINISHED));
+		assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "1"));
+		assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "1", "0"));
+
+		// No 'general' errors recorded
+		assertFalse(recorder.recorded(EC.GENERAL));
+
+		assertCoverage("<Action line 5, col 9 to line 5, col 16 of module Github377>: 1:1\n" + 
+				"  line 5, col 9 to line 5, col 16 of module Github377: 1\n" + 
+				"<Action line 5, col 24 to line 5, col 34 of module Github377>: 0:1\n" + 
+				"  line 5, col 24 to line 5, col 34 of module Github377: 1\n" + 
+				"<1Inv line 9, col 1 to line 9, col 4 of module Github377>\n" + 
+				"  line 10, col 6 to line 10, col 69 of module Github377: 1\n" + 
+				"  line 11, col 5 to line 11, col 13 of module Github377: 1\n" + 
+				"<1InvNonRec line 15, col 1 to line 15, col 10 of module Github377>\n" + 
+				"  line 16, col 6 to line 16, col 40 of module Github377: 1\n" + 
+				"  line 17, col 5 to line 17, col 13 of module Github377: 1\n" + 
+				"<2Inv line 21, col 1 to line 21, col 4 of module Github377>\n" + 
+				"  line 25, col 10 to line 25, col 47 of module Github377: 1\n" + 
+				"  line 26, col 7 to line 26, col 11 of module Github377: 1\n" + 
+				"<2aInv line 28, col 1 to line 28, col 5 of module Github377>\n" + 
+				"  line 32, col 10 to line 33, col 21 of module Github377: 1\n" + 
+				"  line 34, col 7 to line 34, col 11 of module Github377: 1\n" + 
+				"<2bInv line 36, col 1 to line 36, col 5 of module Github377>\n" + 
+				"  line 40, col 10 to line 40, col 31 of module Github377: 1\n" + 
+				"  line 41, col 7 to line 41, col 11 of module Github377: 1\n" + 
+				"<3aInv line 44, col 1 to line 44, col 5 of module Github377>\n" + 
+				"  line 48, col 10 to line 50, col 21 of module Github377: 1\n" + 
+				"  line 51, col 7 to line 51, col 11 of module Github377: 1\n" + 
+				"<3bInv line 55, col 1 to line 55, col 5 of module Github377>\n" + 
+				"  line 58, col 11 to line 58, col 42 of module Github377: 1\n" + 
+				"  line 57, col 11 to line 57, col 70 of module Github377: 1\n" + 
+				"  line 60, col 13 to line 60, col 31 of module Github377: 1\n" + 
+				"  line 61, col 7 to line 61, col 11 of module Github377: 1\n" + 
+				"<4Inv line 66, col 1 to line 66, col 4 of module Github377>\n" + 
+				"  line 71, col 11 to line 71, col 18 of module Github377: 1\n" + 
+				"  line 72, col 7 to line 72, col 11 of module Github377: 1");
+		assertFalse(recorder.recorded(EC.TLC_COVERAGE_MISMATCH));
+    }
+}
diff --git a/tlatools/test/tlc2/tool/coverage/ICoverageTest.java b/tlatools/test/tlc2/tool/coverage/ICoverageTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a8dcaf43a062a01d78883fda0614012686635518
--- /dev/null
+++ b/tlatools/test/tlc2/tool/coverage/ICoverageTest.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool.coverage;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import tlc2.output.EC;
+
+public class ICoverageTest extends AbstractCoverageTest {
+
+    public ICoverageTest () {
+        super("I");
+    }
+
+    @Test
+    public void testSpec () {
+		// ModelChecker has finished and generated the expected amount of states
+		assertTrue(recorder.recorded(EC.TLC_FINISHED));
+		assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "1"));
+		assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "20", "5", "0"));
+
+		// No 'general' errors recorded
+		assertFalse(recorder.recorded(EC.GENERAL));
+
+		assertCoverage("<Action line 11, col 9 to line 11, col 25 of module I>: 5:5\n" + 
+				"  line 11, col 9 to line 11, col 25 of module I: 5\n" + 
+				"  |line 11, col 15 to line 11, col 25 of module I: 1:6\n" + 
+				"<Action line 11, col 52 to line 11, col 55 of module I>: 0:15\n" + 
+				"  line 11, col 52 to line 11, col 52 of module I: 15\n" +
+				"  |line 8, col 1 to line 9, col 22 of module I: 15\n" + 
+				"  ||line 9, col 8 to line 9, col 22 of module I: 15\n" + 
+				"  ||line 8, col 9 to line 8, col 15 of module I: 15\n" + 
+				"  line 11, col 54 to line 11, col 54 of module I: 15\n" +
+				"<Inv line 13, col 1 to line 13, col 3 of module I>\n" + 
+				"  line 13, col 8 to line 13, col 34 of module I: 5\n" + 
+				"  |line 13, col 27 to line 13, col 34 of module I: 15\n" + 
+				"  |line 13, col 17 to line 13, col 24 of module I: 5");
+		assertFalse(recorder.recorded(EC.TLC_COVERAGE_MISMATCH));
+    }
+}
diff --git a/tlatools/test/tlc2/tool/coverage/JCoverageTest.java b/tlatools/test/tlc2/tool/coverage/JCoverageTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a1bfde26c4517186850d89adf0f48ebba4d46fe
--- /dev/null
+++ b/tlatools/test/tlc2/tool/coverage/JCoverageTest.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool.coverage;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import tlc2.output.EC;
+
+public class JCoverageTest extends AbstractCoverageTest {
+
+    public JCoverageTest () {
+        super("J");
+    }
+
+    @Test
+    public void testSpec () {
+		// ModelChecker has finished and generated the expected amount of states
+		assertTrue(recorder.recorded(EC.TLC_FINISHED));
+		assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2"));
+		assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "11", "6", "0"));
+
+		// No 'general' errors recorded
+		assertFalse(recorder.recorded(EC.GENERAL));
+
+		assertCoverage("<Init line 5, col 1 to line 5, col 4 of module J>: 5:5\n" + 
+				"  line 5, col 12 to line 5, col 28 of module J: 1\n" + 
+				"  line 6, col 12 to line 6, col 40 of module J: 5\n" + 
+				"<Next line 12, col 1 to line 12, col 4 of module J>: 1:6\n" + 
+				"  line 12, col 12 to line 12, col 22 of module J: 6\n" + 
+				"  |line 12, col 17 to line 12, col 22 of module J: 6\n" + 
+				"  ||line 9, col 2 to line 10, col 19 of module J: 6\n" + 
+				"  |||line 9, col 7 to line 9, col 11 of module J: 6\n" + 
+				"  |||line 9, col 16 to line 9, col 40 of module J: 2\n" + 
+				"  |||line 10, col 7 to line 10, col 19 of module J: 4\n" + 
+				"  ||line 12, col 21 to line 12, col 21 of module J: 6\n" + 
+				"  line 13, col 12 to line 13, col 22 of module J: 6");
+		assertFalse(recorder.recorded(EC.TLC_COVERAGE_MISMATCH));
+    }
+}
diff --git a/tlatools/test/tlc2/tool/coverage/KCoverageTest.java b/tlatools/test/tlc2/tool/coverage/KCoverageTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a10a275bbfb7ff32abb2e2c2d2fbe07485c6539
--- /dev/null
+++ b/tlatools/test/tlc2/tool/coverage/KCoverageTest.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool.coverage;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import tlc2.output.EC;
+
+public class KCoverageTest extends AbstractCoverageTest {
+
+    public KCoverageTest () {
+        super("K");
+    }
+
+    @Test
+    public void testSpec () {
+		// ModelChecker has finished and generated the expected amount of states
+		assertTrue(recorder.recorded(EC.TLC_FINISHED));
+		assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "1"));
+		assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "1", "0"));
+
+		// No 'general' errors recorded
+		assertFalse(recorder.recorded(EC.GENERAL));
+
+		assertFalse(recorder.recorded(EC.TLC_COVERAGE_MISMATCH));
+    }
+}
diff --git a/tlatools/test/tlc2/tool/coverage/LCoverageTest.java b/tlatools/test/tlc2/tool/coverage/LCoverageTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..16cb8569cb2aad46741f67b155a8debd747d60d2
--- /dev/null
+++ b/tlatools/test/tlc2/tool/coverage/LCoverageTest.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool.coverage;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import tlc2.output.EC;
+
+public class LCoverageTest extends AbstractCoverageTest {
+
+    public LCoverageTest () {
+        super("L");
+    }
+
+    @Test
+    public void testSpec () {
+		// ModelChecker has finished and generated the expected amount of states
+		assertTrue(recorder.recorded(EC.TLC_FINISHED));
+		assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "1"));
+		assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "1", "0"));
+
+		// No 'general' errors recorded
+		assertFalse(recorder.recorded(EC.GENERAL));
+
+		assertFalse(recorder.recorded(EC.TLC_COVERAGE_MISMATCH));
+    }
+}
diff --git a/tlatools/test/tlc2/tool/distributed/TSnapShotDistributedTLCTest.java b/tlatools/test/tlc2/tool/distributed/TSnapShotDistributedTLCTest.java
index a7e7f800dd49b99953ba2af4ed86236c54db86bb..4ad162cbfb621885616611fe2f3e5c1c87425ac6 100644
--- a/tlatools/test/tlc2/tool/distributed/TSnapShotDistributedTLCTest.java
+++ b/tlatools/test/tlc2/tool/distributed/TSnapShotDistributedTLCTest.java
@@ -33,11 +33,12 @@ import java.io.File;
 import org.junit.Test;
 
 import tlc2.output.EC;
+import util.TLAConstants;
 
 public class TSnapShotDistributedTLCTest extends DistributedTLCTestCase {
 
 	public TSnapShotDistributedTLCTest() {
-		super("MC", BASE_PATH + "TSnapShot" + File.separator, new String[] {"-deadlock"});
+		super(TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, BASE_PATH + "TSnapShot" + File.separator, new String[] {"-deadlock"});
 	}
 
 	@Test
diff --git a/tlatools/test/tlc2/tool/liveness/CodePlexBug08Test.java b/tlatools/test/tlc2/tool/liveness/CodePlexBug08Test.java
index c27b3d0647cde8feda1e3b86a77a9ce07f7bbbd6..cc1e1f50b4efee1321b65153a8b898674815c7e5 100644
--- a/tlatools/test/tlc2/tool/liveness/CodePlexBug08Test.java
+++ b/tlatools/test/tlc2/tool/liveness/CodePlexBug08Test.java
@@ -36,6 +36,7 @@ import org.junit.Test;
 
 import tlc2.output.EC;
 import tlc2.output.EC.ExitStatus;
+import util.TLAConstants;
 
 /**
  * see http://tlaplus.codeplex.com/workitem/8
@@ -43,7 +44,7 @@ import tlc2.output.EC.ExitStatus;
 public class CodePlexBug08Test extends ModelCheckerTestCase {
 
 	public CodePlexBug08Test() {
-		super("MC", "CodePlexBug08", ExitStatus.VIOLATION_LIVENESS);
+		super(TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, "CodePlexBug08", ExitStatus.VIOLATION_LIVENESS);
 	}
 	
 	@Test
diff --git a/tlatools/test/tlc2/tool/liveness/LivenessConstraintWarning.java b/tlatools/test/tlc2/tool/liveness/LivenessConstraintWarning.java
new file mode 100644
index 0000000000000000000000000000000000000000..e2eee814faaffc7d8228ab3f179c63048e779e26
--- /dev/null
+++ b/tlatools/test/tlc2/tool/liveness/LivenessConstraintWarning.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.tool.liveness;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import tlc2.output.EC;
+
+public class LivenessConstraintWarning extends ModelCheckerTestCase {
+
+	public LivenessConstraintWarning() {
+		super("LivenessConstraintWarning");
+	}
+	
+	@Test
+	public void testSpec() {
+		assertTrue(recorder.recorded(EC.TLC_FINISHED));
+		assertTrue(recorder.recorded(EC.TLC_FEATURE_LIVENESS_CONSTRAINTS));
+		assertFalse(recorder.recorded(EC.GENERAL));
+	}
+}
diff --git a/tlatools/test/tlc2/tool/liveness/ModelCheckerTestCase.java b/tlatools/test/tlc2/tool/liveness/ModelCheckerTestCase.java
index 258067947519b8ec8b4841245c70e67eb56805be..7249b45070590c4e1a3ee56bf347607299016422 100644
--- a/tlatools/test/tlc2/tool/liveness/ModelCheckerTestCase.java
+++ b/tlatools/test/tlc2/tool/liveness/ModelCheckerTestCase.java
@@ -93,11 +93,17 @@ public abstract class ModelCheckerTestCase extends CommonTestCase {
 		this.expectedExitStatus = exitStatus;
 	}
 
+	protected void beforeSetUp() {
+		// No-op
+	}
+
 	/* (non-Javadoc)
 	 * @see junit.framework.TestCase#setUp()
 	 */
 	@Before
 	public void setUp() {
+		beforeSetUp();
+		
 		// some tests might want to access the liveness graph after model
 		// checking completed. Thus, prevent the liveness graph from being
 		// closed too earlier.
@@ -136,8 +142,10 @@ public abstract class ModelCheckerTestCase extends CommonTestCase {
 			args.add("-fp");
 			args.add("0");
 			
-			args.add("-coverage");
-			args.add("1");
+			if (doCoverage()) {
+				args.add("-coverage");
+				args.add("1");
+			}
 			
 			args.add("-workers");
 			args.add(Integer.toString(getNumberOfThreads()));
@@ -167,12 +175,26 @@ public abstract class ModelCheckerTestCase extends CommonTestCase {
 			fail(e.getMessage());
 		}
 	}
+
+	protected void beforeTearDown() {
+		// No-op
+	}
 	
 	@After
-	public void assertExitStatus() {
+	public void tearDown() {
+		beforeTearDown();
+		
+		assertExitStatus();
+	}
+	
+	protected void assertExitStatus() {
 		assertEquals(expectedExitStatus, actualExitStatus);
 	}
-
+	
+	protected boolean doCoverage() {
+		return true;
+	}
+	
 	/**
 	 * @return True if TLC is to be called with "-deadlock".
 	 */
diff --git a/tlatools/test/tlc2/tool/liveness/NQTest.java b/tlatools/test/tlc2/tool/liveness/NQTest.java
index be01acc7c7503af7791444c9ec0c46702c199911..2a31ef1797f5fb027c89346ea9eb7ad715965ad9 100644
--- a/tlatools/test/tlc2/tool/liveness/NQTest.java
+++ b/tlatools/test/tlc2/tool/liveness/NQTest.java
@@ -35,11 +35,12 @@ import org.junit.Ignore;
 import org.junit.Test;
 
 import tlc2.output.EC;
+import util.TLAConstants;
 
 public class NQTest extends ModelCheckerTestCase {
 
 	public NQTest() {
-		super("MC", "symmetry" + File.separator + "NQ");
+		super(TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, "symmetry" + File.separator + "NQ");
 	}
 	
 	/*
diff --git a/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTest3.java b/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTest3.java
index 72c61c6c1544b690adf6a3aa32b3e799992f3d54..9590eef845a27ab8dd32ab836b1aed0c2052946e 100644
--- a/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTest3.java
+++ b/tlatools/test/tlc2/tool/liveness/SymmetryModelCheckerTest3.java
@@ -36,11 +36,12 @@ import org.junit.Ignore;
 import org.junit.Test;
 
 import tlc2.output.EC;
+import util.TLAConstants;
 
 public class SymmetryModelCheckerTest3 extends ModelCheckerTestCase {
 
 	public SymmetryModelCheckerTest3() {
-		super("MC", "symmetry");
+		super(TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, "symmetry");
 	}
 	
 	@Test
diff --git a/tlatools/test/tlc2/tool/liveness/TwoPhaseCommitTest.java b/tlatools/test/tlc2/tool/liveness/TwoPhaseCommitTest.java
index 3c5950a54025dc87f300300ca426ed77241e8866..4ce85eba6de9539e5aa5c3b822aef521895abfc5 100644
--- a/tlatools/test/tlc2/tool/liveness/TwoPhaseCommitTest.java
+++ b/tlatools/test/tlc2/tool/liveness/TwoPhaseCommitTest.java
@@ -32,11 +32,12 @@ import java.io.File;
 import org.junit.Test;
 
 import tlc2.output.EC;
+import util.TLAConstants;
 
 public class TwoPhaseCommitTest extends ModelCheckerTestCase {
 
 	public TwoPhaseCommitTest() {
-		super("MC", "symmetry" + File.separator + "TwoPhaseCommit");
+		super(TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, "symmetry" + File.separator + "TwoPhaseCommit");
 	}
 	
 	@Test
diff --git a/tlatools/test/tlc2/tool/liveness/simulation/StutteringTest.java b/tlatools/test/tlc2/tool/liveness/simulation/StutteringTest.java
index 4ed5fa134e96b3b3010801f347357289aebe94d4..78577e5c81fec309767be51bf0c0b48539c2e41c 100644
--- a/tlatools/test/tlc2/tool/liveness/simulation/StutteringTest.java
+++ b/tlatools/test/tlc2/tool/liveness/simulation/StutteringTest.java
@@ -34,11 +34,12 @@ import org.junit.Test;
 import tlc2.output.EC;
 import tlc2.output.EC.ExitStatus;
 import tlc2.tool.liveness.ModelCheckerTestCase;
+import util.TLAConstants;
 
 public class StutteringTest extends ModelCheckerTestCase {
 
 	public StutteringTest() {
-		super("MC", "CodePlexBug08", new String[] { "-simulate" }, ExitStatus.VIOLATION_LIVENESS);
+		super(TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, "CodePlexBug08", new String[] { "-simulate" }, ExitStatus.VIOLATION_LIVENESS);
 	}
 
 	@Test
diff --git a/tlatools/test/tlc2/tool/simulation/NQSpecTest.java b/tlatools/test/tlc2/tool/simulation/NQSpecTest.java
index 6391d4936c31d3b21e3f6b360fa4c6ee6ef556ea..6bd0830733ac9dcf07a6c996698f45e47585aae1 100644
--- a/tlatools/test/tlc2/tool/simulation/NQSpecTest.java
+++ b/tlatools/test/tlc2/tool/simulation/NQSpecTest.java
@@ -36,11 +36,12 @@ import org.junit.Test;
 import tlc2.TLC;
 import tlc2.output.EC;
 import tlc2.tool.liveness.ModelCheckerTestCase;
+import util.TLAConstants;
 
 public class NQSpecTest extends ModelCheckerTestCase {
 
 	public NQSpecTest() {
-		super("MC", "simulation" + File.separator + "NQSpec", new String[] { "-simulate" });
+		super(TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, "simulation" + File.separator + "NQSpec", new String[] { "-simulate" });
 		TLC.setTraceNum(100);
 	}
 
diff --git a/tlatools/test/tlc2/tool/simulation/SimulationWorkerTest.java b/tlatools/test/tlc2/tool/simulation/SimulationWorkerTest.java
index fcf29d22d17e648463dccb63acf1583cf782ca8d..f44cd05fd2a33c1accceed3fde0ea344d61a6226 100644
--- a/tlatools/test/tlc2/tool/simulation/SimulationWorkerTest.java
+++ b/tlatools/test/tlc2/tool/simulation/SimulationWorkerTest.java
@@ -21,13 +21,15 @@ import tlc2.tool.ITool;
 import tlc2.tool.SimulationWorker;
 import tlc2.tool.SimulationWorker.SimulationWorkerError;
 import tlc2.tool.SimulationWorker.SimulationWorkerResult;
-import tlc2.tool.impl.Tool;
 import tlc2.tool.StateVec;
 import tlc2.tool.TLCState;
+import tlc2.tool.impl.FastTool;
+import tlc2.tool.impl.Tool;
 import tlc2.tool.liveness.ILiveCheck;
 import tlc2.tool.liveness.NoOpLiveCheck;
 import util.FileUtil;
 import util.SimpleFilenameToStream;
+import util.TLAConstants;
 import util.ToolIO;
 import util.UniqueString;
 
@@ -60,7 +62,7 @@ public class SimulationWorkerTest extends CommonTestCase {
 
 	@Test
 	public void testSuccessfulRun() throws Exception {
-		Tool tool = new Tool("", "BasicMultiTrace", "MC", new SimpleFilenameToStream());
+		Tool tool = new FastTool("", "BasicMultiTrace", TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, new SimpleFilenameToStream());
 
 		ILiveCheck liveCheck =  new NoOpLiveCheck(tool, "BasicMultiTrace");
 		StateVec initStates = tool.getInitStates();
@@ -76,7 +78,7 @@ public class SimulationWorkerTest extends CommonTestCase {
 	
 	@Test
 	public void testInvariantViolation() throws Exception {
-		Tool tool = new Tool("", "BasicMultiTrace", "MCInv", new SimpleFilenameToStream());
+		Tool tool = new FastTool("", "BasicMultiTrace", "MCInv", new SimpleFilenameToStream());
 		
 		ILiveCheck liveCheck =  new NoOpLiveCheck(tool, "BasicMultiTrace");
 		StateVec initStates = tool.getInitStates();
@@ -151,7 +153,7 @@ public class SimulationWorkerTest extends CommonTestCase {
 	
 	@Test
 	public void testActionPropertyViolation() throws Exception {
-		ITool tool = new Tool("", "BasicMultiTrace", "MCActionProp", new SimpleFilenameToStream());
+		ITool tool = new FastTool("", "BasicMultiTrace", "MCActionProp", new SimpleFilenameToStream());
 		
 		StateVec initStates = tool.getInitStates();
 		ILiveCheck liveCheck =  new NoOpLiveCheck(tool, "BasicMultiTrace");
@@ -199,7 +201,7 @@ public class SimulationWorkerTest extends CommonTestCase {
 	
 	@Test
 	public void testInvariantBadEval() throws Exception {
-		ITool tool = new Tool("", "BasicMultiTrace", "MCBadInvNonInitState", new SimpleFilenameToStream());
+		ITool tool = new FastTool("", "BasicMultiTrace", "MCBadInvNonInitState", new SimpleFilenameToStream());
 		
 		StateVec initStates = tool.getInitStates();
 		ILiveCheck liveCheck =  new NoOpLiveCheck(tool, "BasicMultiTrace");
@@ -227,7 +229,7 @@ public class SimulationWorkerTest extends CommonTestCase {
 	
 	@Test
 	public void testActionPropertyBadEval() throws Exception {
-		ITool tool = new Tool("", "BasicMultiTrace", "MCActionPropBadEval", new SimpleFilenameToStream());
+		ITool tool = new FastTool("", "BasicMultiTrace", "MCActionPropBadEval", new SimpleFilenameToStream());
 		
 		StateVec initStates = tool.getInitStates();
 		ILiveCheck liveCheck =  new NoOpLiveCheck(tool, "BasicMultiTrace");
@@ -248,7 +250,7 @@ public class SimulationWorkerTest extends CommonTestCase {
 	
 	@Test
 	public void testUnderspecifiedNext() throws Exception {
-		ITool tool = new Tool("", "BasicMultiTrace", "MCUnderspecNext", new SimpleFilenameToStream());
+		ITool tool = new FastTool("", "BasicMultiTrace", "MCUnderspecNext", new SimpleFilenameToStream());
 		
 		StateVec initStates = tool.getInitStates();
 		ILiveCheck liveCheck =  new NoOpLiveCheck(tool, "BasicMultiTrace");
@@ -276,7 +278,7 @@ public class SimulationWorkerTest extends CommonTestCase {
 	
 	@Test
 	public void testDeadlock() throws Exception {
-		ITool tool = new Tool("", "BasicMultiTrace", "MC", new SimpleFilenameToStream());
+		ITool tool = new FastTool("", "BasicMultiTrace", TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, new SimpleFilenameToStream());
 		
 		StateVec initStates = tool.getInitStates();
 		ILiveCheck liveCheck =  new NoOpLiveCheck(tool, "BasicMultiTrace");
@@ -321,7 +323,7 @@ public class SimulationWorkerTest extends CommonTestCase {
 	
 	@Test
 	public void testModelStateConstraint() throws Exception {
-		ITool tool = new Tool("", "BasicMultiTrace", "MCWithConstraint", new SimpleFilenameToStream());
+		ITool tool = new FastTool("", "BasicMultiTrace", "MCWithConstraint", new SimpleFilenameToStream());
 		
 		StateVec initStates = tool.getInitStates();
 		ILiveCheck liveCheck =  new NoOpLiveCheck(tool, "BasicMultiTrace");
@@ -338,7 +340,7 @@ public class SimulationWorkerTest extends CommonTestCase {
 	
 	@Test
 	public void testModelActionConstraint() throws Exception {
-		ITool tool = new Tool("", "BasicMultiTrace", "MCWithActionConstraint", new SimpleFilenameToStream());
+		ITool tool = new FastTool("", "BasicMultiTrace", "MCWithActionConstraint", new SimpleFilenameToStream());
 		
 		StateVec initStates = tool.getInitStates();
 		ILiveCheck liveCheck =  new NoOpLiveCheck(tool, "BasicMultiTrace");
@@ -355,7 +357,7 @@ public class SimulationWorkerTest extends CommonTestCase {
 	
 	@Test
 	public void testWorkerInterruption() throws Exception {
-		ITool tool = new Tool("", "BasicMultiTrace", "MCInv", new SimpleFilenameToStream());
+		ITool tool = new FastTool("", "BasicMultiTrace", "MCInv", new SimpleFilenameToStream());
 		
 		StateVec initStates = tool.getInitStates();
 		ILiveCheck liveCheck =  new NoOpLiveCheck(tool, "BasicMultiTrace");
@@ -384,7 +386,7 @@ public class SimulationWorkerTest extends CommonTestCase {
 
 	@Test
 	public void testTraceDepthObeyed() throws Exception {
-		ITool tool = new Tool("", "BasicMultiTrace", "MCInv", new SimpleFilenameToStream());
+		ITool tool = new FastTool("", "BasicMultiTrace", "MCInv", new SimpleFilenameToStream());
 		
 		StateVec initStates = tool.getInitStates();
 		ILiveCheck liveCheck =  new NoOpLiveCheck(tool, "BasicMultiTrace");
@@ -405,7 +407,7 @@ public class SimulationWorkerTest extends CommonTestCase {
 	
 	@Test
 	public void testStateAndTraceGenerationCount() throws Exception {
-		ITool tool = new Tool("", "BasicMultiTrace", "MC", new SimpleFilenameToStream());
+		ITool tool = new FastTool("", "BasicMultiTrace", TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, new SimpleFilenameToStream());
 		
 		StateVec initStates = tool.getInitStates();
 		ILiveCheck liveCheck =  new NoOpLiveCheck(tool, "BasicMultiTrace");
diff --git a/tlatools/test/tlc2/tool/simulation/SimulatorTest.java b/tlatools/test/tlc2/tool/simulation/SimulatorTest.java
index 214d281818aa182d0d873bbe78a19cc8a2008bfb..70756893fda447ef31d7fcdd00b242bdafae2138 100644
--- a/tlatools/test/tlc2/tool/simulation/SimulatorTest.java
+++ b/tlatools/test/tlc2/tool/simulation/SimulatorTest.java
@@ -20,6 +20,7 @@ import tlc2.util.FP64;
 import tlc2.util.RandomGenerator;
 import util.FileUtil;
 import util.SimpleFilenameToStream;
+import util.TLAConstants;
 import util.ToolIO;
 
 /**
@@ -39,6 +40,9 @@ public class SimulatorTest extends CommonTestCase {
 		// Make the each unit test execution as deterministic as possible.
 		rng = new RandomGenerator(0);
 		ToolIO.setUserDir(BASE_PATH + File.separator + "simulation" + File.separator + "BasicMultiTrace");
+		
+		// Printing the error trace entails fingerprint its states.
+		FP64.Init();
 	}
 	
 	@After
@@ -67,7 +71,7 @@ public class SimulatorTest extends CommonTestCase {
 	
 	@Test
 	public void testSuccessfulSimulation() {	
-		runSimulatorTest("BasicMultiTrace", "MC", false, 100, 100);
+		runSimulatorTest("BasicMultiTrace", TLAConstants.Files.MODEL_CHECK_FILE_BASENAME, false, 100, 100);
 		assertFalse(recorder.recorded(EC.TLC_INVARIANT_VIOLATED_INITIAL));
 		assertTrue(recorder.recorded(EC.TLC_PROGRESS_SIMU));
 	}
diff --git a/tlatools/test/tlc2/util/FP64Test.java b/tlatools/test/tlc2/util/FP64Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..cc31a31523abb5836f4e8aa7fd9b72c34d2b279c
--- /dev/null
+++ b/tlatools/test/tlc2/util/FP64Test.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved.
+ *
+ * The MIT License (MIT)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Random;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class FP64Test {
+
+	@Before
+	public void setup() {
+		FP64.Init();
+	}
+	
+	@Test
+	public void testExtendLongInt() {
+		final Random random = new Random();
+		for (int i = 0; i < 1000; i++) {
+			final long fp = random.nextLong();
+			final int x = random.nextInt();
+			assertEquals(FP64.Extend(fp, x), FP64.ExtendLoop(fp, x));
+		}
+	}
+}
diff --git a/tlatools/test/tlc2/value/impl/InitializeValueTest.java b/tlatools/test/tlc2/value/impl/InitializeValueTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..0628e479e70a1bb83039d5ff820dacd8dada1a0f
--- /dev/null
+++ b/tlatools/test/tlc2/value/impl/InitializeValueTest.java
@@ -0,0 +1,283 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Research. All rights reserved. 
+ *
+ * The MIT License (MIT)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy 
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Contributors:
+ *   Markus Alexander Kuppe - initial API and implementation
+ ******************************************************************************/
+package tlc2.value.impl;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import tlc2.util.FP64;
+import util.InternTable;
+import util.UniqueString;
+
+public class InitializeValueTest {
+
+	@BeforeClass
+	public static void setup() {
+		FP64.Init();
+	}
+	
+	/**
+	 * Test method for {@link tlc2.value.impl.UnionValue#deepNormalize()}.
+	 */
+	@Test
+	public void union() {
+		final ValueVec vec = new ValueVec();
+		vec.addElement(new SetEnumValue(new IntValue[] {IntValue.gen(42)}, false));
+		vec.addElement(new SetEnumValue(new IntValue[] {IntValue.gen(23)}, false));
+		vec.addElement(new SetEnumValue(new IntValue[] {IntValue.gen(4711)}, false));
+		vec.addElement(new SetEnumValue(new IntValue[] {IntValue.gen(1)}, false));
+		
+		final UnionValue uv = new UnionValue(new SetEnumValue(vec, false));
+		assertFalse(uv.isNormalized());
+		assertFalse(uv.set.isNormalized());
+		
+		uv.initialize();
+		
+		assertTrue(uv.set.isNormalized());
+		assertTrue(uv.isNormalized());
+	}
+
+	/**
+	 * Test method for {@link tlc2.value.impl.SetCapValue#deepNormalize()}.
+	 */
+	@Test
+	public void setcap() {
+		final ValueVec vec = new ValueVec();
+		vec.addElement(IntValue.gen(42));
+		vec.addElement(IntValue.gen(23));
+		vec.addElement(IntValue.gen(4711));
+		vec.addElement(IntValue.gen(1));
+		
+		SetCapValue scv = new SetCapValue(new SetEnumValue(vec, false), new SetEnumValue(vec, false));
+		assertFalse(scv.isNormalized());
+		assertFalse(scv.set1.isNormalized());
+		assertFalse(scv.set2.isNormalized());
+		
+		scv.initialize();
+		
+		assertTrue(scv.set1.isNormalized());
+		assertTrue(scv.set2.isNormalized());
+		assertTrue(scv.isNormalized());
+	}
+
+	@Test
+	public void setcup() {
+		final ValueVec vec = new ValueVec();
+		vec.addElement(IntValue.gen(42));
+		vec.addElement(IntValue.gen(23));
+		vec.addElement(IntValue.gen(4711));
+		vec.addElement(IntValue.gen(1));
+		
+		SetCupValue scv = new SetCupValue(new SetEnumValue(vec, false), new SetEnumValue(vec, false));
+		assertFalse(scv.isNormalized());
+		assertFalse(scv.set1.isNormalized());
+		assertFalse(scv.set2.isNormalized());
+		
+		scv.initialize();
+		
+		assertTrue(scv.set1.isNormalized());
+		assertTrue(scv.set2.isNormalized());
+		assertTrue(scv.isNormalized());
+	}
+
+	@Test
+	public void setdiff() {
+		final ValueVec vec = new ValueVec();
+		vec.addElement(IntValue.gen(42));
+		vec.addElement(IntValue.gen(23));
+		vec.addElement(IntValue.gen(4711));
+		vec.addElement(IntValue.gen(1));
+		
+		SetDiffValue sdv = new SetDiffValue(new SetEnumValue(vec, false), new SetEnumValue(vec, false));
+		assertFalse(sdv.isNormalized());
+		assertFalse(sdv.set1.isNormalized());
+		assertFalse(sdv.set2.isNormalized());
+		
+		sdv.initialize();
+		
+		assertTrue(sdv.isNormalized());
+		assertTrue(sdv.set1.isNormalized());
+		assertTrue(sdv.set2.isNormalized());
+	}
+
+	@Test
+	public void subset() {
+		final ValueVec vec = new ValueVec();
+		vec.addElement(IntValue.gen(42));
+		vec.addElement(IntValue.gen(23));
+		vec.addElement(IntValue.gen(4711));
+		vec.addElement(IntValue.gen(1));
+		
+		SubsetValue sub = new SubsetValue(new SetEnumValue(vec, false));
+		assertFalse(sub.isNormalized());
+		assertFalse(sub.set.isNormalized());
+		
+		sub.initialize();
+		
+		assertTrue(sub.set.isNormalized());
+		assertTrue(sub.isNormalized());
+	}
+
+	@Test
+	public void record() {
+		final InternTable internTable = new InternTable(2);
+		final UniqueString a = internTable.put("a");
+		final UniqueString b = internTable.put("b");
+		
+		final ValueVec vec = new ValueVec();
+		vec.addElement(IntValue.gen(42));
+		vec.addElement(IntValue.gen(23));
+		vec.addElement(IntValue.gen(4711));
+		vec.addElement(IntValue.gen(1));
+		final Value aVal = new SetEnumValue(vec, false);
+		final Value bVal = new SetEnumValue(vec, false);
+		
+		final RecordValue rcdv = new RecordValue(new UniqueString[] {b, a}, new Value[] {bVal, aVal}, false);
+
+		assertFalse(rcdv.isNormalized());
+		for (Value v : rcdv.values) {
+			assertFalse(v.isNormalized());
+		}
+		
+		rcdv.initialize();
+		
+		for (Value v : rcdv.values) {
+			assertTrue(v.isNormalized());
+		}
+		assertTrue(rcdv.isNormalized());
+	}
+
+	@Test
+	public void fcnrecord() {
+		final ValueVec vec = new ValueVec();
+		vec.addElement(IntValue.gen(42));
+		vec.addElement(IntValue.gen(23));
+		vec.addElement(IntValue.gen(4711));
+		vec.addElement(IntValue.gen(1));
+		final Value aVal = new SetEnumValue(vec, false);
+		final Value bVal = new SetEnumValue(vec, false);
+
+		final FcnRcdValue rcdv = new FcnRcdValue(new Value[] { new StringValue("B"), new StringValue("A") },
+				new Value[] { bVal, aVal }, false);
+
+		assertFalse(rcdv.isNormalized());
+		for (Value v : rcdv.values) {
+			assertFalse(v.isNormalized());
+		}
+		
+		rcdv.initialize();
+		
+		for (Value v : rcdv.values) {
+			assertTrue(v.isNormalized());
+		}
+		assertTrue(rcdv.isNormalized());
+	}
+	
+	@Test
+	public void tuple() {
+		final ValueVec vec = new ValueVec();
+		vec.addElement(IntValue.gen(42));
+		vec.addElement(IntValue.gen(23));
+		vec.addElement(IntValue.gen(4711));
+		vec.addElement(IntValue.gen(1));
+		final Value aVal = new SetEnumValue(vec, false);
+		
+		final TupleValue tuple = new TupleValue(aVal);
+
+//		for (Value v : tuple.elems) {
+//			assertFalse(v.isNormalized());
+//		}
+//		assertFalse(tuple.isNormalized());
+
+		tuple.initialize();
+		
+		assertTrue(tuple.isNormalized());
+		for (Value v : tuple.elems) {
+			assertTrue(v.isNormalized());
+		}
+	}
+	
+	@Test
+	public void setOfTuple() {
+		final IntervalValue intVal = new IntervalValue(1, 2);
+		final SetOfTuplesValue inner = new SetOfTuplesValue(intVal, intVal);
+		final SetOfTuplesValue tuples = new SetOfTuplesValue(inner, inner);
+		
+//		for (Value v : tuples.sets) {
+//			assertFalse(v.isNormalized());
+//		}
+//		assertFalse(tuples.isNormalized());
+		
+		tuples.initialize();
+		
+		assertTrue(tuples.isNormalized());
+		for (Value v : tuples.sets) {
+			assertTrue(v.isNormalized());
+		}
+	}
+	
+	@Test
+	public void setOfRcds() {
+
+		final Value[] values = new Value[3];
+		values[0] = new SetEnumValue(getValue(7, "a"), true);
+		values[1] = new IntervalValue(1, 2);
+		values[2] = new IntervalValue(1, 4);
+
+		final SetOfRcdsValue setOfRcrds= new SetOfRcdsValue(getNames(3), values, true);
+
+//		for (Value v : setOfRcrds.values) {
+//			assertFalse(v.isNormalized());
+//		}
+//		assertFalse(setOfRcrds.isNormalized());
+
+		setOfRcrds.initialize();
+
+		assertTrue(setOfRcrds.isNormalized());
+		for (Value v : setOfRcrds.values) {
+			assertTrue(v.isNormalized());
+		}
+	}
+
+	private static final Value[] getValue(final int n, String str) {
+		final Value[] values = new Value[n];
+		for (int i = 0; i < n; i++) {
+			values[i] = new StringValue(str + i);
+		}
+		return values;
+	}
+
+	private static final UniqueString[] getNames(final int n) {
+		final UniqueString[] names = new UniqueString[n];
+		for (int i = 0; i < names.length; i++) {
+			names[i] = UniqueString.uniqueStringOf("N" + i);
+		}
+		return names;
+	}
+}
diff --git a/tlatools/test/tlc2/value/impl/IntervalValueTest.java b/tlatools/test/tlc2/value/impl/IntervalValueTest.java
index 9520823a06e35485c866d2fcbc15b77ceb6c6bf0..759f3220b2a361bdc69f239a594c6690712496fc 100644
--- a/tlatools/test/tlc2/value/impl/IntervalValueTest.java
+++ b/tlatools/test/tlc2/value/impl/IntervalValueTest.java
@@ -1,12 +1,11 @@
 package tlc2.value.impl;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import org.junit.Test;
 
-import tlc2.value.impl.IntValue;
-import tlc2.value.impl.IntervalValue;
 import util.Assert.TLCRuntimeException;
 
 public class IntervalValueTest {
@@ -40,4 +39,76 @@ public class IntervalValueTest {
 		}
 		fail();
 	}
+	
+	@Test
+	public void sizeOverflow() {
+		assertEquals(Integer.MAX_VALUE, new IntervalValue(1, Integer.MAX_VALUE).size());
+		assertEquals(Integer.MAX_VALUE, new IntervalValue(Integer.MIN_VALUE, -2).size());
+		
+		try {
+			assertEquals(0, new IntervalValue(-989_822_976, 1_157_660_672).size());
+		} catch (TLCRuntimeException e) {
+			assertTrue(e.getMessage().contains("Size of interval value exceeds the maximum representable size (32bits)"));
+			return;
+		}
+		fail();
+	}
+	
+	@Test
+	public void compareToOverflow1() {
+		final IntervalValue iv = new IntervalValue(Integer.MAX_VALUE - 1, Integer.MAX_VALUE);
+		assertEquals(2, iv.size());
+		
+		final IntervalValue iv2 = new IntervalValue(Integer.MIN_VALUE + 1, Integer.MIN_VALUE + 2);
+		assertEquals(2, iv2.size());
+		
+		assertEquals(1, iv.compareTo(iv2));
+	}
+
+	@Test
+	public void testCompareExtremeIntervals() {
+		final IntervalValue x = new IntervalValue(Integer.MIN_VALUE, -2);
+		final IntervalValue y = new IntervalValue(1, Integer.MAX_VALUE);
+		assertEquals(x.size(), y.size());
+		assertTrue(x.compareTo(y) < 0);
+		assertTrue(y.compareTo(x) > 0);
+	}
+
+	@Test
+	public void testEmptyIntervalEquality() {
+		IntervalValue i1 = new IntervalValue(10, 1);
+		IntervalValue i2 = new IntervalValue(20, 15);
+		assertEquals(i1, i2);
+	}
+
+	@Test
+	public void testCompareEmptyIntervals() {
+		int cmp = new IntervalValue(10, 1).compareTo(new IntervalValue(20, 15));
+		assertEquals(0, cmp);
+	}
+
+	@Test
+	public void testSizeOfMaximumRepresentableInterval() {
+		final IntervalValue iv = new IntervalValue(Integer.MIN_VALUE, Integer.MAX_VALUE);
+		try {
+			iv.size();
+		} catch (TLCRuntimeException e) {
+			assertTrue(e.getMessage().contains("Size of interval value exceeds the maximum representable size (32bits)"));
+			return;
+		}
+		fail();
+	}
+
+	@Test
+	public void testExtremeIntervalSize() {
+		final IntervalValue iv1 = new IntervalValue(Integer.MAX_VALUE, Integer.MAX_VALUE);
+		assertEquals(1, iv1.size());
+		final IntervalValue iv2 = new IntervalValue(Integer.MIN_VALUE, Integer.MIN_VALUE);
+		assertEquals(1, iv2.size());
+		final IntervalValue iv3 = new IntervalValue(Integer.MAX_VALUE-10, Integer.MAX_VALUE);
+		assertEquals(11, iv3.size());
+		final IntervalValue iv4 = new IntervalValue(Integer.MIN_VALUE, Integer.MIN_VALUE+10);
+		assertEquals(11, iv4.size());
+	}
+
 }
diff --git a/tlatools/test/util/SimpleFilenameToStreamTest.java b/tlatools/test/util/SimpleFilenameToStreamTest.java
index 815e8db3429dd7f35de3e25e7bb9b63971bea5b1..18322e3bfaec3c95c7695d3a874f6c185c516d83 100644
--- a/tlatools/test/util/SimpleFilenameToStreamTest.java
+++ b/tlatools/test/util/SimpleFilenameToStreamTest.java
@@ -20,4 +20,22 @@ public class SimpleFilenameToStreamTest {
 		assertNotNull(file);
 		assertTrue(file.getAbsolutePath() + " does not exist!", file.exists());
 	}
+	
+	/**
+	 * Test whether the fix for #424 still works
+	 */
+	@Test
+	public void testWindowsTLAFileCreation() {
+		if (System.getProperty("os.name").toLowerCase().indexOf("win") > -1) {
+			final String driveLetter = "X:";
+			final String parentDirectory = driveLetter + "\\Develop\\myspecs\\DecentSpec\\";
+			final String child = parentDirectory + "Fromage.tla";
+			final FilenameToStream.TLAFile file = new FilenameToStream.TLAFile(parentDirectory, child, null);
+			final int driveLetterCount = file.getAbsolutePath().split(driveLetter).length - 1;
+			
+			assertTrue("There should be 1 drive letter in the child's absolute path, but there are " + driveLetterCount,
+					   (1 == driveLetterCount));
+		}
+	}
+	
 }
diff --git a/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/util/StringHelperTest.java b/tlatools/test/util/StringHelperTest.java
similarity index 99%
rename from org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/util/StringHelperTest.java
rename to tlatools/test/util/StringHelperTest.java
index a1764aaa4ede1d6791ec528d07cef6b102db3a81..f5dc5ff71dc2ab365d573fa674f78b30cb44c135 100644
--- a/org.lamport.tla.toolbox.test/src/org/lamport/tla/toolbox/util/StringHelperTest.java
+++ b/tlatools/test/util/StringHelperTest.java
@@ -24,11 +24,12 @@
  *   Markus Alexander Kuppe - initial API and implementation
  ******************************************************************************/
 
-package org.lamport.tla.toolbox.util;
+package util;
 
 import static org.junit.Assert.assertArrayEquals;
 
 import junit.framework.TestCase;
+import util.StringHelper;
 
 public class StringHelperTest extends TestCase {