Repository: hed-standard/hed-python (language: python)

Issue:
Web work



Discussion / hints:

Fix patch:
diff --git a/hedweb/hed/web/constants/blueprint_constants.py b/hedweb/hed/web/constants/blueprint_constants.py
deleted file mode 100644
index 2e0f69355..000000000
--- a/hedweb/hed/web/constants/blueprint_constants.py
+++ /dev/null
@@ -1,1 +0,0 @@
-ROUTE_BLUEPRINT = 'route_blueprint'
diff --git a/hedweb/hed/web/constants/file_constants.py b/hedweb/hed/web/constants/file_constants.py
index 2b3930143..9b565a556 100644
--- a/hedweb/hed/web/constants/file_constants.py
+++ b/hedweb/hed/web/constants/file_constants.py
@@ -3,4 +3,4 @@
 DICTIONARY_FILE_EXTENSIONS = ['.json']
 SCHEMA_WIKI_EXTENSION = '.mediawiki'
 SCHEMA_XML_EXTENSION = '.xml'
-SCHEMA_EXTENSIONS = [SCHEMA_XML_EXTENSION, SCHEMA_WIKI_EXTENSION]
\ No newline at end of file
+SCHEMA_EXTENSIONS = [SCHEMA_XML_EXTENSION, SCHEMA_WIKI_EXTENSION]
diff --git a/hedweb/hed/web/constants/route_constants.py b/hedweb/hed/web/constants/route_constants.py
index 5883c945f..9e3ad3279 100644
--- a/hedweb/hed/web/constants/route_constants.py
+++ b/hedweb/hed/web/constants/route_constants.py
@@ -1,3 +1,5 @@
+ROUTE_BLUEPRINT = 'route_blueprint'
+
 ADDITIONAL_EXAMPLES_ROUTE = '/additional-examples'
 COMMON_ERRORS_ROUTE = '/common-errors'
 DELETE_FILE_ROUTE = '/delete/<filename>'
diff --git a/hedweb/hed/web/dictionary.py b/hedweb/hed/web/dictionary.py
index 57caece50..ce3c4eac2 100644
--- a/hedweb/hed/web/dictionary.py
+++ b/hedweb/hed/web/dictionary.py
@@ -1,17 +1,14 @@
-import json
-import traceback
 from urllib.error import URLError, HTTPError
 from flask import current_app
 
-from hed.util.file_util import get_file_extension, delete_file_if_it_exists, write_strings_to_file
-from hed.validator.hed_validator import HedValidator
+from hed.schema import HedSchema, load_schema
+from hed.util.error_reporter import get_printable_issue_string
+from hed.util.file_util import delete_file_if_it_exists
 from hed.util.column_def_group import ColumnDefGroup
-from hed.util.hed_schema import HedSchema
-
 from hed.web.constants import common_constants, error_constants, file_constants
 from hed.web.web_utils import generate_filename, generate_download_file_response, \
-    handle_http_error, get_hed_path_from_pull_down, get_printable_issue_string, \
-    get_uploaded_file_path_from_form, save_file_to_upload_folder, save_text_to_upload_folder, get_optional_form_field
+    handle_http_error, get_hed_path_from_pull_down, \
+    get_uploaded_file_path_from_form, save_text_to_upload_folder, get_optional_form_field
 
 app_config = current_app.config
 
@@ -45,52 +42,6 @@ def generate_arguments_from_dictionary_form(request):
     return input_arguments
 
 
-def report_eeg_events_validation_status(request):
-    """Reports validation status of hed strings associated with EEG events
-       received from EEGLAB plugin HEDTools
-
-    Parameters
-    ----------
-    request: Request object
-        A Request object containing user data submitted by HEDTools.
-        Keys include "hed_strings", "check_for_warnings", and "hed_xml_file"
-
-    Returns
-    -------
-    string
-        A serialized JSON string containing information related to the hed strings validation result.
-        If the validation fails then a 500 error message is returned.
-    """
-    validation_status = {}
-
-    # Parse uploaded data
-    form_data = request.form
-    check_for_warnings = form_data["check_for_warnings"] == '1' if "check_for_warnings" in form_data else False
-    # if hed_xml_file was submitted, it's accessed by request.files, otherwise empty
-    if "hed-xml-file" in request.files and get_file_extension(request.files["hed-xml-file"].filename) == "xml":
-        hed_xml_file = save_file_to_upload_folder(request.files["hed-xml-file"])
-    else:
-        hed_xml_file = ''
-
-    try:
-        # parse hed_strings from json
-        hed_strings = json.loads(form_data["hed-strings"])
-        # hed_strings is a list of HED strings associated with events in EEG.event (order preserved)
-        hed_input_reader = HedValidator(hed_strings, check_for_warnings=check_for_warnings, hed_xml_file=hed_xml_file)
-        # issues is a list of lists. Element list is empty if no error,
-        # else is a list of dictionaries, each dictionary contains an error-message key-value pair
-        issues = hed_input_reader.get_validation_issues()
-
-        # Prepare response
-        validation_status["issues"] = issues
-    except:
-        validation_status[error_constants.ERROR_KEY] = traceback.format_exc()
-    finally:
-        delete_file_if_it_exists(hed_xml_file)
-
-    return validation_status
-
-
 def report_dictionary_validation_status(request):
     """Reports the spreadsheet validation status.
 
@@ -108,7 +59,7 @@ def report_dictionary_validation_status(request):
     input_arguments = []
     try:
         input_arguments = generate_arguments_from_dictionary_form(request)
-        return validate_dictionary(input_arguments, hed_schema=None)
+        return validate_dictionary(input_arguments)
     except HTTPError:
         return error_constants.NO_URL_CONNECTION_ERROR
     except URLError:
@@ -117,11 +68,10 @@ def report_dictionary_validation_status(request):
         return "Unexpected processing error: " + str(e)
     finally:
         delete_file_if_it_exists(input_arguments.get(common_constants.JSON_PATH, ''))
-    return ""
 
 
 def validate_dictionary(input_arguments, hed_schema=None, return_response=True):
-    """Validates the dictionary and returns a
+    """Validates the dictionary and returns a response or a printable string depending on return_response value
 
     Parameters
     ----------
@@ -140,11 +90,11 @@ def validate_dictionary(input_arguments, hed_schema=None, return_response=True):
 
     json_dictionary = ColumnDefGroup(input_arguments.get(common_constants.JSON_PATH, ''))
     if not hed_schema:
-        hed_schema = HedSchema(input_arguments.get(common_constants.HED_XML_FILE, ''))
+        hed_schema = load_schema(input_arguments.get(common_constants.HED_XML_FILE, ''))
     issues = json_dictionary.validate_entries(hed_schema)
     if issues:
         display_name = input_arguments.get(common_constants.JSON_FILE, '')
-        issue_str = get_printable_issue_string(issues, display_name, 'HED validation errors')
+        issue_str = get_printable_issue_string(issues, f"HED validation errors for {display_name}")
         if not return_response:
             return issue_str
         file_name = generate_filename(display_name, suffix='validation_errors', extension='.txt')
diff --git a/hedweb/hed/web/events.py b/hedweb/hed/web/events.py
index a4c07d57f..a89ee42c7 100644
--- a/hedweb/hed/web/events.py
+++ b/hedweb/hed/web/events.py
@@ -4,7 +4,7 @@
 
 from hed.util.file_util import delete_file_if_it_exists
 from hed.validator.hed_validator import HedValidator
-from hed.util.hed_schema import HedSchema
+from hed.schema import hed_schema_file
 
 from hed.web.constants import common_constants, error_constants, file_constants
 from hed.web.dictionary import validate_dictionary
@@ -72,7 +72,7 @@ def report_events_validation_status(request):
     input_arguments = []
     try:
         input_arguments = generate_input_from_events_form(request)
-        hed_schema = HedSchema(input_arguments.get(common_constants.HED_XML_FILE, ''))
+        hed_schema = hed_schema_file.load_schema(input_arguments.get(common_constants.HED_XML_FILE, ''))
         download_response = validate_dictionary(input_arguments, hed_schema=hed_schema)
         if download_response:
             return download_response
diff --git a/hedweb/hed/web/routes.py b/hedweb/hed/web/routes.py
index 9ca98cc6c..3c310b783 100644
--- a/hedweb/hed/web/routes.py
+++ b/hedweb/hed/web/routes.py
@@ -4,15 +4,15 @@
 import traceback
 
 from hed.util import hed_cache
-
-from hed.web import events, spreadsheet, schema, services, utils
-from hed.web.constants import blueprint_constants, common_constants, error_constants, page_constants, route_constants
-from hed.web.web_utils import delete_file_if_it_exists, find_hed_version_in_uploaded_file, save_file_to_upload_folder, \
+from hed.schema import hed_schema_file
+from hed.web import events, spreadsheet, schema, services, spreadsheet_utils
+from hed.web.constants import common_constants, error_constants, page_constants, route_constants
+from hed.web.web_utils import delete_file_if_it_exists, save_file_to_upload_folder, \
     generate_download_file_response, handle_http_error
 from hed.web.dictionary import report_dictionary_validation_status
 
 app_config = current_app.config
-route_blueprint = Blueprint(blueprint_constants.ROUTE_BLUEPRINT, __name__)
+route_blueprint = Blueprint(route_constants.ROUTE_BLUEPRINT, __name__)
 
 
 @route_blueprint.route(route_constants.DELETE_FILE_ROUTE, strict_slashes=False, methods=['GET'])
@@ -59,28 +59,18 @@ def download_file_in_upload_directory(filename, header=None):
 
 @route_blueprint.route(route_constants.DICTIONARY_VALIDATION_SUBMIT_ROUTE, strict_slashes=False, methods=['POST'])
 def get_dictionary_validation_results():
-    """Validate the JSON dictionary in the form after submission and return an attachment other containing the output.
+    """Validate the JSON dictionary in the form after submission and return an attachment containing the output.
 
     Parameters
     ----------
 
     Returns
     -------
-        string
-        A serialized JSON string containing information related to the worksheet columns. If the validation fails then a
-        500 error message is returned.
+        download file
+        A text file with the validation errors.
     """
     validation_response = report_dictionary_validation_status(request)
     return validation_response
-    # validation_response = dictionary.report_dictionary_validation_status(request)
-    # # Success
-    # if isinstance(validation_response, Response):
-    #     return validation_response
-    # if isinstance(validation_response, str):
-    #     if validation_response:
-    #         return handle_http_error(error_constants.INTERNAL_SERVER_ERROR, validation_response, as_text=True)
-    #     else:
-    #         return ""
 
 
 @route_blueprint.route(route_constants.EVENTS_VALIDATION_SUBMIT_ROUTE, strict_slashes=False, methods=['POST'])
@@ -141,9 +131,13 @@ def get_hed_version():
         A serialized JSON string containing information related to the spreadsheet columns.
 
     """
-    hed_info = find_hed_version_in_uploaded_file(request)
-    if error_constants.ERROR_KEY in hed_info:
-        return handle_http_error(error_constants.INTERNAL_SERVER_ERROR, hed_info[error_constants.ERROR_KEY])
+    hed_info = {}
+    try:
+        if common_constants.HED_XML_FILE in request.files:
+            hed_file_path = save_file_to_upload_folder(request.files[common_constants.HED_XML_FILE])
+            hed_info[common_constants.HED_VERSION] = hed_schema_file.get_hed_xml_version(hed_file_path)
+    except:
+        return handle_http_error(error_constants.INTERNAL_SERVER_ERROR, traceback.format_exc())
     return json.dumps(hed_info)
 
 
@@ -238,7 +232,7 @@ def get_spreadsheet_columns_info():
         A serialized JSON string containing information related to the spreadsheet columns.
 
     """
-    spreadsheet_columns_info = utils.find_spreadsheet_columns_info(request)
+    spreadsheet_columns_info = spreadsheet_utils.find_spreadsheet_columns_info(request)
     if error_constants.ERROR_KEY in spreadsheet_columns_info:
         return handle_http_error(error_constants.INTERNAL_SERVER_ERROR,
                                  spreadsheet_columns_info[error_constants.ERROR_KEY])
@@ -293,7 +287,7 @@ def get_worksheets_info():
             workbook_file = request.files[common_constants.SPREADSHEET_FILE]
             workbook_file_path = save_file_to_upload_folder(workbook_file)
             if workbook_file_path:
-                worksheets_info = utils.populate_worksheets_info_dictionary(worksheets_info, workbook_file_path)
+                worksheets_info = spreadsheet_utils.populate_worksheets_info_dictionary(worksheets_info, workbook_file_path)
     except:
         worksheets_info[error_constants.ERROR_KEY] = traceback.format_exc()
     finally:
diff --git a/hedweb/hed/web/schema.py b/hedweb/hed/web/schema.py
index 4930361e6..16f27c6bd 100644
--- a/hedweb/hed/web/schema.py
+++ b/hedweb/hed/web/schema.py
@@ -4,12 +4,13 @@
 from urllib.parse import urlparse
 from flask import current_app, Response
 
-from hed.schema import xml2wiki, wiki2xml, schema_validator
+from hed.schema.hed_schema_file import load_schema, convert_schema_to_format
+from hed.util.error_reporter import get_printable_issue_string
 from hed.util.file_util import delete_file_if_it_exists, url_to_file, get_file_extension
 from hed.util.exceptions import HedFileError
 
-from hed.web.web_utils import file_extension_is_valid, form_has_file, form_has_option, form_has_url, \
-    generate_download_file_response, generate_filename, get_printable_issue_string, \
+from hed.web.web_utils import form_has_file, form_has_option, form_has_url, \
+    generate_download_file_response, generate_filename,  \
     handle_http_error, save_file_to_upload_folder, save_text_to_upload_folder
 
 from hed.web.constants import common_constants, error_constants, file_constants
@@ -48,31 +49,6 @@ def generate_input_from_schema_form(request):
     return arguments
 
 
-def get_schema_conversion(schema_local_path):
-    """Runs the appropriate xml<>mediawiki converter depending on input filetype.
-
-    returns: A dictionary with converter.constants filled in.
-    """
-
-    try:
-        if not schema_local_path:
-            raise ValueError(f"Invalid input schema path")
-        input_extension = get_file_extension(schema_local_path)
-
-        if input_extension == file_constants.SCHEMA_XML_EXTENSION:
-            conversion_function = xml2wiki.convert_hed_xml_2_wiki
-        elif input_extension == file_constants.SCHEMA_WIKI_EXTENSION:
-            conversion_function = wiki2xml.convert_hed_wiki_2_xml
-        else:
-            raise ValueError(f"Invalid extension type: {input_extension}")
-        converted_schema_path, errors = conversion_function(None, schema_local_path, check_for_issues=False)
-    except ValueError as error:
-        errors = format(error)
-        converted_schema_path = ''
-
-    return converted_schema_path, errors
-
-
 def run_schema_compliance_check(request):
     """Run tag comparison(map_schema from converter)
 
@@ -85,20 +61,12 @@ def run_schema_compliance_check(request):
     try:
         input_arguments = generate_input_from_schema_form(request)
         hed_file_path = input_arguments.get(common_constants.SCHEMA_PATH, '')
-        if hed_file_path and hed_file_path.endswith(".mediawiki"):
-            new_file_path, errors = get_schema_conversion(hed_file_path)
-            if new_file_path:
-                delete_file_if_it_exists(hed_file_path)
-                hed_file_path = new_file_path
-
-        if not hed_file_path or not file_extension_is_valid(hed_file_path, [file_constants.SCHEMA_XML_EXTENSION]):
-            return f"Invalid file name {hed_file_path}"
-
-        issues = schema_validator.validate_schema(hed_file_path)
+        this_schema = load_schema(hed_file_path)
+        issues = this_schema.check_compliance()
         if issues:
             display_name = input_arguments.get(common_constants.SCHEMA_DISPLAY_NAME)
-            issue_str = get_printable_issue_string(issues, display_name, 'Schema HED 3G compliance errors for ')
-            file_name = generate_filename(display_name, suffix='schema_errors', extension='.txt')
+            issue_str = get_printable_issue_string(issues, f"Schema HED 3G compliance errors for {display_name}")
+            file_name = generate_filename(display_name, suffix='schema_3G_compliance_errors', extension='.txt')
             issue_file = save_text_to_upload_folder(issue_str, file_name)
             download_response = generate_download_file_response(issue_file, display_name=file_name, category='warning',
                                                                 msg='Schema is not HED 3G compliant')
@@ -125,14 +93,17 @@ def run_schema_conversion(request):
         Non empty string is an error
         Response is a download success.
     """
-    hed_file_path = ''
+    schema_file_path = ''
     try:
         input_arguments = generate_input_from_schema_form(request)
-        hed_file_path = input_arguments.get(common_constants.SCHEMA_PATH)
+        schema_file_path = input_arguments.get(common_constants.SCHEMA_PATH)
         display_name = input_arguments.get(common_constants.SCHEMA_DISPLAY_NAME)
-        schema_file, issues = get_schema_conversion(hed_file_path)
+        input_extension = get_file_extension(schema_file_path)
+        save_wiki = input_extension == file_constants.SCHEMA_XML_EXTENSION
+        schema_file, issues = convert_schema_to_format(local_hed_file=schema_file_path, check_for_issues=False,
+                                                       display_filename=display_name, save_as_mediawiki=save_wiki)
         if issues:
-            issue_str = get_printable_issue_string(issues, display_name, 'Schema conversion errors for ')
+            issue_str = get_printable_issue_string(issues, f"Schema conversion errors for {display_name}")
             file_name = generate_filename(display_name, suffix='conversion_errors', extension='.txt')
             issue_file = save_text_to_upload_folder(issue_str, file_name)
             download_response = \
@@ -158,4 +129,4 @@ def run_schema_conversion(request):
     except:
         return traceback.format_exc()
     finally:
-        delete_file_if_it_exists(hed_file_path)
+        delete_file_if_it_exists(schema_file_path)
diff --git a/hedweb/hed/web/services.py b/hedweb/hed/web/services.py
index 4641918bf..5dd92f016 100644
--- a/hedweb/hed/web/services.py
+++ b/hedweb/hed/web/services.py
@@ -1,51 +1,19 @@
+import os
 import json
 import traceback
-from urllib.error import URLError, HTTPError
 from flask import current_app
 
-from hed.util.file_util import get_file_extension, delete_file_if_it_exists
+from hed.schema import hed_schema_file
+from hed.util import hed_cache
+from hed.util.file_util import delete_file_if_it_exists
 from hed.validator.hed_validator import HedValidator
-from hed.util.hed_file_input import HedFileInput
+from hed.util.column_def_group import ColumnDefGroup
+from hed.util.error_types import ErrorContext
 
-from hed.web.constants import common_constants, error_constants, file_constants
-from hed.web.web_utils import convert_number_str_to_list, generate_filename, get_printable_issue_string, \
-    generate_download_file_response, get_hed_path_from_pull_down, get_uploaded_file_path_from_form, \
-    handle_http_error, save_file_to_upload_folder, save_text_to_upload_folder
-from hed.web import utils
 
 app_config = current_app.config
 
 
-def generate_arguments_from_form(request):
-    """Gets the input arguments from a request object associated with a service.
-
-    Parameters
-    ----------
-    request: Request object
-        A Request object containing user data from the validation form.
-
-    Returns
-    -------
-    dictionary
-        A dictionary containing input arguments for calling the underlying validation function.
-    """
-    hed_file_path, hed_display_name = get_hed_path_from_pull_down(request)
-    uploaded_file_name, original_file_name = \
-        get_uploaded_file_path_from_form(request, common_constants.SPREADSHEET_FILE,
-                                         file_constants.SPREADSHEET_FILE_EXTENSIONS)
-
-    input_arguments = { }
-    #     common_constants.HED_VERSION:  form_data = request.form,
-    #     common_constants.HED_DISPLAY_NAME: hed_display_name,
-    #
-    #
-    #     common_constants.CHECK_FOR_WARNINGS:
-    #         utils.get_optional_form_field(request, common_constants.CHECK_FOR_WARNINGS,
-    #                                       common_constants.BOOLEAN)
-    # }
-    return input_arguments
-
-
 def report_services_status(request):
     """
     Reports validation status of hed strings associated with EEG events received from EEGLAB plugin HEDTools
@@ -62,31 +30,108 @@ def report_services_status(request):
         A serialized JSON string containing information related to the hed strings validation result.
         If the validation fails then a 500 error message is returned.
     """
-    validation_status = {}
-
-    # Parse uploaded data
-    form_data = request.form
-    check_for_warnings = form_data["check_for_warnings"] == '1' if "check_for_warnings" in form_data else False
-    # if hed_xml_file was submitted, it's accessed by request.files, otherwise empty
-    if "hed-xml-file" in request.files and get_file_extension(request.files["hed-xml-file"].filename) == "xml":
-        hed_xml_file = save_file_to_upload_folder(request.files["hed-xml-file"])
-    else:
-        hed_xml_file = ''
-
+    response = {"result": "", "errors": "", "error_details": ""}
+    hed_xml_file = ''
     try:
-        # parse hed_strings from json
-        hed_strings = json.loads(form_data["hed-strings"])
-        # hed_strings is a list of HED strings associated with events in EEG.event (order preserved)
-        hed_input_reader = HedValidator(hed_strings, check_for_warnings=check_for_warnings, hed_xml_file=hed_xml_file)
-        # issues is a list of lists. Element list is empty if no error,
-        # else is a list of dictionaries, each dictionary contains an error-message key-value pair
-        issues = hed_input_reader.get_validation_issues()
-
-        # Prepare response
-        validation_status["issues"] = issues
+        form_data = request.data
+        form_string = form_data.decode()
+        param_dict = json.loads(form_string)
+        service = param_dict.get("service", "")
+        supported_services = get_services()
+        if not service:
+            response["errors"] = "Must specify a service"
+        elif service not in supported_services.keys():
+            response["errors"] = f"{service} not supported"
+        elif service == "get_services":
+            response["result"] = {"supported_services": supported_services}
+        elif service == "validate_json":
+            response["result"] = get_validate_dictionary(param_dict)
+        elif service == "validate_strings":
+            response["result"] = get_validate_strings(param_dict)
+        else:
+            response["errors"] = f"{service} not implemented"
     except:
-        validation_status[error_constants.ERROR_KEY] = traceback.format_exc()
+        response["error_details"] = traceback.format_exc()
+        response["errors"] = "An exception thrown during execution of service"
     finally:
         delete_file_if_it_exists(hed_xml_file)
 
-    return validation_status
+    return response
+
+
+def get_services():
+    dir_path = os.path.dirname(os.path.realpath(__file__))
+    the_path = os.path.join(dir_path, 'static/resources/services.json')
+    with open(the_path) as f:
+        service_info = json.load(f)
+    return service_info
+
+
+def get_validate_dictionary(params):
+    """
+    Reports validation status of hed strings
+
+    Parameters
+    ----------
+    params: dict
+         A Request object containing user data submitted by HEDTools.
+         Keys include "hed_strings", "check_for_warnings", and "hed_xml_file"
+
+    Returns
+    -------
+    dict
+         A serialized JSON string containing information related to the hed strings validation result.
+    """
+    hed = params.get("hed_version", "")
+    hed_file_path = hed_cache.get_path_from_hed_version(hed)
+    hed_schema = hed_schema_file.load_schema(hed_file_path)
+    json_text = params.get("json_dictionary", "")
+    json_dictionary = ColumnDefGroup(json_string=json_text)
+    issues = json_dictionary.validate_entries(hed_schema)
+    issue_list = []
+    for issue in issues:
+        code = issue.get('code', "")
+        message = issue.get('message', "")
+        column_name = issue.get(ErrorContext.SIDECAR_COLUMN_NAME, "")
+        if column_name:
+            column_name = column_name[0]
+        key_name = issue.get(ErrorContext.SIDECAR_KEY_NAME, "")
+        if key_name:
+            key_name = key_name[0]
+        hed_string = issue.get(ErrorContext.SIDECAR_HED_STRING, "")
+        if hed_string:
+            hed_string = hed_string[0]
+        issue_dict = {"code": code, "message": message, "column_name": column_name,
+                      "key_name": key_name, "hed_string": hed_string}
+        issue_list.append(issue_dict)
+    result = {'hed_version': hed, 'validation_errors': issue_list}
+    return result
+
+
+def get_validate_strings(params):
+    """
+    Reports validation status of hed strings
+
+    Parameters
+    ----------
+    params: dict
+         A Request object containing user data submitted by HEDTools.
+         Keys include "hed_strings", "check_for_warnings", and "hed_xml_file"
+
+    Returns
+    -------
+    list of dict
+         A serialized JSON string containing information related to the hed strings validation result.
+    """
+    hed = params.get("hed_version", "")
+    hed_file_path = hed_cache.get_path_from_hed_version(hed)
+    hed_strings = params.get("hed_strings", "")
+    hed_validator = HedValidator(hed_xml_file=hed_file_path)
+    validation_issues = {}
+    str_num = 1
+    for hed_string in hed_strings:
+        issue = hed_validator.validate_input(hed_string)
+        if issue:
+            validation_issues[f"String_{str_num}"] = issue
+        str_num += 1
+    return {'hed_version': hed, 'validation_errors': validation_issues}
diff --git a/hedweb/hed/web/spreadsheet.py b/hedweb/hed/web/spreadsheet.py
index 2f50f7173..f607cba50 100644
--- a/hedweb/hed/web/spreadsheet.py
+++ b/hedweb/hed/web/spreadsheet.py
@@ -1,16 +1,17 @@
 from urllib.error import URLError, HTTPError
 from flask import current_app
 
+from hed.util.error_reporter import get_printable_issue_string
 from hed.util.file_util import delete_file_if_it_exists
 from hed.validator.hed_validator import HedValidator
 from hed.util.hed_file_input import HedFileInput
 
 import hed.web.web_utils
 from hed.web.constants import common_constants, error_constants, file_constants
-from hed.web.web_utils import convert_number_str_to_list, generate_filename, get_printable_issue_string, \
+from hed.web.web_utils import convert_number_str_to_list, generate_filename, \
     generate_download_file_response, get_hed_path_from_pull_down, get_uploaded_file_path_from_form, \
     handle_http_error, save_text_to_upload_folder
-from hed.web import utils
+from hed.web import spreadsheet_utils
 
 app_config = current_app.config
 
@@ -33,21 +34,24 @@ def generate_input_from_validation_form(request):
         get_uploaded_file_path_from_form(request, common_constants.SPREADSHEET_FILE,
                                          file_constants.SPREADSHEET_FILE_EXTENSIONS)
 
-    validation_input_arguments = {
+    input_arguments = {
         common_constants.HED_XML_FILE: hed_file_path,
         common_constants.HED_DISPLAY_NAME: hed_display_name,
         common_constants.SPREADSHEET_PATH: uploaded_file_name,
         common_constants.SPREADSHEET_FILE: original_file_name,
         common_constants.TAG_COLUMNS: convert_number_str_to_list(request.form[common_constants.TAG_COLUMNS]),
-        common_constants.COLUMN_PREFIX_DICTIONARY: utils.get_specific_tag_columns_from_form(request),
-        common_constants.WORKSHEET_NAME: hed.web.web_utils.get_optional_form_field(request, common_constants.WORKSHEET_NAME,
+        common_constants.COLUMN_PREFIX_DICTIONARY: spreadsheet_utils.get_specific_tag_columns_from_form(request),
+        common_constants.WORKSHEET_NAME: hed.web.web_utils.get_optional_form_field(request,
+                                                                                   common_constants.WORKSHEET_NAME,
                                                                                    common_constants.STRING),
         common_constants.HAS_COLUMN_NAMES:
-            hed.web.web_utils.get_optional_form_field(request, common_constants.HAS_COLUMN_NAMES, common_constants.BOOLEAN),
+            hed.web.web_utils.get_optional_form_field(request, common_constants.HAS_COLUMN_NAMES,
+                                                      common_constants.BOOLEAN),
         common_constants.CHECK_FOR_WARNINGS:
-            hed.web.web_utils.get_optional_form_field(request, common_constants.CHECK_FOR_WARNINGS, common_constants.BOOLEAN)
+            hed.web.web_utils.get_optional_form_field(request, common_constants.CHECK_FOR_WARNINGS,
+                                                      common_constants.BOOLEAN)
     }
-    return validation_input_arguments
+    return input_arguments
 
 
 def report_spreadsheet_validation_status(request):
@@ -115,7 +119,7 @@ def validate_spreadsheet(input_arguments, hed_validator=None, return_response=Tr
         if worksheet_name:
             title_string = display_name + ' [worksheet ' + worksheet_name + ']'
             suffix = '_worksheet_' + worksheet_name + '_' + suffix
-        issue_str = get_printable_issue_string(issues, title_string, 'HED validation errors')
+        issue_str = get_printable_issue_string(issues, f"{title_string} HED validation errors")
         if not return_response:
             return issue_str
         file_name = generate_filename(display_name, suffix=suffix, extension='.txt')
diff --git a/hedweb/hed/web/utils.py b/hedweb/hed/web/spreadsheet_utils.py
similarity index 95%
rename from hedweb/hed/web/utils.py
rename to hedweb/hed/web/spreadsheet_utils.py
index 7470cef53..0248543ff 100644
--- a/hedweb/hed/web/utils.py
+++ b/hedweb/hed/web/spreadsheet_utils.py
@@ -1,10 +1,7 @@
 import xlrd
 import traceback
-
 from flask import current_app
-
 from hed.util.file_util import get_file_extension, delete_file_if_it_exists
-
 from hed.web.constants import common_constants, error_constants, spreadsheet_constants
 from hed.web.web_utils import save_file_to_upload_folder, find_all_str_indices_in_list
 
@@ -31,7 +28,7 @@ def find_spreadsheet_columns_info(request):
         if common_constants.SPREADSHEET_FILE in request.files:
             spreadsheet_file = request.files[common_constants.SPREADSHEET_FILE]
             spreadsheet_file_path = save_file_to_upload_folder(spreadsheet_file)
-            if spreadsheet_file_path and worksheet_name_present_in_form(request):
+            if spreadsheet_file_path and common_constants.WORKSHEET_NAME in request.form:
                 worksheet_name = request.form[common_constants.WORKSHEET_NAME]
                 spreadsheet_columns_info = populate_spreadsheet_columns_info_dictionary(spreadsheet_columns_info,
                                                                                         spreadsheet_file_path,
@@ -271,20 +268,3 @@ def populate_worksheets_info_dictionary(worksheets_info, spreadsheet_file_path):
     worksheets_info[common_constants.REQUIRED_TAG_COLUMN_INDICES] = \
         get_spreadsheet_specific_tag_column_indices(worksheets_info[common_constants.COLUMN_NAMES])
     return worksheets_info
-
-
-def worksheet_name_present_in_form(request):
-    """Checks to see if a worksheet name is present in a request object from form.
-
-    Parameters
-    ----------
-    request: Request object
-        A Request object containing user data from a form.
-
-    Returns
-    -------
-    boolean
-        True if a worksheet name is present in a request object from the form.
-
-    """
-    return common_constants.WORKSHEET_NAME in request.form
diff --git a/hedweb/hed/web/static/resources/services.json b/hedweb/hed/web/static/resources/services.json
new file mode 100644
index 000000000..df0d31c60
--- /dev/null
+++ b/hedweb/hed/web/static/resources/services.json
@@ -0,0 +1,46 @@
+{
+  "get_services": {
+    "Name": "get_services",
+    "Description": "Return a list of hed services commands with descriptions",
+    "Parameters" : [],
+    "Returns" : [
+      {"Name": "supported_services",
+       "Description": "A list of available services with description, parameters and return values."}]
+  },
+  "validate_strings": {
+     "Name": "validate_strings",
+     "Description": "Validate a list of HED strings and return errors",
+     "Parameters": [
+         {"Name": "hed_version",
+          "Description": "Version of HED to be used to validate",
+          "Default": "Latest"},
+         {"Name": "hed_strings",
+          "Description": "List of hed strings to be validated",
+          "Default": []}
+       ],
+     "Returns": [
+         {"Name": "hed_version",
+          "Description": "Version of HED used to validate"},
+         {"Name": "validation_errors",
+          "Description": "List of validation error dictionaries"}
+     ]
+  },
+    "validate_json": {
+     "Name": "validate_json",
+     "Description": "Validate a JSON string in form of BIDS sidecar and return errors",
+     "Parameters": [
+         {"Name": "hed_version",
+          "Description": "Version of HED to be used to validate",
+          "Default": "Latest"},
+         {"Name": "json_dictionary",
+          "Description": "JSON sidecar as a string",
+          "Default": []}
+       ],
+     "Returns": [
+         {"Name": "hed_version",
+          "Description": "Version of HED used to validate"},
+         {"Name": "validation_errors",
+          "Description": "List of validation error dictionaries"}
+     ]
+  }
+}
\ No newline at end of file
diff --git a/hedweb/hed/web/templates/hed-services.html b/hedweb/hed/web/templates/hed-services.html
index f85acafb0..ba80d4823 100644
--- a/hedweb/hed/web/templates/hed-services.html
+++ b/hedweb/hed/web/templates/hed-services.html
@@ -5,6 +5,7 @@
     <title>HED services</title>
 </head>
 <body>
+<h1>Hi</h1>
 <form id="hed-services-form" method="POST" enctype="multipart/form-data">
     <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
 </form>
diff --git a/hedweb/hed/web/web_utils.py b/hedweb/hed/web/web_utils.py
index 0990c30d1..707966461 100644
--- a/hedweb/hed/web/web_utils.py
+++ b/hedweb/hed/web/web_utils.py
@@ -7,10 +7,8 @@
 from flask import current_app, jsonify, Response
 
 from hed.util import hed_cache
-from hed.util.error_reporter import ErrorHandler
 from hed.util.file_util import get_file_extension, delete_file_if_it_exists
-from hed.util.hed_schema import HedSchema
-from hed.web.constants import common_constants, error_constants
+from hed.web.constants import common_constants
 
 app_config = current_app.config
 
@@ -76,32 +74,6 @@ def find_all_str_indices_in_list(list_of_str, str_value):
             value.lower().replace(' ', '') == str_value.lower().replace(' ', '')]
 
 
-def find_hed_version_in_uploaded_file(request, key_name=common_constants.HED_XML_FILE):
-    """Finds the version number in an HED XML other.
-
-    Parameters
-    ----------
-    request: Request object
-        A Request object containing user data
-    key_name: str
-        Name of the key for the HED XML file in the request
-
-    Returns
-    -------
-    string
-        A serialized JSON string containing the version number information.
-
-    """
-    hed_info = {}
-    try:
-        if key_name in request.files:
-            hed_file_path = save_file_to_upload_folder(request.files[key_name])
-            hed_info[common_constants.HED_VERSION] = HedSchema.get_hed_xml_version(hed_file_path)
-    except:
-        hed_info[error_constants.ERROR_KEY] = traceback.format_exc()
-    return hed_info
-
-
 def form_has_file(request, file_field, valid_extensions):
     """Checks to see if a file name with valid extension is present in the request object.
 
@@ -195,7 +167,6 @@ def generate_download_file_response(download_file, display_name=None, header=Non
     """
     if not display_name:
         display_name = download_file
-    print("In generate:", display_name)
     try:
         if not download_file:
             return f"No download file given"
@@ -280,36 +251,6 @@ def get_hed_path_from_pull_down(request):
     return hed_file_path, hed_display_name
 
 
-def get_printable_issue_string(issues, display_name=None, title_string=''):
-    """Returns a string suitable for text blob download
-
-     Parameters
-     ----------
-     issues: list
-         List of the issues to be printed.
-     title_string: str
-         key name in the files dictionary of the Request object
-     display_name: list of str
-         List of valid extensions
-
-     Returns
-     -------
-     tuple
-         A tuple containing the other paths. The two other paths are for the spreadsheet and a optional HED XML other.
-     """
-    if not issues:
-        return ''
-    if title_string:
-        title = title_string
-    else:
-        title = ''
-    if display_name:
-        title = display_name + ' ' + title_string + '\n'
-    if not title:
-        title = None
-    return ErrorHandler.get_printable_issue_string(issues, title, skip_filename=True)
-
-
 def get_optional_form_field(request, form_field_name, type=''):
     """Gets the specified optional form field if present.
 
@@ -417,31 +358,6 @@ def save_file_to_upload_folder(file_object, delete_on_close=False):
     return file_path
 
 
-def save_issues_to_upload_folder(issues, filename):
-    """Saves the issues found the upload folder as filename.
-
-    Parameters
-    ----------
-    issues: string
-        A string containing the validation issues.
-    filename: str
-        File name of the issue folder
-
-    Returns
-    -------
-    string
-        The name of the validation output other.
-
-    """
-
-    issues_file_path = os.path.join(current_app.config['UPLOAD_FOLDER'], filename)
-    with open(issues_file_path, 'w', encoding='utf-8') as issues_file:
-        for val_issue in issues:
-            issues_file.write(val_issue['message'] + "\n")
-    issues_file.close()
-    return issues_file_path
-
-
 def save_text_to_upload_folder(text, filename):
     """Saves a string in the upload folder as filename.
 


Test patch:
diff --git a/hedweb/tests/data/HED3.mediawiki b/hedweb/tests/data/HED3.mediawiki
new file mode 100644
index 000000000..1703062bb
--- /dev/null
+++ b/hedweb/tests/data/HED3.mediawiki
@@ -0,0 +1,1166 @@
+HED version: 8.0.0-alpha.1
+
+!# start hed 
+
+'''Event''' 
+* Sensory-event <nowiki>{suggestedTag=Task-property/Task-role}[Something perceivable by the participant. An event meant to be an experimental stimulus should also be tagged with Task-property/Task-role/Experiment-stimulus.]</nowiki>
+* Agent-action <nowiki>[Any action engaged in by an agent. An event that is a participant response to an experiment stimulus should also be tagged with Agent-property/Agent-task-role/Participant-response.]</nowiki>
+* Data-feature <nowiki>[An event derived from the data itself or possibly inserted in a post-hoc fashion. Examples are markers for interictal spikes or alpha bursts.]</nowiki>
+* Experiment-control <nowiki>{extensionAllowed} [An event pertaining to the control of the experiment during its operation.]</nowiki>
+* Experiment-procedure <nowiki>[An event indicating an experimental procedure as in doing a saliva swab on a participant during the experiment or administering a survey.]</nowiki>  
+* Experiment-structure <nowiki>{extensionAllowed} [An event specifying the structure of the experiment.]</nowiki>
+
+
+'''Agent''' <nowiki>[Something in the experiment that takes an active role or produces an effect. The role or effect may be implicit. Being alive or performing an activity such as a computation may qualify something to be an agent. An agent may also be soething that simulates something else.]</nowiki>
+* Animal-agent <nowiki>[An animal that is present.]</nowiki>
+* Avatar-agent
+* Computational-agent
+* Controller-agent <nowiki>[An outside controller such as the experimental control software.]</nowiki> 
+* Human-agent 
+* Robotic-agent 
+
+'''Action''' <nowiki>{extensionAllowed} [May or may not be in response to a previous Sensory presentation event.]</nowiki> 
+* Move
+** Breathe
+*** Inhale <nowiki>[A deliberate in-breath in response to a task instruction or as part of a task. Group with Attribute/Cognitive modifier/Incidental if the inhalation is incidental to the task (Action/Move/Breathe/Inhale, Attribute/Cognitive modifier/Incidental).]</nowiki>
+*** Exhale <nowiki>[A deliberate out-breath in response to a task instruction or as part of a task. Group with Attribute/Cognitive modifier/Incidental: (Action/Move/Breathe/Exhale, Attribute/Cognitive modifier/Incidental).]</nowiki>
+*** Hold-breath
+** Move-full-body
+*** Bend
+*** Dance
+*** Fall-down <nowiki>[Involuntary fall to floor or ground]</nowiki>
+*** Flex
+*** Jerk <nowiki>[When some force applied to the participant causes them to involuntarily accommodate or react to it.]</nowiki>
+***	Recover-balance <nowiki>[A movement made in response to a stumble or unforeseen loss of balance]</nowiki>
+*** Stretch <nowiki>[Stretching the body or body part]</nowiki> 
+*** Shudder 
+*** Stumble <nowiki>[Temporary and involuntary loss of balance]</nowiki>
+*** Turn
+** Move-head
+*** Move-eyes
+**** Blink
+**** Close-eyes
+**** Fixate
+**** Inhibit-blinks
+**** Open-eyes 
+**** Saccade
+*** Move-mouth
+**** Burp 
+**** Clear-throat
+**** Cough 
+**** Gurgle
+**** Hiccup 
+**** Smile
+**** Sneeze 
+**** Sniffle
+**** Swallow
+**** Yawn 
+*** Nod
+*** Shake-head
+** Move-arm-hand
+*** Clap
+*** Drop <nowiki>[For example the participant drops a handheld ball]</nowiki>
+*** Grab
+*** Grasp <nowiki>[Grasp an object in one or both hands]</nowiki>
+*** Hold-down
+*** Lift <nowiki>[Often grouped with item being lifted.]</nowiki>
+*** Make-fist
+*** Point  <nowiki>[Should be grouped with Item/Agent/Human/Body part/Hand/Finger tag to specify which finger was used for the action.]</nowiki> 
+*** Press <nowiki>[Often grouped with body part doing action and item being pressed.]</nowiki>
+*** Push
+*** Reach <nowiki>[Requires a spatial goal such as reaching to touch a button or to grasp something. A body stretch is not a reach.]</nowiki> 
+*** Release <nowiki>[Often grouped with item being released.]</nowiki>
+*** Retract <nowiki>[Often grouped with body part doing action and item being retracted.]</nowiki>
+*** Scratch
+*** Snap-fingers
+*** Tap <nowiki>[Often grouped with body part doing action.]</nowiki>
+*** Touch <nowiki>[May follow a Reach event]</nowiki> 
+** Move-leg-foot
+*** Curl-toes
+*** Jog
+*** Jump
+*** Kick 
+*** Pedal
+*** Run
+*** Step
+**** Heel-strike 
+**** Toe-off
+*** Trot
+*** Walk
+
+* Communicate
+** Communicate-vocally
+*** Cry
+*** Groan
+*** Gulp  <nowiki>[Communicate anxiety. Use swallow if non-editorial.]</nowiki>
+***	Laugh
+*** Scream
+*** Sigh
+*** Speak <nowiki>[Communicate using spoken language.]</nowiki>
+** Gesture <nowiki>[Make a expressive communicative movement of hands/arms and, often, face]</nowiki>
+***	Index-up
+***	Pump-fist
+***	Spread-hand
+***	Shhh
+***	Shrug
+***	Thumb-up
+***	Wave
+** Communicate-musically
+*** Hum
+*** Sing
+*** Vocalize <nowiki>[Make a sustained vowel sound such as Ahhh.]</nowiki>
+*** Whistle
+* Perform <nowiki>[Carry out or accomplish an action or task or function.]</nowiki>
+** Collide
+** Halt <nowiki>[Stop action.]</nowiki>
+** Modify <nowiki>[Deliberately make a change in something.]</nowiki>
+** Operate <nowiki>[Control something else.]</nowiki>
+** Perceive
+*** Feel
+*** Listen
+*** Look
+*** Smell
+*** Taste
+** Play  <nowiki>[As a musical instrument or a game.]</nowiki>
+** Read
+** Rest 
+** Write
+* Think
+** Allow <nowiki>[Allow access to something such as allowing a car to pass]</nowiki> 
+** Attend-to
+** Count 
+** Deny <nowiki> [Deny access to something such as preventing someone to pass]</nowiki> 
+** Detect
+** Discriminate
+** Encode 
+** Evade 
+** Generate
+** Identify
+** Imagine
+** Predict
+** Respond
+** Recall
+** Repeat
+** Switch-attention
+** Track
+
+'''Item''' <nowiki>{extensionAllowed}</nowiki>
+* Language <nowiki>[An  system of communication that is receivable in a sensory presentation.]</nowiki>
+** Character <nowiki>[A mark, sign or symbol used as part of language.]</nowiki>
+** Glyph <nowiki>[A symbol or pictograph.]</nowiki>
+** Nonword <nowiki>[A group of letters or speech sounds that looks or sounds like a word but that is not accepted as such by native speakers.]</nowiki>
+** Phoneme <nowiki>[A sound or a group of different sounds perceived to have the same function by speakers of the language.]</nowiki>
+** Phrase <nowiki>[A small group of words standing together as a conceptual unit.]</nowiki>
+** Sentence <nowiki>[A set of words that is complete in itself.]</nowiki>
+** Syllable <nowiki>[A unit of pronunciation having one vowel sound.]</nowiki>
+** Textblock <nowiki>[A block of text.]</nowiki>
+** Word <nowiki>[A single distinct meaningful element of a language.]</nowiki>
+* Object <nowiki> {extensionAllowed} [Physical object perceptible via Visual, Auditory, Olfactory, and/or Tactile modalities.]</nowiki>
+** Geometric
+*** Pattern
+**** Dots
+**** Led-pattern
+*** 2D-shape
+**** Clockface
+**** Cross
+**** Ellipse
+***** Circle
+**** Rectangle
+***** Square
+**** Single-point
+**** Star
+**** Triangle
+*** 3D-shape
+**** Box
+***** Cube
+**** Cone
+**** Cylinder
+**** Ellipsoid
+***** Sphere
+**** Pyradmid
+** Man-made-object <nowiki>[A manmade object]</nowiki>
+*** Media
+**** Sound-clip
+**** Visualization <nowiki>[A visual representation of something else -- such as using a stick-figure to represent motion capture data.]</nowiki>
+***** Animation
+***** Art-installation
+***** Braille
+***** Cutout
+***** Image <nowiki>[A still 2-D representation.]</nowiki>
+****** Cartoon
+****** Drawing
+****** Icon
+****** Painting
+****** Photograph
+***** Movie
+***** Outline-visualization
+***** Point-light-visualization
+***** Sculpture
+***** Stick-figure-visualization
+*** Building <nowiki>[Whole building or building feature]</nowiki>
+**** Room
+**** Roof
+**** Entrance
+**** Attic
+**** Basement
+*** Clothing
+*** Device
+**** Computing-device
+**** Engine
+**** IO-device
+***** Input-device
+****** Button
+****** Joystick
+****** Keyboard
+******* Key
+******** <nowiki># {takesValue}[Value of key.]</nowiki>
+****** Keypad 
+******* <nowiki># {takesValue}[Value of keypad key.]</nowiki>
+****** Microphone
+****** Mouse
+******* Mouse-button
+******* Scroll-wheel
+****** Touch-screen
+***** Network-device
+***** Output-device
+****** Display-device
+******* Head-mounted-display
+******* LED-display
+******* Screen
+******** Screen-window
+****** Auditory-device
+******* Headphones
+******* Screen-speaker
+******* Loudspeaker
+***** Recording-device
+****** EEG-recording
+****** File-recording
+****** MEG-recording
+****** Motion-capture
+****** Tape-recording
+**** Machine
+***** Noisemaker
+**** Measurement-device
+***** Clock
+****** Clock-face
+**** Robot
+**** Tool
+***	Document <nowiki>[A physical, written document]</nowiki>
+**** Manuscript
+**** Letter
+**** Note
+**** Book
+**** Notebook
+*** Furnishing <nowiki>[Furniture and appliances and other movable accessories including curtains and rugs]</nowiki>
+*** Navigational-object
+**** Path
+**** Road
+***** Lane
+**** Runway
+**** Sign
+*** Vehicle
+**** Aircraft 
+**** Bicycle
+**** Boat 
+**** Car
+**** Cart
+**** Tractor
+**** Train 
+**** Truck 
+** Natural-object <nowiki>[An object occuring naturally in contrast to a man-made object.]</nowiki>
+
+
+*** Mineral <nowiki>[An inorganic substance]</nowiki>
+*** Natural-feature <nowiki>[Some terrain occuring in the outdoors.]</nowiki>
+**** Field
+**** Hill
+**** Mountain
+**** River
+**** Waterfall
+** Food <nowiki>[Something that is usually solid and can be consumed by an organism.]</nowiki>
+** Drink <nowiki>[Something that is liquid and can be consumed by an organism.]</nowiki>
+
+
+* Organism <nowiki>[Something living or part of something living.]</nowiki>
+** Animal <nowiki>[Any multicellular or eukaryotic organism.]</nowiki>
+*** Human
+** Plant
+** Body-part
+*** Head
+**** Hair
+**** Ear
+**** Face
+***** Cheek
+***** Chin
+***** Eye
+***** Eyebrow
+***** Forehead
+***** Lip
+***** Nose
+***** Mouth
+***** Teeth
+*** Arm
+**** Elbow
+**** Hand
+***** Finger
+****** Index-finger
+****** Little-finger
+****** Middle-finger
+****** Ring-finger
+****** Thumb
+**** Wrist
+*** Leg
+**** Ankle
+**** Foot
+***** Toe
+**** Knee
+*** Torso
+**** Upper-torso
+***** Chest
+**** Lower-torso
+***** Hips
+**** Waist
+* Sound <nowiki>[Item/Sound can be used in a tag group to describe a sound created by an action Item/Sound, Action/Move/Move leg-foot/Walk, Agent/Human or an object or Item/Sound, Item/Object/Man-made/Vehicle/Car]</nowiki>
+** Environmental-sound<nowiki>[A background sound from the surrounding environment.]</nowiki>
+*** Crowd-sound <nowiki>[Multiple speech streams at once]</nowiki>
+*** Noise
+**** White-noise
+**** Colored-noise
+** Musical-sound <nowiki>[Any tone or combination of tones with characteristics such as controlled pitch and timbre that can be controlled by an agent.]</nowiki>
+*** Tone
+*** Instrument-sound
+*** Vocalized-sound
+** Named-animal-sound
+*** Bark
+*** Bleat
+*** Crow
+*** Chirp
+*** Growl
+*** Meow
+*** Moo
+*** Purr
+*** Roar
+
+** Named-object-sound
+*** Alarm
+*** Buzz
+*** Ka-ching <nowiki>[Cash register sound]</nowiki>
+*** Click
+*** Ding
+*** Horn
+*** Siren
+
+'''Agent-property''' 
+* Cognitive-state <nowiki>{extensionAllowed, requireChild}</nowiki>
+** Alert
+** Anesthetized 
+** Asleep
+** Attentive
+** Awake 
+** Brain-dead 
+** Comatose 
+** Drowsy 
+** Intoxicated <nowiki>[Indicates a state in which participant has consumed alcohol or drugs or other substances that may alter physical or mental state.]</nowiki> 
+** Locked-in 
+** Passive <nowiki>[Observing but not allowed to make any behavioral outputs. The resting state is not considered passive.</nowiki>
+** Resting
+** Vegetative 
+* Emotional-state <nowiki>{extensionAllowed, requireChild}</nowiki>
+** Angry 
+** Aroused
+** Awed
+** Compassionate
+** Content
+** Disgusted 
+** Emotionally-neutral
+** Empathetic
+** Excited 
+** Fearful
+** Feeling-stress
+** Frustrated
+** Grieving
+** Happy
+** Jealous 
+** Joyful 
+** Loving
+** Relieved
+** Sad 
+* Postural-state <nowiki>[Indicates the position of an agent. Usually this position or posture is static for some length of time rather than being part of a motion.]</nowiki> 
+** Crouching
+** Kneeling
+** On-treadmill
+** Prone
+** Sitting
+** Standing
+** Supported-by-chin-rest
+* Agent-trait <nowiki>{extensionAllowed}</nowiki> 
+** Age
+*** <nowiki># {takesValue}</nowiki>
+** Sex
+*** <nowiki># {takesValue}</nowiki> 
+** Handedness
+*** <nowiki># {takesValue}</nowiki> 
+* Social-role <nowiki> [The role of the agent not particular to the task.]</nowiki>
+** Brother
+** Child
+** Father
+** Mother
+** Sister
+* Agent-task-role <nowiki> [The role of the agent in the task.]</nowiki>
+** Experiment-controller
+** Experiment-participant
+** Experimenter
+** Follower
+** Friend
+** Leader
+** Stranger
+** Student
+** Teacher
+* Association 
+** Associated-with-non-agent 
+** Associated-with-other <nowiki>[Item such as a cup belonging to another person]</nowiki> 
+** Associated-with-self <nowiki>[Item such as a cup belonging to the participant]</nowiki> 
+
+'''Data-property'''
+* Computed-property<nowiki>{extensionAllowed}[Feature computed by tool. Should be grouped with a label of the form Toolname_propertyName]</nowiki>
+** Computed-prediction
+* Data-value
+** <nowiki># {takesValue}</nowiki>
+* Observational-property <nowiki>{extensionAllowed}[Manually identified data feature. Should be grouped with a label of the form AgentID_featureName]</nowiki>
+** Expert-annotation <nowiki>{extensionAllowed}</nowiki>
+** Instrument-measurement <nowiki>{extensionAllowed}</nowiki>
+* Physical-property'''
+** Electrical-property
+** Magnetic-property
+** Mechanical-property
+** Organic-property
+** Thermodynamic-property
+*** Energy
+*** Pressure
+*** Temperature
+**** <nowiki># {takesValue, isNumeric}</nowiki>
+
+* Quantitative <nowiki>{extensionAllowed}</nowiki>
+** Angle<nowiki>[Angle assumed clockwise from vertical unless grouped with axis.]</nowiki>
+*** <nowiki># {takesValue}</nowiki>  
+** Fraction <nowiki>[Fraction of items of a particular type.]</nowiki>
+*** <nowiki># {takesValue}</nowiki> 
+** Interval 
+*** <nowiki># {takesValue}</nowiki>  
+** Item-count 
+*** <nowiki># {takesValue}</nowiki>  
+** Percentage <nowiki>[Percentage of items of a particular type.]</nowiki> 
+*** <nowiki># {takesValue}</nowiki>  
+** Ratio 
+*** <nowiki># {takesValue}</nowiki>  
+** Repetition <nowiki>[When the same type of event such as a fixation on the exact same object happens multiple times and it might be necessary to distinguish the first look vs. others]</nowiki>
+*** <nowiki># {takesValue}</nowiki> 
+* Spatiotemporal <nowiki>{extensionAllowed}</nowiki>
+** Rate-of-change
+*** Acceleration
+**** <nowiki># {takesValue, isNumeric, unitClass=acceleration}</nowiki>  
+*** Jerk-rate <nowiki>[Rate at which the acceleration of an object changes with respect to time.]</nowiki> 
+**** <nowiki># {takesValue, isNumeric, unitClass=jerk}</nowiki>
+*** Sampling-rate <nowiki>{requireChild}[Number of measurements per unit time.]</nowiki> 
+**** <nowiki># {takesValue, unitClass=frequency}</nowiki> 
+*** Refresh-rate <nowiki>{requireChild}[Number of times per second a device displays an image. Also known as the frame rate.]</nowiki> 
+**** <nowiki># {takesValue, isNumeric}</nowiki>
+*** Temporal-rate <nowiki>[Number of occurrences in a unit of time.]</nowiki>
+**** <nowiki># {takesValue, isNumeric}</nowiki> 
+*** Velocity
+**** <nowiki># {takesValue, isNumeric, unitClass=speed}</nowiki> 
+** Resolution
+*** IO-resolution 
+**** Screen-resolution <nowiki>[Number of pixels in each dimension for a digital display device.]</nowiki> 
+***** <nowiki># {takesValue} </nowiki>
+**** Printer-resolution <nowiki>[Number of dots-per-inch for a printer.]</nowiki> 
+***** <nowiki># {takesValue} </nowiki>
+*** Spatial-resolution <nowiki>[Linear spacing of a spatial measurement.]</nowiki> 
+**** <nowiki># {takesValue}</nowiki>
+*** Spectral-resolution 
+**** <nowiki># {takesValue}</nowiki> 
+*** Temporal-resolution 
+**** <nowiki># {takesValue} </nowiki>  
+** Spatial
+*** Direction
+**** <nowiki># {takesValue, isNumeric}</nowiki>
+*** Distance <nowiki>[Distance from a specified position in a specified Direction or grouped with an item from which the distance is measured.]</nowiki> 
+**** <nowiki># {takesValue, isNumeric, unitClass=physicalLength}</nowiki> 
+*** Orientation 
+**** <nowiki># {takesValue, isNumeric}</nowiki> 
+*** Position <nowiki>[Coordinates with respect a specified frame of reference or the default Screen-frame if no frame is given.] </nowiki>
+**** X-position 
+***** <nowiki># {takesValue, isNumeric, unitClass=physicalLength}</nowiki> 
+**** Y-position 
+***** <nowiki># {takesValue, isNumeric, unitClass=physicalLength}</nowiki>  
+**** Z-position 
+***** <nowiki># {takesValue, isNumeric, unitClass=physicalLength}</nowiki>   
+*** Reference-frame <nowiki>[A frame of reference used to express spatial attributes.]</nowiki>
+**** Custom-frame <nowiki><nowiki>[A custom frame of reference which should be defined in terms of one of the default frames of reference or by a library.]</nowiki> 
+**** Room-frame
+**** Screen-frame <nowiki>[HED default frame of reference with origin at center of screen used to display experimental stimuli. Looking out of the screen has +X is horizontal to the right. +Y is up and +Z is out of the front of the screen.]</nowiki>
+**** Screen-facing-frame <nowiki>[HED default frame of reference with origin at the subject Nasion. +X is horizontal to the subject right. +Y is to the subject front and +Z is vertical upward.]</nowiki>
+**** World-frame
+*** Size
+**** Area 
+***** <nowiki># {takesValue, isNumeric, unitClass=area}</nowiki> 
+**** Length <nowiki>[A measurement of the size along the longest dimension.]</nowiki> 
+***** <nowiki># {takesValue, isNumeric, unitClass=physicalLength}</nowiki> 
+**** Width <nowiki>[A measurement along the shortest of two or three dimensions.]</nowiki>
+***** <nowiki># {takesValue, isNumeric, unitClass=physicalLength}</nowiki>
+**** Height <nowiki>[A measurement in a direction perpendicular to Length and Width in 3D. In 2D, it is perpendicular to both the Length and Height.]</nowiki>
+***** <nowiki># {takesValue, isNumeric, unitClass=physicalLength}</nowiki> 
+**** Volume 
+***** <nowiki># {takesValue, isNumeric, unitClass=volume}</nowiki>
+*** Surface-properties
+**** Rough
+**** Smooth
+
+** Temporal
+*** Delay <nowiki>[An indicator that the associated tag group represents something temporally offset from the current event. The delay value can be positive or negative and should always appear in a tag group indicating what is delayed.]</nowiki>
+**** <nowiki># {takesValue, isNumeric, unitClass=time}</nowiki> 
+*** Duration <nowiki>[Time extent of something.]</nowiki>
+**** <nowiki># {takesValue, isNumeric, unitClass=time}</nowiki> 
+*** Onset
+*** Offset
+*** Pause <nowiki>[Indicating something stopped such as a break or waiting for input.]</nowiki>    
+*** Temporal-value 
+**** <nowiki># {takesValue, isNumeric, unitClass=time}</nowiki> 
+*** Time-out
+*** Time-sync <nowiki>[Indicates a marker inserted into the recorded data to allow post hoc synchronization of concurrently recorded data streams.]</nowiki>
+  
+* Statistical-property <nowiki>{extensionAllowed}</nowiki>
+** Accuracy 
+** Data-mean 
+** Data-median 
+** Data-minimum 
+** Data-maximum 
+** Probability <nowiki> [Use to specify the level of certainty about the occurrence of the event.]</nowiki>  
+** Statistical-precision 
+** Statistical-recall 
+** Standard-deviation 
+** Uncertainty <nowiki> [Use to specify the level of error.]</nowiki>
+
+'''Task-property'''
+* Attentional-strategy
+** Bottom-up-attention
+** Covert-attention
+** Divided-attention
+** Focused-attention
+** Orienting-attention
+** Overt-attention
+** Selective-attention
+** Sustained-attention
+** Top-down-attention
+
+* Task-effect-evidence
+** Computational-evidence <nowiki>[Prediction made by computer program.]</nowiki> 
+**  External-evidence <nowiki>[External judgment assumed to be ground truth such as from an experiment control software or an annotator about participant actions such as answering a question, failing to answer in time, etc. Related to participant indication]</nowiki> 
+** Intended-effect <nowiki> [How the stimulus is expected to effect the participants based on the experimental design.]</nowiki> 
+** Behavioral-evidence <nowiki>  [This tag is placed in Agent-action events and grouped  with Task-related tags to specify the type of what that action means with respect to the task. For example if a button press indicates a target then Participant-indication would be grouped with Target.</nowiki>
+
+* Task-role <nowiki>[The purpose with respect to the task.]</nowiki>
+** Activity <nowiki> [Something that is part of the overall task or is necessary to the overall experiment but is not directly part of a stimulus-response cycle. Examples would be taking a survey or provided providing a silva sample.]</nowiki>
+** Background-subtask <nowiki>[A part of the task which should be performed in the background.]</nowiki>
+** Experimental-stimulus <nowiki>[Part of something designed to elicit a response in the experiment.]</nowiki>
+** Failure
+** Incidental <nowiki> [Usually associated with a sensory event intended to give instructions to the participant about the task or behavior.]</nowiki>
+** Instructional <nowiki> [Usually associated with a sensory event intended to give instructions to the participant about the task or behavior.]</nowiki>
+** Mishap <nowiki> [Unplanned disruption such as an equipment or experiment control abnormality or experimenter error.]</nowiki>
+** Participant-response <nowiki> [Something related to a participant actions in performing the task.]</nowiki>
+** Primary-subtask <nowiki>[A part of the task which should be the primary focus of the participant.]</nowiki>
+** Warning <nowiki>[Something that should warn the participant that the parameters of the task have been or are about to be exceeded such as a warning message about getting too close to the shoulder of the road in a driving task.]</nowiki> 
+
+* Task-response-type <nowiki> [How the participant response should be interpreted in terms of the task specification.]</nowiki>
+** Appropriate <nowiki>{relatedTag=Inappropriate}</nowiki>
+** Correction <nowiki>{relatedTag=Successful}</nowiki>
+** Erroneous
+** Imagined <nowiki>[This is used to identity something that only happened in the imagination of the participant as in imagined movements in motor imagery paradigms.]</nowiki>
+** Inappropriate <nowiki>{relatedTag=Appropriate}</nowiki>
+** Indeterminate <nowiki>{relatedTag=Missed,relatedTag=Near-miss}</nowiki>
+** Missed <nowiki>{relatedTag=Indeterminate,relatedTag=Near-miss}</nowiki>
+** Near-miss <nowiki>{relatedTag=Indeterminate,relatedTag=Miss}</nowiki>
+** Successful <nowiki>{relatedTag=Correction}</nowiki>
+
+* Task-stimulus-type <nowiki> [The stimulus purpose in the task.]</nowiki>
+** Cue
+** Distractor 
+** Expected <nowiki>[Of low information value as in frequent non-targets in an RSVP paradigm.]</nowiki>
+** Extraneous
+** Feedback 
+** Meaningful
+** Newly-learned
+** Non-informative
+** Non-target <nowiki>[Make sure to tag Expected if the Non-target is frequent] </nowiki> 
+** Not-meaningful 
+** Novel <nowiki>[Genuinely novel such as an event occurring once or so per experiment]</nowiki> 
+** Oddball <nowiki> [Unexpected or infrequent]</nowiki>
+** Planned
+** Penalty
+** Priming
+** Reward
+** Signal-go
+** Signal-stop 
+** Target <nowiki>[Something the subject is looking for]</nowiki> 
+** Threat
+** Timed
+** Unexpected
+
+
+'''Attribute''' <nowiki>{extensionAllowed} [Subtree tree for general properties.]</nowiki>
+* Informational <nowiki>[Informational properties.]</nowiki>
+** Def <nowiki>{requireChild} [A label that specifically corresponds to a Definition name and indicates that this label represents tags in an unexpanded definition.]</nowiki>
+*** <nowiki># {takesValue}</nowiki>
+** Defexp <nowiki> {requireChild} [A label that specifically corresponds to a Definition name and indicates that this label is in a group containing an expanded definition and should not be expanded again.]</nowiki>
+*** <nowiki># {takesValue}</nowiki>   
+** Definition <nowiki>{requireChild}[A tag used within a tag group also containing a Label tag to indicate that the Label represents that group of tags.]</nowiki> 
+*** <nowiki># {takesValue}</nowiki>
+** Description <nowiki>{requireChild} [Human-readable text description of the event.]</nowiki> 
+*** <nowiki># {takesValue}</nowiki>
+ 
+** ID <nowiki>{requireChild} [An alphanumeric code usually used to identify a particular instance of an item.]</nowiki>
+*** <nowiki># {takesValue}</nowiki>
+** Label <nowiki>{requireChild} [A string of 20 or fewer characters identifying something. Labels usually refer to general classes of things while IDs refer to specific instances.]</nowiki>
+*** <nowiki># {takesValue}</nowiki>
+** Metadata <nowiki>[A tag used within a tag group indicate to designate information about the data such as file size or author.]</nowiki>
+*** CogAtlas <nowiki>[A tag used within a tag group indicate a relationship to the CognitiveAtlas terminology.]</nowiki>
+**** <nowiki># {takesValue}</nowiki>
+*** CogPo <nowiki>[A tag used within a tag group indicate a relationship to the CogPO terminology.]</nowiki>
+**** <nowiki># {takesValue}</nowiki>
+*** Creation-date 
+**** <nowiki># {takesValue, unitClass=datetime}</nowiki>
+*** Library-name 
+**** <nowiki># {takesValue}</nowiki>  
+*** Subject 
+**** <nowiki># {takesValue}</nowiki>
+*** Version 
+**** <nowiki># {takesValue}{Usually is a semantic version.]</nowiki> 
+
+** Parameter <nowiki>[As a Name:Value]</nowiki> 
+*** <nowiki># {takesValue}</nowiki>
+
+* Organizational
+** Collection <nowiki>[A tag designating a grouping of items such as in a set or list.]</nowiki> 
+** Event-context <nowiki>[A tag indicating the overall environment and setup of the experiment or a portion of the experiment. This event is often inserted into a recording at the beginning of an experimental record to describe information such as whether the experiment is conducted indoors or outdoors or whether the experiment is conducted in the real-world or in a controlled laboratory setting. Tags specifying subject metadata might also be included. ]</nowiki>
+** Event-stream <nowiki>[An ordered list of events  ]</nowiki>
+** Permutation <nowiki>[A tag used within a tag group also containing a Label tag to indicate that the Label represents events that are permutations of each other.]</nowiki>
+** Recording <nowiki>[Indicates an uninterrupted block of time during which data was acquired using a fixed scanning protocol or sensor positioning. Recording tags are usually have temporal scope which is the entire recording.]</nowiki>
+** Task <nowiki>[A tag used to indicate a linkage the structured activities performed as part of the experiment.]</nowiki> 
+** Task-condition <nowiki>[An aspect of the experiment or task that is to be varied during the experiment. Task-conditions are sometimes called independent variables or contrasts.]</nowiki>
+** Task-control <nowiki>[An aspect of the experiment that is fixed throughout the study and usually is explicitly controlled.]</nowiki>
+** Task-response <nowiki>[An aspect of the experiment or task that is measured as task conditions are varied during the experiment. Task-responses are sometimes called dependent variables.]</nowiki>
+** Task-trial <nowiki>[A tag used to indicate a particular organizational part in the experimental design often containing a stimulus-response pair.]</nowiki>
+** Time-block <nowiki>[A tag used to indicate a contiguous time block in the experiment during which something is fixed or noted.]</nowiki>
+* Relational <nowiki>{extensionAllowed}</nowiki>
+** Comparative-relation
+*** Less-than
+*** Less-than-or-equal-to
+*** Greater-than
+*** Greater-than-or-equal-to
+*** Equal-to
+*** Not-equal-to
+** Connective-relation
+*** Belongs-to <nowiki>[As in owned by]</nowiki>
+*** Connected-to
+*** Contained-in
+*** Described-by
+*** From-to
+*** Group-of
+*** Implied-by
+*** Interacts-with
+*** Member-of
+*** Part-of
+*** Performed-by
+*** Related-to
+
+** Ordering-relation
+*** Early-item <nowiki>[Indication that this item appears early in a sequence.]</nowiki>
+*** First-item <nowiki>[Indication that this is the first item in a sequence.]</nowiki>
+*** Next-item <nowiki>[Indication that this item appears immediately after the previous item in a sequence.]</nowiki> 
+*** Later-item <nowiki>[Indication that this item appears later in a sequence.]</nowiki>
+*** Last-item <nowiki>[Indication that this is the last item in a sequence.]</nowiki>
+
+** Quantitative-relation
+*** Estimated
+*** Approximated
+*** Exact
+
+** Spatiotemporal-relation
+*** Directional-relation
+**** Away-from
+**** Backward
+**** Closing
+**** Decreasing
+**** Downward
+**** Forward
+**** Increasing
+**** Leftward
+**** Rightward
+**** Opening
+**** Towards
+**** Upward
+*** Orientational-relation
+**** Horizontally-oriented
+**** Oblique
+**** Rotated
+**** Vertically-oriented
+*** Positional-relation <nowiki>[Should be grouped with what it is positionally related to.]</nowiki>
+**** Above
+**** Across
+**** Adjacent-to
+**** Ahead-of
+**** Around
+**** Back-of
+**** Behind
+**** Below
+**** Between <nowiki>[Should be grouped with the items between designates.]</nowiki>
+**** Bilateral <nowiki>{Used designate activities or items that occur on both sides or on top and bottom.]</nowiki>
+**** Bottom-of <nowiki>[At the bottom of something. Should be grouped with the item that it is positionally related to.]</nowiki>
+**** Boundary-of
+**** Center-of <nowiki>[At the center of something. Should be grouped with the item that it is positionally related to.]</nowiki>
+**** Close-to
+
+**** Edge-of
+**** Far-from
+**** Front-of
+**** Inside-of
+**** Left-of
+**** Left-side
+**** Outside-of
+**** Over
+**** Right-of
+**** Right-side
+**** Top-of
+**** Under
+*** Temporal-relation
+**** After
+**** Asynchronous-with
+**** Before
+**** During
+**** Synchronous-with
+**** Waiting-for
+*** Variability-relation
+**** Constant
+**** Continuous
+**** Deterministic
+**** Discrete
+**** Flickering <nowiki>[Irregular changes in time.]</nowiki>
+**** Fractal
+**** Random
+**** Repetitive
+**** Sudden
+**** Varying
+
+** Thermal-relation
+*** Cold
+*** Colder-than
+*** Hot
+*** Hotter-than
+
+
+
+* Categorical <nowiki>{extensionAllowed}</nowiki>
+** Abnormal <nowiki>{relatedTag=Normal}</nowiki>
+** All <nowiki>{relatedTag=Some, relatedTag=None}</nowiki>
+** Asymmetric <nowiki>{relatedTag=Symmetric}</nowiki>
+** Congruent <nowiki>{relatedTag=Incongruent}</nowiki>
+** Constrained <nowiki>{relatedTag=Unconstrained}</nowiki>
+** Correct <nowiki>{relatedTag=Incorrect}</nowiki>
+** Deep <nowiki>{relatedTag=Shallow}</nowiki>
+** Disordered <nowiki>{relatedTag=Ordered}</nowiki>
+** False <nowiki>{relatedTag=True}</nowiki>
+** Familiar <nowiki>{relatedTag=Unfamiliar, relatedTag=Famous}[Something known or encountered before.]</nowiki>
+** Famous <nowiki>{relatedTag=Familiar, relatedTag=Unfamiliar}[Something known by many people but necessarily because of direct contact.]</nowiki>
+** High <nowiki>{relatedTag=Low, relatedTag=Medium}</nowiki>
+** Incongruent <nowiki>{relatedTag=Congruent}</nowiki>
+** Incorrect <nowiki>{relatedTag=Correct}</nowiki>
+** Invalid <nowiki>{relatedTag=Valid}</nowiki>
+** Involuntary <nowiki>{relatedTag=Voluntary}</nowiki>
+** Liminal <nowiki>{relatedTag=Subliminal, relatedTag=Supraliminal}</nowiki>
+** Low <nowiki>{relatedTag=High}</nowiki>
+** Masked <nowiki>[Ability to perceive influenced by presence of another stimulus]</nowiki>
+** Medium <nowiki>{relatedTag=Low, relatedTag=High}</nowiki>
+** None <nowiki>{relatedTag=All, relatedTag=Some}</nowiki>
+** Normal <nowiki>{relatedTag=Abnormal}</nowiki>
+** Negative <nowiki>{relatedTag=Positive}</nowiki>
+** Ordered <nowiki>{relatedTag=Disordered}</nowiki>
+** Positive <nowiki>{relatedTag=Negative}</nowiki>
+** Shallow <nowiki>{relatedTag=Deep}</nowiki>
+** Some <nowiki>{relatedTag=All, relatedTag=None}</nowiki>
+** Subliminal <nowiki>{relatedTag=Liminal, relatedTag=Supraliminal}</nowiki>
+** Supraliminal <nowiki>{relatedTag=Liminal, relatedTag=Subliminal}</nowiki>
+** Symmetric <nowiki>{relatedTag=Unsymmetric}</nowiki>
+** True <nowiki>{relatedTag=False}</nowiki>
+** Unconstrained <nowiki>{relatedTag=Constrained}</nowiki>
+** Unfamiliar <nowiki>{relatedTag=Familiar,relatedTag=Famous}[Something not known or encountered before.]</nowiki>
+** Unmasked <nowiki>[Ability to perceive not influenced by presence of another stimulus]</nowiki>
+** Valid <nowiki>{relatedTag=Invalid}</nowiki>
+** Voluntary <nowiki>{relatedTag=Involuntary}</nowiki>
+
+* Descriptive <nowiki>[Indicate the type of thing.]</nowiki>
+** Abstract
+** Clinical
+** Complex
+** Composite
+** Numerical
+** Symbolic
+
+* Sensory <nowiki>{extensionAllowed}</nowiki>
+** Auditory
+*** Audible
+*** Frequency 
+**** <nowiki># {takesValue, isNumeric, unitClass=frequency}</nowiki>  
+*** Loudness 
+**** <nowiki># {takesValue, isNumeric}</nowiki>
+*** Monophonic <nowiki> [Consisting of one independent audio channel]</nowiki>  
+*** Ramp-up <nowiki>[Increasing in amplitude]</nowiki> 
+*** Ramp-down <nowiki>[Decreasing in amplitude]</nowiki>
+*** Silent
+*** Stereophonic <nowiki> [Consisting of more than one independent audio channel]</nowiki> 
+*** Timbre <nowiki>[Sound quality]</nowiki>  
+** Gustatory <nowiki>[Pertaining to sensations of relating to taste.]</nowiki>
+*** Bitter
+*** Salty
+*** Savory
+*** Sour
+*** Sweet
+** Tactile <nowiki>[Pertaining to sensations of relating to touch.]</nowiki>
+*** Tactile-pressure
+*** Tactile-texture
+*** Tactile-vibration
+** Olfactory <nowiki>[Pertaining to sensations of relating to smell.]</nowiki>
+** Somatic <nowiki>[Pertaining to sensations of nervous system such as pain.]</nowiki>
+*** Pain
+*** Stress
+** Vestibular
+** Visual
+*** Luminance 
+*** Color 
+**** Color-shade 
+***** Dark-shade
+***** Light-shade 
+**** HSV-color
+***** Hue 
+****** <nowiki># {takesValue, isNumeric} [Angular value between 0 and 360]</nowiki> 
+***** Saturation 
+****** <nowiki># {takesValue, isNumeric} [B value of RGB between 0 and 1]</nowiki> 
+***** HSV-value 
+****** <nowiki># {takesValue, isNumeric} [G value of RGB between 0 and 1]</nowiki> 
+**** RGB-color
+***** RGB-red 
+****** <nowiki># {takesValue, isNumeric} [R value of RGB between 0 and 1]</nowiki> 
+***** RGB-blue 
+****** <nowiki># {takesValue, isNumeric} [B value of RGB between 0 and 1]</nowiki> 
+***** RGB-green 
+****** <nowiki># {takesValue, isNumeric} [G value of RGB between 0 and 1]</nowiki> 
+**** Grayscale <nowiki>[Indicates gray scale]</nowiki> 
+***** <nowiki># {takesValue, isNumeric} [White intensity between 0 and 1]</nowiki>
+**** CSS-color <nowiki>[One of 140 colors supported by all browsers. For more details such as the color RGB or HEX values,  check:  https://www.w3schools.com/colors/colors_groups.asp]</nowiki> 
+***** Blue-color
+****** CadetBlue
+****** SteelBlue
+****** LightSteelBlue
+****** LightBlue
+****** PowderBlue
+****** LightSkyBlue
+****** SkyBlue
+****** CornflowerBlue
+****** DeepSkyBlue
+****** DodgerBlue
+****** RoyalBlue
+****** Blue
+****** MediumBlue
+****** DarkBlue
+****** Navy
+****** MidnightBlue
+***** Brown-color
+****** Cornsilk 
+****** BlanchedAlmond 
+****** Bisque 
+****** NavajoWhite 
+****** Wheat 
+****** BurlyWood 
+****** Tan 
+****** RosyBrown 
+****** SandyBrown 
+****** GoldenRod 
+****** DarkGoldenRod 
+****** Peru 
+****** Chocolate 
+****** Olive 
+****** SaddleBrown 
+****** Sienna 
+****** Brown 
+****** Maroon 
+***** Cyan-color
+****** Aqua
+****** Cyan
+****** LightCyan
+****** PaleTurquoise
+****** Aquamarine
+****** Turquoise
+****** MediumTurquoise
+****** DarkTurquoise
+***** Green-color
+****** GreenYellow
+****** Chartreuse
+****** LawnGreen
+****** Lime
+****** LimeGreen
+****** PaleGreen
+****** LightGreen
+****** MediumSpringGreen
+****** SpringGreen
+****** MediumSeaGreen
+****** SeaGreen
+****** ForestGreen
+****** Green
+****** DarkGreen
+****** YellowGreen
+****** OliveDrab
+****** DarkOliveGreen
+****** MediumAquaMarine
+****** DarkSeaGreen
+****** LightSeaGreen
+****** DarkCyan
+****** Teal
+***** Gray-color
+****** Gainsboro
+****** LightGray
+****** Silver
+****** DarkGray
+****** DimGray
+****** Gray
+****** LightSlateGray
+****** SlateGray
+****** DarkSlateGray
+****** Black
+***** Orange-color
+****** Orange
+****** DarkOrange
+****** Coral
+****** Tomato
+****** OrangeRed
+***** Pink-color
+****** Pink
+****** LightPink
+****** HotPink
+****** DeepPink
+****** PaleVioletRed
+****** MediumVioletRed
+***** Purple-color
+****** Lavender
+****** Thistle
+****** Plum
+****** Orchid
+****** Violet
+****** Fuchsia
+****** Magenta
+****** MediumOrchid
+****** DarkOrchid
+****** DarkViolet
+****** BlueViolet
+****** DarkMagenta
+****** Purple
+****** MediumPurple
+****** MediumSlateBlue
+****** SlateBlue
+****** DarkSlateBlue
+****** RebeccaPurple
+****** Indigo
+***** Red-color
+****** LightSalmon
+****** Salmon
+****** DarkSalmon
+****** LightCoral
+****** IndianRed
+****** Crimson
+****** Red
+****** FireBrick
+****** DarkRed
+***** Yellow-color
+****** Gold
+****** Yellow
+****** LightYellow
+****** LemonChiffon
+****** LightGoldenRodYellow
+****** PapayaWhip
+****** Moccasin
+****** PeachPuff
+****** PaleGoldenRod
+****** Khaki
+****** DarkKhaki
+***** White-color
+****** White
+****** Snow
+****** HoneyDew
+****** MintCream
+****** Azure
+****** AliceBlue
+****** GhostWhite
+****** WhiteSmoke
+****** SeaShell
+****** Beige
+****** OldLace
+****** FloralWhite
+****** Ivory
+****** AntiqueWhite
+****** Linen
+****** LavenderBlush
+****** MistyRose
+*** View
+**** 2D-view
+**** 3D-view
+**** Background-view
+**** Bistable-view <nowiki>[Something having two stable visual forms that have two distinguishable stable forms as in optical illusions.]</nowiki>
+**** Foreground-view
+**** Foveal-view <nowiki>[Visual presentation directly on the fovea.]</nowiki>
+**** Map-view <nowiki>[A representation of a geographical location.]</nowiki>
+***** Aerial-view <nowiki>[A representation from an overhead view such as captured by a drone.]</nowiki>
+***** Satellite-view <nowiki>[A representation as captured by technology such as a satellite.]</nowiki>
+***** Street-view <nowiki>[A panoramic view from a position on the ground.]</nowiki>
+**** Peripheral-view
+
+
+
+* Environmental <nowiki>{extensionAllowed}</nowiki>
+** Indoors
+** Outdoors
+** Real-world
+** Virtual-world
+** Augmented-reality
+** Motion-platform
+** Urban
+** Rural
+*** Wooden-walkway
+** Terrain
+*** Composite-terrain
+*** Dirt-terrain
+*** Grassy-terrain
+*** Gravel-terrain
+*** Leaf-covered-terrain
+*** Muddy-terrain
+*** Paved-terrain
+*** Rocky-terrain
+*** Sloped-terrain
+*** Uneven-terrain
+
+* Anatomical
+
+
+
+'''Unit classes''' 
+* time <nowiki>{defaultUnits=s}</nowiki> 
+** second <nowiki>{SIUnit}</nowiki> 
+** s <nowiki>{SIUnit, unitSymbol}</nowiki> 
+** day 
+** minute 
+** hour <nowiki>[Should be in 24-hour format.]</nowiki>
+* dateTime <nowiki>{defaultUnits=YYYY-MM-DDThh:mm:ss}</nowiki> 
+** YYYY-MM-DDThh:mm:ss <nowiki>[Date-times should conform to ISO8601 date-time format.]</nowiki> 
+* clockTime <nowiki>{defaultUnits=hour:min}</nowiki> 
+** hour:min <nowiki>[Hours should be in 24 hour format. Two-digit values should be used for each item.]</nowiki> 
+** hour:min:sec <nowiki>[Hours should be in 24 hour format. Two-digit values should be used for each item.]</nowiki> 
+* frequency <nowiki>{defaultUnits=Hz}</nowiki>
+** hertz  <nowiki>{SIUnit}</nowiki>
+** Hz <nowiki>{SIUnit, unitSymbol}</nowiki> 
+* angle <nowiki>{defaultUnits=radian}</nowiki> 
+** radian <nowiki>{SIUnit}</nowiki> 
+** rad <nowiki>{SIUnit, unitSymbol}</nowiki> 
+** degree 
+* physicalLength <nowiki>{defaultUnits=m}</nowiki> 
+** metre <nowiki>{SIUnit}</nowiki> 
+** m <nowiki>{SIUnit, unitSymbol}</nowiki> 
+** foot 
+** mile  
+* pixels <nowiki>{defaultUnits=px}</nowiki>  
+** pixel 
+** px <nowiki>{unitSymbol}</nowiki> 
+* area <nowiki>{defaultUnits=m^2}</nowiki> 
+** m^2 <nowiki>{SIUnit, unitSymbol}</nowiki> 
+** px^2 <nowiki>{unitSymbol}</nowiki> 
+** pixel^2
+* volume <nowiki>{defaultUnits=m^3}</nowiki> 
+** m^3 <nowiki>{SIUnit, unitSymbol}</nowiki> 
+* speed <nowiki>{defaultUnits=m-per-s}</nowiki> 
+** m-per-s <nowiki>{SIUnit, unitSymbol}</nowiki> 
+** mph <nowiki>{unitSymbol}</nowiki> 
+** kph <nowiki>{unitSymbol}</nowiki> 
+* acceleration <nowiki>{defaultUnits=m-per-s^2}</nowiki> 
+** m-per-s^2 <nowiki>{SIUnit, unitSymbol}</nowiki> 
+* jerk <nowiki>{defaultUnits=m-per-s^3}</nowiki> 
+** m-per-s^3 <nowiki>{unitSymbol}</nowiki> 
+* intensity <nowiki>{defaultUnits=dB}</nowiki> 
+** dB <nowiki>{unitSymbol}</nowiki> 
+* luminousIntensity <nowiki>{defaultUnits=cd}</nowiki> 
+** candela <nowiki>{SIUnit}</nowiki> 
+** cd <nowiki>{SIUnit, unitSymbol}</nowiki> 
+* memorySize <nowiki>{defaultUnits=B}</nowiki> 
+** byte <nowiki>{SIUnit}</nowiki>
+** B <nowiki>{SIUnit, unitSymbol}</nowiki> 
+* currency <nowiki>{defaultUnits=$}</nowiki> 
+** dollar 
+** $ <nowiki>{unitSymbol}</nowiki> 
+** point 
+** fraction 
+
+'''Unit modifiers''' 
+* deca <nowiki>{SIUnitModifier} [SI unit multiple representing 10^1]</nowiki> 
+* da <nowiki>{SIUnitSymbolModifier} [SI unit multiple representing 10^1]</nowiki>
+* hecto <nowiki>{SIUnitModifier} [SI unit multiple representing 10^2]</nowiki> 
+* h <nowiki>{SIUnitSymbolModifier} [SI unit multiple representing 10^2]</nowiki>
+* kilo <nowiki>{SIUnitModifier} [SI unit multiple representing 10^3]</nowiki> 
+* k <nowiki>{SIUnitSymbolModifier} [SI unit multiple representing 10^3]</nowiki>
+* mega <nowiki>{SIUnitModifier} [SI unit multiple representing 10^6]</nowiki> 
+* M <nowiki>{SIUnitSymbolModifier} [SI unit multiple representing 10^6]</nowiki>
+* giga <nowiki>{SIUnitModifier} [SI unit multiple representing 10^9]</nowiki> 
+* G <nowiki>{SIUnitSymbolModifier} [SI unit multiple representing 10^9]</nowiki>
+* tera <nowiki>{SIUnitModifier} [SI unit multiple representing 10^12]</nowiki> 
+* T <nowiki>{SIUnitSymbolModifier} [SI unit multiple representing 10^12]</nowiki>
+* peta <nowiki>{SIUnitModifier} [SI unit multiple representing 10^15]</nowiki> 
+* P <nowiki>{SIUnitSymbolModifier} [SI unit multiple representing 10^15]</nowiki> 
+* exa <nowiki>{SIUnitModifier} [SI unit multiple representing 10^18]</nowiki> 
+* E <nowiki>{SIUnitSymbolModifier} [SI unit multiple representing 10^18]</nowiki>
+* zetta <nowiki>{SIUnitModifier} [SI unit multiple representing 10^21]</nowiki> 
+* Z <nowiki>{SIUnitSymbolModifier} [SI unit multiple representing 10^21]</nowiki>
+* yotta <nowiki>{SIUnitModifier} [SI unit multiple representing 10^24]</nowiki> 
+* Y <nowiki>{SIUnitSymbolModifier} [SI unit multiple representing 10^24]</nowiki>   
+* deci <nowiki>{SIUnitModifier} [SI unit submultiple representing 10^-1]</nowiki> 
+* d <nowiki>{SIUnitSymbolModifier} [SI unit submultiple representing 10^-1]</nowiki> 
+* centi <nowiki>{SIUnitModifier} [SI unit submultiple representing 10^-2]</nowiki> 
+* c <nowiki>{SIUnitSymbolModifier} [SI unit submultiple representing 10^-2]</nowiki>
+* milli <nowiki>{SIUnitModifier} [SI unit submultiple representing 10^-3]</nowiki> 
+* m <nowiki>{SIUnitSymbolModifier} [SI unit submultiple representing 10^-3]</nowiki>
+* micro <nowiki>{SIUnitModifier} [SI unit submultiple representing 10^-6]</nowiki> 
+* u <nowiki>{SIUnitSymbolModifier} [SI unit submultiple representing 10^-6]</nowiki>
+* nano <nowiki>{SIUnitModifier} [SI unit submultiple representing 10^-9]</nowiki> 
+* n <nowiki>{SIUnitSymbolModifier} [SI unit submultiple representing 10^-9]</nowiki> 
+* pico <nowiki>{SIUnitModifier} [SI unit submultiple representing 10^-12]</nowiki> 
+* p <nowiki>{SIUnitSymbolModifier} [SI unit submultiple representing 10^-12]</nowiki>
+* femto <nowiki>{SIUnitModifier} [SI unit submultiple representing 10^-15]</nowiki> 
+* f <nowiki>{SIUnitSymbolModifier} [SI unit submultiple representing 10^-15]</nowiki>
+* atto <nowiki>{SIUnitModifier} [SI unit submultiple representing 10^-18]</nowiki> 
+* a <nowiki>{SIUnitSymbolModifier} [SI unit submultiple representing 10^-18]</nowiki>
+* zepto <nowiki>{SIUnitModifier} [SI unit submultiple representing 10^-21]</nowiki> 
+* z <nowiki>{SIUnitSymbolModifier} [SI unit submultiple representing 10^-21]</nowiki>
+* yocto <nowiki>{SIUnitModifier} [SI unit submultiple representing 10^-24]</nowiki> 
+* y <nowiki>{SIUnitSymbolModifier} [SI unit submultiple representing 10^-24]</nowiki>  
+!# end hed 
+
+'''Attribute Definitions:'''
+* defaultUnits <nowiki>[Default units for a tag.]</nowiki> 
+* extensionAllowed <nowiki>[Users can add unlimited levels of child nodes under this tag.]</nowiki> 
+* isNumeric <nowiki>[The tag "#" must be replaced by a numerical value.]</nowiki> 
+* position <nowiki>[Used to specify the order of the required and recommended tags in canonical order for display. The position attribute value should be an integer and the order can start at 0 or 1. Required or recommended tags without this attribute or with negative position will be shown after the others in canonical ordering.]</nowiki> 
+* predicateType <nowiki> [One of propertyOf, subclassOf, passThrough -- used to facilitate mapping to OWL or RDF.]</nowiki>  
+* recommended  <nowiki>[A HED string tagging an event is recommended to include this tag.]</nowiki> 
+* relatedTag <nowiki>[Additional HED tags suggested to be used with this tag. This attribute is used by tagging tools.]</nowiki> 
+* requireChild  <nowiki>[One of its descendants must be chosen to tag an event.]</nowiki> 
+* required <nowiki>[Every HED string tagging an event should include this tag.]</nowiki>
+* SIUnit  <nowiki>[Designates the name of an SI unit so it can be modified by multiple and submultiple names. Note that some units such as byte are designated as SI units although they are not part of the standard.]</nowiki>
+* SIUnitModifier <nowiki>[SI unit modifier indicating a multiple or submultiple of a base unit.]</nowiki> 
+* SIUnitSymbolModifier <nowiki>[SI unit symbol modifier indicating a multiple or submultiple of a base unit symbol.]</nowiki>
+* suggestedTag <nowiki>[Additional HED tags suggested to be used with this tag. This attribute is used by tagging tools.]</nowiki> 
+* takesValue <nowiki>[This tag will have a "#" placeholder child in the schema which is expected to be replaced with a user-defined value.] </nowiki> 
+* unique <nowiki>[Only one of this tag or its descendants can be used within a single tag group or event.]</nowiki> 
+* unitSymbol <nowiki>[Abbreviation or symbol representing a type of unit. Unit symbols  represent both the singular and the plural and thus cannot be pluralized.]</nowiki> 
diff --git a/hedweb/tests/data/HED8.0.0-alpha.1.xml b/hedweb/tests/data/HED8.0.0-alpha.1.xml
index b4cc6d725..d71da44e6 100644
--- a/hedweb/tests/data/HED8.0.0-alpha.1.xml
+++ b/hedweb/tests/data/HED8.0.0-alpha.1.xml
@@ -2,17 +2,17 @@
 <HED version="8.0.0-alpha.1">
    <node>
       <name>Event</name>
-      <node>
+      <node suggestedTag="Task-property/Task-role">
          <name>Sensory-event</name>
-         <description>Something perceivable by the participant. An event meant to be an experimental stimulus should also be tagged with Attribute/Contextual/Task-related. Other events may be tagged with Attribute/Contextual/Non task-related.</description>
+         <description>Something perceivable by the participant. An event meant to be an experimental stimulus should also be tagged with Task-property/Task-role/Experiment-stimulus.</description>
       </node>
       <node>
          <name>Agent-action</name>
-         <description>Any action engaged in by an agent. An event which is a participant response to an experimental stimulus should also be tagged with Attribute/Task-related and Attribute/Role/Experimental subject.</description>
+         <description>Any action engaged in by an agent. An event that is a participant response to an experiment stimulus should also be tagged with Agent-property/Agent-task-role/Participant-response.</description>
       </node>
       <node>
          <name>Data-feature</name>
-         <description>An event derived from the data itself, possibly inserted in a post-hoc fashion, for example an interictal spike or alpha burst.</description>
+         <description>An event derived from the data itself or possibly inserted in a post-hoc fashion. Examples are markers for interictal spikes or alpha bursts.</description>
       </node>
       <node extensionAllowed="true">
          <name>Experiment-control</name>
@@ -20,17 +20,19 @@
       </node>
       <node>
          <name>Experiment-procedure</name>
-         <description>An event indicating an experimental procedure as in doing a saliva swab on the person during the experiment or administering a survey.</description>
+         <description>An event indicating an experimental procedure as in doing a saliva swab on a participant during the experiment or administering a survey.</description>
       </node>
       <node extensionAllowed="true">
          <name>Experiment-structure</name>
          <description>An event specifying the structure of the experiment.</description>
       </node>
    </node>
-   <node extensionAllowed="true">
+   <node>
       <name>Agent</name>
+      <description>Something in the experiment that takes an active role or produces an effect. The role or effect may be implicit. Being alive or performing an activity such as a computation may qualify something to be an agent. An agent may also be soething that simulates something else.</description>
       <node>
          <name>Animal-agent</name>
+         <description>An animal that is present.</description>
       </node>
       <node>
          <name>Avatar-agent</name>
@@ -58,11 +60,11 @@
             <name>Breathe</name>
             <node>
                <name>Inhale</name>
-               <description>A deliberate inbreath, e.g. in response to a task instruction. If incidental, group it with Attribute/Cognitive modifier/Incidental. E.g. (Action/Move/Breathe/Inhale, Attribute/Cognitive modifier/Incidental).</description>
+               <description>A deliberate in-breath in response to a task instruction or as part of a task. Group with Attribute/Cognitive modifier/Incidental if the inhalation is incidental to the task (Action/Move/Breathe/Inhale, Attribute/Cognitive modifier/Incidental).</description>
             </node>
             <node>
                <name>Exhale</name>
-               <description>A deliberate outbreath, e.g. in response to a task instruction. If incidental, group it with Attribute/Cognitive modifier/Incidental. E.g. (Action/Move/Breathe/Exhale, Attribute/Cognitive modifier/Incidental).</description>
+               <description>A deliberate out-breath in response to a task instruction or as part of a task. Group with Attribute/Cognitive modifier/Incidental: (Action/Move/Breathe/Exhale, Attribute/Cognitive modifier/Incidental).</description>
             </node>
             <node>
                <name>Hold-breath</name>
@@ -333,7 +335,7 @@
             </node>
             <node>
                <name>Vocalize</name>
-               <description>Make a sustained vowel sound such as, Ahhh</description>
+               <description>Make a sustained vowel sound such as Ahhh.</description>
             </node>
             <node>
                <name>Whistle</name>
@@ -343,46 +345,52 @@
       <node>
          <name>Perform</name>
          <description>Carry out or accomplish an action or task or function.</description>
-         <node>
-            <name>Appear</name>
-         </node>
-         <node>
-            <name>Change</name>
-         </node>
          <node>
             <name>Collide</name>
          </node>
          <node>
-            <name>Disappear</name>
-         </node>
-         <node>
-            <name>Fill-out-survey</name>
+            <name>Halt</name>
+            <description>Stop action.</description>
          </node>
          <node>
-            <name>Halt</name>
+            <name>Modify</name>
+            <description>Deliberately make a change in something.</description>
          </node>
          <node>
             <name>Operate</name>
             <description>Control something else.</description>
+         </node>
+         <node>
+            <name>Perceive</name>
+            <node>
+               <name>Feel</name>
+            </node>
+            <node>
+               <name>Listen</name>
+            </node>
             <node>
-               <name>Drive</name>
-               <description>Control something that moves.</description>
+               <name>Look</name>
             </node>
             <node>
-               <name>Brake</name>
-               <description>Apply brakes to stop something.</description>
+               <name>Smell</name>
             </node>
             <node>
-               <name>Steer</name>
+               <name>Taste</name>
             </node>
          </node>
          <node>
             <name>Play</name>
             <description>As a musical instrument or a game.</description>
          </node>
+         <node>
+            <name>Read</name>
+         </node>
          <node>
             <name>Rest</name>
          </node>
+         <node>
+            <name>Write</name>
+         </node>
       </node>
       <node>
          <name>Think</name>
@@ -425,7 +433,7 @@
             <name>Predict</name>
          </node>
          <node>
-            <name>Read</name>
+            <name>Respond</name>
          </node>
          <node>
             <name>Recall</name>
@@ -443,6 +451,46 @@
    </node>
    <node extensionAllowed="true">
       <name>Item</name>
+      <node>
+         <name>Language</name>
+         <description>An  system of communication that is receivable in a sensory presentation.</description>
+         <node>
+            <name>Character</name>
+            <description>A mark, sign or symbol used as part of language.</description>
+         </node>
+         <node>
+            <name>Glyph</name>
+            <description>A symbol or pictograph.</description>
+         </node>
+         <node>
+            <name>Nonword</name>
+            <description>A group of letters or speech sounds that looks or sounds like a word but that is not accepted as such by native speakers.</description>
+         </node>
+         <node>
+            <name>Phoneme</name>
+            <description>A sound or a group of different sounds perceived to have the same function by speakers of the language.</description>
+         </node>
+         <node>
+            <name>Phrase</name>
+            <description>A small group of words standing together as a conceptual unit.</description>
+         </node>
+         <node>
+            <name>Sentence</name>
+            <description>A set of words that is complete in itself.</description>
+         </node>
+         <node>
+            <name>Syllable</name>
+            <description>A unit of pronunciation having one vowel sound.</description>
+         </node>
+         <node>
+            <name>Textblock</name>
+            <description>A block of text.</description>
+         </node>
+         <node>
+            <name>Word</name>
+            <description>A single distinct meaningful element of a language.</description>
+         </node>
+      </node>
       <node extensionAllowed="true">
          <name>Object</name>
          <description>Physical object perceptible via Visual, Auditory, Olfactory, and/or Tactile modalities.</description>
@@ -613,17 +661,17 @@
                      </node>
                      <node>
                         <name>Keyboard</name>
-                        <node takesValue="true">
+                        <node>
                            <name>Key</name>
-                           <node>
+                           <node takesValue="true">
                               <name>#</name>
                               <description>Value of key.</description>
                            </node>
                         </node>
                      </node>
-                     <node takesValue="true">
+                     <node>
                         <name>Keypad</name>
-                        <node>
+                        <node takesValue="true">
                            <name>#</name>
                            <description>Value of keypad key.</description>
                         </node>
@@ -789,23 +837,14 @@
          </node>
          <node>
             <name>Natural-object</name>
-            <node>
-               <name>Organism</name>
-               <node>
-                  <name>Animal</name>
-               </node>
-               <node>
-                  <name>Human</name>
-               </node>
-               <node>
-                  <name>Plant</name>
-               </node>
-            </node>
+            <description>An object occuring naturally in contrast to a man-made object.</description>
             <node>
                <name>Mineral</name>
+               <description>An inorganic substance</description>
             </node>
             <node>
                <name>Natural-feature</name>
+               <description>Some terrain occuring in the outdoors.</description>
                <node>
                   <name>Field</name>
                </node>
@@ -825,50 +864,140 @@
          </node>
          <node>
             <name>Food</name>
+            <description>Something that is usually solid and can be consumed by an organism.</description>
          </node>
          <node>
             <name>Drink</name>
+            <description>Something that is liquid and can be consumed by an organism.</description>
          </node>
       </node>
       <node>
-         <name>Language</name>
-         <description>Perceivable in a visual or auditory (spoken) sensory presentation</description>
-         <node>
-            <name>Character</name>
-         </node>
-         <node>
-            <name>Glyph</name>
-         </node>
-         <node>
-            <name>Nonword</name>
-         </node>
-         <node>
-            <name>Phoneme</name>
-         </node>
+         <name>Organism</name>
+         <description>Something living or part of something living.</description>
          <node>
-            <name>Phrase</name>
-         </node>
-         <node>
-            <name>Sentence</name>
-         </node>
-         <node>
-            <name>Syllable</name>
+            <name>Animal</name>
+            <description>Any multicellular or eukaryotic organism.</description>
+            <node>
+               <name>Human</name>
+            </node>
          </node>
          <node>
-            <name>Textblock</name>
+            <name>Plant</name>
          </node>
          <node>
-            <name>Word</name>
+            <name>Body-part</name>
+            <node>
+               <name>Head</name>
+               <node>
+                  <name>Hair</name>
+               </node>
+               <node>
+                  <name>Ear</name>
+               </node>
+               <node>
+                  <name>Face</name>
+                  <node>
+                     <name>Cheek</name>
+                  </node>
+                  <node>
+                     <name>Chin</name>
+                  </node>
+                  <node>
+                     <name>Eye</name>
+                  </node>
+                  <node>
+                     <name>Eyebrow</name>
+                  </node>
+                  <node>
+                     <name>Forehead</name>
+                  </node>
+                  <node>
+                     <name>Lip</name>
+                  </node>
+                  <node>
+                     <name>Nose</name>
+                  </node>
+                  <node>
+                     <name>Mouth</name>
+                  </node>
+                  <node>
+                     <name>Teeth</name>
+                  </node>
+               </node>
+            </node>
+            <node>
+               <name>Arm</name>
+               <node>
+                  <name>Elbow</name>
+               </node>
+               <node>
+                  <name>Hand</name>
+                  <node>
+                     <name>Finger</name>
+                     <node>
+                        <name>Index-finger</name>
+                     </node>
+                     <node>
+                        <name>Little-finger</name>
+                     </node>
+                     <node>
+                        <name>Middle-finger</name>
+                     </node>
+                     <node>
+                        <name>Ring-finger</name>
+                     </node>
+                     <node>
+                        <name>Thumb</name>
+                     </node>
+                  </node>
+               </node>
+               <node>
+                  <name>Wrist</name>
+               </node>
+            </node>
+            <node>
+               <name>Leg</name>
+               <node>
+                  <name>Ankle</name>
+               </node>
+               <node>
+                  <name>Foot</name>
+                  <node>
+                     <name>Toe</name>
+                  </node>
+               </node>
+               <node>
+                  <name>Knee</name>
+               </node>
+            </node>
+            <node>
+               <name>Torso</name>
+               <node>
+                  <name>Upper-torso</name>
+                  <node>
+                     <name>Chest</name>
+                  </node>
+               </node>
+               <node>
+                  <name>Lower-torso</name>
+                  <node>
+                     <name>Hips</name>
+                  </node>
+               </node>
+               <node>
+                  <name>Waist</name>
+               </node>
+            </node>
          </node>
       </node>
       <node>
          <name>Sound</name>
-         <description>Item/Sound can be used in a tag group to describe, for example, sound created by an action Item/Sound, Action/Move/Move leg-foot/Walk, Agent/Human or an object or Item/Sound, Item/Object/Man-made/Vehicle/Car</description>
+         <description>Item/Sound can be used in a tag group to describe a sound created by an action Item/Sound, Action/Move/Move leg-foot/Walk, Agent/Human or an object or Item/Sound, Item/Object/Man-made/Vehicle/Car</description>
          <node>
             <name>Environmental-sound</name>
             <description>A background sound from the surrounding environment.</description>
             <node>
-               <name>Crowd sound</name>
+               <name>Crowd-sound</name>
                <description>Multiple speech streams at once</description>
             </node>
             <node>
@@ -1056,8 +1185,9 @@
             <name>Sad</name>
          </node>
       </node>
-      <node requireChild="true">
+      <node>
          <name>Postural-state</name>
+         <description>Indicates the position of an agent. Usually this position or posture is static for some length of time rather than being part of a motion.</description>
          <node>
             <name>Crouching</name>
          </node>
@@ -1080,7 +1210,7 @@
             <name>Supported-by-chin-rest</name>
          </node>
       </node>
-      <node extensionAllowed="true" requireChild="true">
+      <node extensionAllowed="true">
          <name>Agent-trait</name>
          <node>
             <name>Age</name>
@@ -1101,7 +1231,7 @@
             </node>
          </node>
       </node>
-      <node requireChild="true">
+      <node>
          <name>Social-role</name>
          <description>The role of the agent not particular to the task.</description>
          <node>
@@ -1120,14 +1250,14 @@
             <name>Sister</name>
          </node>
       </node>
-      <node requireChild="true">
-         <name>Task-role</name>
+      <node>
+         <name>Agent-task-role</name>
          <description>The role of the agent in the task.</description>
          <node>
             <name>Experiment-controller</name>
          </node>
          <node>
-            <name>Experiment-subject</name>
+            <name>Experiment-participant</name>
          </node>
          <node>
             <name>Experimenter</name>
@@ -1151,7 +1281,7 @@
             <name>Teacher</name>
          </node>
       </node>
-      <node requireChild="true">
+      <node>
          <name>Association</name>
          <node>
             <name>Associated-with-non-agent</name>
@@ -1168,62 +1298,377 @@
    </node>
    <node>
       <name>Data-property</name>
-      <node requireChild="true">
-         <name>Data-property-value</name>
+      <node extensionAllowed="true">
+         <name>Computed-property</name>
+         <description>Feature computed by tool. Should be grouped with a label of the form Toolname_propertyName</description>
+         <node>
+            <name>Computed-prediction</name>
+         </node>
+      </node>
+      <node>
+         <name>Data-value</name>
          <node takesValue="true">
             <name>#</name>
          </node>
       </node>
-      <node>
-         <name>Statistical-property</name>
-         <node>
-            <name>Accuracy</name>
+      <node extensionAllowed="true">
+         <name>Observational-property</name>
+         <description>Manually identified data feature. Should be grouped with a label of the form AgentID_featureName</description>
+         <node extensionAllowed="true">
+            <name>Expert-annotation</name>
+         </node>
+         <node extensionAllowed="true">
+            <name>Instrument-measurement</name>
          </node>
+      </node>
+      <node>
+         <name>Physical-property</name>
          <node>
-            <name>Data-mean</name>
+            <name>Electrical-property</name>
          </node>
          <node>
-            <name>Data-median</name>
+            <name>Magnetic-property</name>
          </node>
          <node>
-            <name>Data-minimum</name>
+            <name>Mechanical-property</name>
          </node>
          <node>
-            <name>Data-maximum</name>
+            <name>Organic-property</name>
          </node>
          <node>
-            <name>Probability</name>
-            <description>Use to specify the level of certainty about the occurrence of the event.</description>
+            <name>Thermodynamic-property</name>
+            <node>
+               <name>Energy</name>
+            </node>
+            <node>
+               <name>Pressure</name>
+            </node>
+            <node>
+               <name>Temperature</name>
+               <node isNumeric="true" takesValue="true">
+                  <name>#</name>
+               </node>
+            </node>
          </node>
+      </node>
+      <node extensionAllowed="true">
+         <name>Quantitative</name>
          <node>
-            <name>Statistical-precision</name>
+            <name>Angle</name>
+            <description>Angle assumed clockwise from vertical unless grouped with axis.</description>
+            <node takesValue="true">
+               <name>#</name>
+            </node>
          </node>
          <node>
-            <name>Statistical-recall</name>
+            <name>Fraction</name>
+            <description>Fraction of items of a particular type.</description>
+            <node takesValue="true">
+               <name>#</name>
+            </node>
          </node>
          <node>
-            <name>Standard-deviation</name>
+            <name>Interval</name>
+            <node takesValue="true">
+               <name>#</name>
+            </node>
          </node>
          <node>
-            <name>Uncertainty</name>
-            <description>Use to specify the level of error.</description>
+            <name>Item-count</name>
+            <node takesValue="true">
+               <name>#</name>
+            </node>
+         </node>
+         <node>
+            <name>Percentage</name>
+            <description>Percentage of items of a particular type.</description>
+            <node takesValue="true">
+               <name>#</name>
+            </node>
+         </node>
+         <node>
+            <name>Ratio</name>
+            <node takesValue="true">
+               <name>#</name>
+            </node>
+         </node>
+         <node>
+            <name>Repetition</name>
+            <description>When the same type of event such as a fixation on the exact same object happens multiple times and it might be necessary to distinguish the first look vs. others</description>
+            <node takesValue="true">
+               <name>#</name>
+            </node>
          </node>
       </node>
-      <node>
-         <name>Observational-property</name>
-         <description>Manually identified data feature. Should be grouped with a label of the form AgentID_featureName</description>
+      <node extensionAllowed="true">
+         <name>Spatiotemporal</name>
          <node>
-            <name>Expert-annotation</name>
+            <name>Rate-of-change</name>
+            <node>
+               <name>Acceleration</name>
+               <node isNumeric="true" takesValue="true" unitClass="acceleration">
+                  <name>#</name>
+               </node>
+            </node>
+            <node>
+               <name>Jerk-rate</name>
+               <description>Rate at which the acceleration of an object changes with respect to time.</description>
+               <node isNumeric="true" takesValue="true" unitClass="jerk">
+                  <name>#</name>
+               </node>
+            </node>
+            <node requireChild="true">
+               <name>Sampling-rate</name>
+               <description>Number of measurements per unit time.</description>
+               <node takesValue="true" unitClass="frequency">
+                  <name>#</name>
+               </node>
+            </node>
+            <node requireChild="true">
+               <name>Refresh-rate</name>
+               <description>Number of times per second a device displays an image. Also known as the frame rate.</description>
+               <node isNumeric="true" takesValue="true">
+                  <name>#</name>
+               </node>
+            </node>
+            <node>
+               <name>Temporal-rate</name>
+               <description>Number of occurrences in a unit of time.</description>
+               <node isNumeric="true" takesValue="true">
+                  <name>#</name>
+               </node>
+            </node>
+            <node>
+               <name>Velocity</name>
+               <node isNumeric="true" takesValue="true" unitClass="speed">
+                  <name>#</name>
+               </node>
+            </node>
          </node>
          <node>
-            <name>Instrument-measurement</name>
+            <name>Resolution</name>
+            <node>
+               <name>IO-resolution</name>
+               <node>
+                  <name>Screen-resolution</name>
+                  <description>Number of pixels in each dimension for a digital display device.</description>
+                  <node takesValue="true">
+                     <name>#</name>
+                  </node>
+               </node>
+               <node>
+                  <name>Printer-resolution</name>
+                  <description>Number of dots-per-inch for a printer.</description>
+                  <node takesValue="true">
+                     <name>#</name>
+                  </node>
+               </node>
+            </node>
+            <node>
+               <name>Spatial-resolution</name>
+               <description>Linear spacing of a spatial measurement.</description>
+               <node takesValue="true">
+                  <name>#</name>
+               </node>
+            </node>
+            <node>
+               <name>Spectral-resolution</name>
+               <node takesValue="true">
+                  <name>#</name>
+               </node>
+            </node>
+            <node>
+               <name>Temporal-resolution</name>
+               <node takesValue="true">
+                  <name>#</name>
+               </node>
+            </node>
+         </node>
+         <node>
+            <name>Spatial</name>
+            <node>
+               <name>Direction</name>
+               <node isNumeric="true" takesValue="true">
+                  <name>#</name>
+               </node>
+            </node>
+            <node>
+               <name>Distance</name>
+               <description>Distance from a specified position in a specified Direction or grouped with an item from which the distance is measured.</description>
+               <node isNumeric="true" takesValue="true" unitClass="physicalLength">
+                  <name>#</name>
+               </node>
+            </node>
+            <node>
+               <name>Orientation</name>
+               <node isNumeric="true" takesValue="true">
+                  <name>#</name>
+               </node>
+            </node>
+            <node>
+               <name>Position</name>
+               <description>Coordinates with respect a specified frame of reference or the default Screen-frame if no frame is given.</description>
+               <node>
+                  <name>X-position</name>
+                  <node isNumeric="true" takesValue="true" unitClass="physicalLength">
+                     <name>#</name>
+                  </node>
+               </node>
+               <node>
+                  <name>Y-position</name>
+                  <node isNumeric="true" takesValue="true" unitClass="physicalLength">
+                     <name>#</name>
+                  </node>
+               </node>
+               <node>
+                  <name>Z-position</name>
+                  <node isNumeric="true" takesValue="true" unitClass="physicalLength">
+                     <name>#</name>
+                  </node>
+               </node>
+            </node>
+            <node>
+               <name>Reference-frame</name>
+               <description>A frame of reference used to express spatial attributes.</description>
+               <node>
+                  <name>Custom-frame</name>
+                  <description>A custom frame of reference which should be defined in terms of one of the default frames of reference or by a library.</description>
+               </node>
+               <node>
+                  <name>Room-frame</name>
+               </node>
+               <node>
+                  <name>Screen-frame</name>
+                  <description>HED default frame of reference with origin at center of screen used to display experimental stimuli. Looking out of the screen has +X is horizontal to the right. +Y is up and +Z is out of the front of the screen.</description>
+               </node>
+               <node>
+                  <name>Screen-facing-frame</name>
+                  <description>HED default frame of reference with origin at the subject Nasion. +X is horizontal to the subject right. +Y is to the subject front and +Z is vertical upward.</description>
+               </node>
+               <node>
+                  <name>World-frame</name>
+               </node>
+            </node>
+            <node>
+               <name>Size</name>
+               <node>
+                  <name>Area</name>
+                  <node isNumeric="true" takesValue="true" unitClass="area">
+                     <name>#</name>
+                  </node>
+               </node>
+               <node>
+                  <name>Length</name>
+                  <description>A measurement of the size along the longest dimension.</description>
+                  <node isNumeric="true" takesValue="true" unitClass="physicalLength">
+                     <name>#</name>
+                  </node>
+               </node>
+               <node>
+                  <name>Width</name>
+                  <description>A measurement along the shortest of two or three dimensions.</description>
+                  <node isNumeric="true" takesValue="true" unitClass="physicalLength">
+                     <name>#</name>
+                  </node>
+               </node>
+               <node>
+                  <name>Height</name>
+                  <description>A measurement in a direction perpendicular to Length and Width in 3D. In 2D, it is perpendicular to both the Length and Height.</description>
+                  <node isNumeric="true" takesValue="true" unitClass="physicalLength">
+                     <name>#</name>
+                  </node>
+               </node>
+               <node>
+                  <name>Volume</name>
+                  <node isNumeric="true" takesValue="true" unitClass="volume">
+                     <name>#</name>
+                  </node>
+               </node>
+            </node>
+            <node>
+               <name>Surface-properties</name>
+               <node>
+                  <name>Rough</name>
+               </node>
+               <node>
+                  <name>Smooth</name>
+               </node>
+            </node>
+         </node>
+         <node>
+            <name>Temporal</name>
+            <node>
+               <name>Delay</name>
+               <description>An indicator that the associated tag group represents something temporally offset from the current event. The delay value can be positive or negative and should always appear in a tag group indicating what is delayed.</description>
+               <node isNumeric="true" takesValue="true" unitClass="time">
+                  <name>#</name>
+               </node>
+            </node>
+            <node>
+               <name>Duration</name>
+               <description>Time extent of something.</description>
+               <node isNumeric="true" takesValue="true" unitClass="time">
+                  <name>#</name>
+               </node>
+            </node>
+            <node>
+               <name>Onset</name>
+            </node>
+            <node>
+               <name>Offset</name>
+            </node>
+            <node>
+               <name>Pause</name>
+               <description>Indicating something stopped such as a break or waiting for input.</description>
+            </node>
+            <node>
+               <name>Temporal-value</name>
+               <node isNumeric="true" takesValue="true" unitClass="time">
+                  <name>#</name>
+               </node>
+            </node>
+            <node>
+               <name>Time-out</name>
+            </node>
+            <node>
+               <name>Time-sync</name>
+               <description>Indicates a marker inserted into the recorded data to allow post hoc synchronization of concurrently recorded data streams.</description>
+            </node>
          </node>
       </node>
-      <node>
-         <name>Computed-property</name>
-         <description>Feature computed by tool. Should be grouped with a label of the form Toolname_propertyName</description>
+      <node extensionAllowed="true">
+         <name>Statistical-property</name>
          <node>
-            <name>Computed-prediction</name>
+            <name>Accuracy</name>
+         </node>
+         <node>
+            <name>Data-mean</name>
+         </node>
+         <node>
+            <name>Data-median</name>
+         </node>
+         <node>
+            <name>Data-minimum</name>
+         </node>
+         <node>
+            <name>Data-maximum</name>
+         </node>
+         <node>
+            <name>Probability</name>
+            <description>Use to specify the level of certainty about the occurrence of the event.</description>
+         </node>
+         <node>
+            <name>Statistical-precision</name>
+         </node>
+         <node>
+            <name>Statistical-recall</name>
+         </node>
+         <node>
+            <name>Standard-deviation</name>
+         </node>
+         <node>
+            <name>Uncertainty</name>
+            <description>Use to specify the level of error.</description>
          </node>
       </node>
    </node>
@@ -1278,12 +1723,15 @@
          </node>
       </node>
       <node>
-         <name>Task-event-type</name>
+         <name>Task-role</name>
+         <description>The purpose with respect to the task.</description>
          <node>
             <name>Activity</name>
+            <description>Something that is part of the overall task or is necessary to the overall experiment but is not directly part of a stimulus-response cycle. Examples would be taking a survey or provided providing a silva sample.</description>
          </node>
          <node>
-            <name>Background-task</name>
+            <name>Background-subtask</name>
+            <description>A part of the task which should be performed in the background.</description>
          </node>
          <node>
             <name>Experimental-stimulus</name>
@@ -1292,14 +1740,13 @@
          <node>
             <name>Failure</name>
          </node>
-         <node>
-            <name>Feedback</name>
-         </node>
          <node>
             <name>Incidental</name>
+            <description>Usually associated with a sensory event intended to give instructions to the participant about the task or behavior.</description>
          </node>
          <node>
             <name>Instructional</name>
+            <description>Usually associated with a sensory event intended to give instructions to the participant about the task or behavior.</description>
          </node>
          <node>
             <name>Mishap</name>
@@ -1307,22 +1754,24 @@
          </node>
          <node>
             <name>Participant-response</name>
-            <description>Something related to a participant's actions in performing the task.</description>
+            <description>Something related to a participant actions in performing the task.</description>
          </node>
          <node>
-            <name>Primary-task</name>
+            <name>Primary-subtask</name>
+            <description>A part of the task which should be the primary focus of the participant.</description>
          </node>
          <node>
             <name>Warning</name>
-            <description>As in a warning message that you are getting too close to the shoulder in a driving task</description>
+            <description>Something that should warn the participant that the parameters of the task have been or are about to be exceeded such as a warning message about getting too close to the shoulder of the road in a driving task.</description>
          </node>
       </node>
       <node>
          <name>Task-response-type</name>
-         <node>
+         <description>How the participant response should be interpreted in terms of the task specification.</description>
+         <node relatedTag="Inappropriate">
             <name>Appropriate</name>
          </node>
-         <node>
+         <node relatedTag="Successful">
             <name>Correction</name>
          </node>
          <node>
@@ -1330,26 +1779,27 @@
          </node>
          <node>
             <name>Imagined</name>
-            <description>This is used to identity that the (sub)event only happened in the imagination of the participant, e.g.  imagined movements in motor imagery paradigms.</description>
+            <description>This is used to identity something that only happened in the imagination of the participant as in imagined movements in motor imagery paradigms.</description>
          </node>
-         <node>
+         <node relatedTag="Appropriate">
             <name>Inappropriate</name>
          </node>
-         <node>
+         <node relatedTag="Near-miss">
             <name>Indeterminate</name>
          </node>
-         <node>
+         <node relatedTag="Near-miss">
             <name>Missed</name>
          </node>
-         <node>
+         <node relatedTag="Miss">
             <name>Near-miss</name>
          </node>
-         <node>
+         <node relatedTag="Correction">
             <name>Successful</name>
          </node>
       </node>
       <node>
          <name>Task-stimulus-type</name>
+         <description>The stimulus purpose in the task.</description>
          <node>
             <name>Cue</name>
          </node>
@@ -1358,11 +1808,14 @@
          </node>
          <node>
             <name>Expected</name>
-            <description>Of low information value, for example frequent Non-targets in an RSVP paradigm</description>
+            <description>Of low information value as in frequent non-targets in an RSVP paradigm.</description>
          </node>
          <node>
             <name>Extraneous</name>
          </node>
+         <node>
+            <name>Feedback</name>
+         </node>
          <node>
             <name>Meaningful</name>
          </node>
@@ -1391,13 +1844,13 @@
             <name>Planned</name>
          </node>
          <node>
-            <name>Penalizing</name>
+            <name>Penalty</name>
          </node>
          <node>
             <name>Priming</name>
          </node>
          <node>
-            <name>Rewarding</name>
+            <name>Reward</name>
          </node>
          <node>
             <name>Signal-go</name>
@@ -1410,7 +1863,7 @@
             <description>Something the subject is looking for</description>
          </node>
          <node>
-            <name>Threatening</name>
+            <name>Threat</name>
          </node>
          <node>
             <name>Timed</name>
@@ -1422,48 +1875,48 @@
    </node>
    <node extensionAllowed="true">
       <name>Attribute</name>
-      <description>Vocabulary tree for properties.</description>
+      <description>Subtree tree for general properties.</description>
       <node>
          <name>Informational</name>
          <description>Informational properties.</description>
          <node requireChild="true">
-            <name>Label</name>
-            <description>A string of 20 or fewer characters identifying something. Labels usually refer to general classes of things while IDs refer to specific instances.</description>
+            <name>Def</name>
+            <description>A label that specifically corresponds to a Definition name and indicates that this label represents tags in an unexpanded definition.</description>
             <node takesValue="true">
                <name>#</name>
             </node>
          </node>
          <node requireChild="true">
-            <name>Label-def</name>
-            <description>A label that specifically corresponds to a Definition name and indicates that this label represents tags in an unexpanded definition.</description>
+            <name>Defexp</name>
+            <description>A label that specifically corresponds to a Definition name and indicates that this label is in a group containing an expanded definition and should not be expanded again.</description>
             <node takesValue="true">
                <name>#</name>
             </node>
          </node>
          <node requireChild="true">
-            <name>Label-exp</name>
-            <description>A label that specifically corresponds to a Definition name and indicates that this label is in a group containing an expanded definition.</description>
+            <name>Definition</name>
+            <description>A tag used within a tag group also containing a Label tag to indicate that the Label represents that group of tags.</description>
             <node takesValue="true">
                <name>#</name>
             </node>
          </node>
          <node requireChild="true">
-            <name>ID</name>
-            <description>An alphanumeric code usually used to identify a particular instance of an item.</description>
+            <name>Description</name>
+            <description>Human-readable text description of the event.</description>
             <node takesValue="true">
                <name>#</name>
             </node>
          </node>
          <node requireChild="true">
-            <name>Description</name>
-            <description>Human-readable text description of the event.</description>
+            <name>ID</name>
+            <description>An alphanumeric code usually used to identify a particular instance of an item.</description>
             <node takesValue="true">
                <name>#</name>
             </node>
          </node>
-         <node>
-            <name>Definition</name>
-            <description>A tag used within a tag group also containing a Label tag to indicate that the Label represents that group of tags.</description>
+         <node requireChild="true">
+            <name>Label</name>
+            <description>A string of 20 or fewer characters identifying something. Labels usually refer to general classes of things while IDs refer to specific instances.</description>
             <node takesValue="true">
                <name>#</name>
             </node>
@@ -1471,32 +1924,46 @@
          <node>
             <name>Metadata</name>
             <description>A tag used within a tag group indicate to designate information about the data such as file size or author.</description>
-            <node requireChild="true">
+            <node>
+               <name>CogAtlas</name>
+               <description>A tag used within a tag group indicate a relationship to the CognitiveAtlas terminology.</description>
+               <node takesValue="true">
+                  <name>#</name>
+               </node>
+            </node>
+            <node>
+               <name>CogPo</name>
+               <description>A tag used within a tag group indicate a relationship to the CogPO terminology.</description>
+               <node takesValue="true">
+                  <name>#</name>
+               </node>
+            </node>
+            <node>
                <name>Creation-date</name>
                <node takesValue="true" unitClass="datetime">
                   <name>#</name>
                </node>
             </node>
-            <node requireChild="true">
+            <node>
                <name>Library-name</name>
                <node takesValue="true">
                   <name>#</name>
                </node>
             </node>
-            <node requireChild="true">
+            <node>
                <name>Subject</name>
                <node takesValue="true">
                   <name>#</name>
                </node>
             </node>
-            <node requireChild="true">
+            <node>
                <name>Version</name>
                <node takesValue="true">
                   <name>#</name>
                </node>
             </node>
          </node>
-         <node requireChild="true">
+         <node>
             <name>Parameter</name>
             <description>As a Name:Value</description>
             <node takesValue="true">
@@ -1506,61 +1973,50 @@
       </node>
       <node>
          <name>Organizational</name>
-         <node>
-            <name>Block</name>
-            <description>An event used to indicate a particular organizational part in the experimental design or plan. Usually the Block tag is used with scoping tags as well as tags describing what the block represents to assist with downstream analysis.</description>
-         </node>
          <node>
             <name>Collection</name>
             <description>A tag designating a grouping of items such as in a set or list.</description>
          </node>
          <node>
-            <name>Context</name>
+            <name>Event-context</name>
             <description>A tag indicating the overall environment and setup of the experiment or a portion of the experiment. This event is often inserted into a recording at the beginning of an experimental record to describe information such as whether the experiment is conducted indoors or outdoors or whether the experiment is conducted in the real-world or in a controlled laboratory setting. Tags specifying subject metadata might also be included.</description>
          </node>
-         <node>
-            <name>Condition-variable</name>
-            <description>An aspect of the experiment or task that is to be varied during the experiment. Condition-variables are sometimes called independent variables.</description>
-         </node>
-         <node>
-            <name>Control-variable</name>
-            <description>An aspect of the experiment that is fixed throughout the study and usually is explicitly controlled.</description>
-         </node>
-         <node>
-            <name>Data-acquisition</name>
-            <description>An activity related to data acquisition.</description>
-         </node>
          <node>
             <name>Event-stream</name>
             <description>An ordered list of events</description>
          </node>
-         <node>
-            <name>Namespace</name>
-            <description>Tag used to indicate a namespace type of definition.</description>
-         </node>
          <node>
             <name>Permutation</name>
             <description>A tag used within a tag group also containing a Label tag to indicate that the Label represents events that are permutations of each other.</description>
          </node>
          <node>
-            <name>Response-variable</name>
-            <description>An aspect of the experiment or task that is measured as control-variables are varied during the experiment. Response-variables are sometimes called dependent variables.</description>
+            <name>Recording</name>
+            <description>Indicates an uninterrupted block of time during which data was acquired using a fixed scanning protocol or sensor positioning. Recording tags are usually have temporal scope which is the entire recording.</description>
          </node>
          <node>
-            <name>Sequence</name>
-            <description>A tag used within a tag group also containing a Label tag to indicate that the Label represents events related in a sequential order.</description>
+            <name>Task</name>
+            <description>A tag used to indicate a linkage the structured activities performed as part of the experiment.</description>
          </node>
          <node>
-            <name>Session</name>
+            <name>Task-condition</name>
+            <description>An aspect of the experiment or task that is to be varied during the experiment. Task-conditions are sometimes called independent variables or contrasts.</description>
          </node>
          <node>
-            <name>Task</name>
-            <description>A tag used to indicate a linkage to the task.</description>
+            <name>Task-control</name>
+            <description>An aspect of the experiment that is fixed throughout the study and usually is explicitly controlled.</description>
          </node>
          <node>
-            <name>Trial</name>
+            <name>Task-response</name>
+            <description>An aspect of the experiment or task that is measured as task conditions are varied during the experiment. Task-responses are sometimes called dependent variables.</description>
+         </node>
+         <node>
+            <name>Task-trial</name>
             <description>A tag used to indicate a particular organizational part in the experimental design often containing a stimulus-response pair.</description>
          </node>
+         <node>
+            <name>Time-block</name>
+            <description>A tag used to indicate a contiguous time block in the experiment during which something is fixed or noted.</description>
+         </node>
       </node>
       <node extensionAllowed="true">
          <name>Relational</name>
@@ -1838,7 +2294,7 @@
                </node>
                <node>
                   <name>Flickering</name>
-                  <description>Irregular changes in time</description>
+                  <description>Irregular changes in time.</description>
                </node>
                <node>
                   <name>Fractal</name>
@@ -1854,71 +2310,22 @@
                </node>
                <node>
                   <name>Varying</name>
-               </node>
-            </node>
-         </node>
-         <node>
-            <name>Thermal-relation</name>
-            <node>
-               <name>Cold</name>
-            </node>
-            <node>
-               <name>Colder-than</name>
-            </node>
-            <node>
-               <name>Hot</name>
-            </node>
-            <node>
-               <name>Hotter-than</name>
-            </node>
-         </node>
-      </node>
-      <node extensionAllowed="true">
-         <name>Quantitative</name>
-         <node requireChild="true">
-            <name>Angle</name>
-            <description>Angle assumed clockwise from vertical unless grouped with axis.</description>
-            <node takesValue="true">
-               <name>#</name>
-            </node>
-         </node>
-         <node requireChild="true">
-            <name>Fraction</name>
-            <description>Fraction of items of a particular type.</description>
-            <node takesValue="true">
-               <name>#</name>
+               </node>
             </node>
          </node>
          <node>
-            <name>Interval</name>
-            <node takesValue="true">
-               <name>#</name>
-            </node>
-         </node>
-         <node requireChild="true">
-            <name>Item-count</name>
-            <node takesValue="true">
-               <name>#</name>
+            <name>Thermal-relation</name>
+            <node>
+               <name>Cold</name>
             </node>
-         </node>
-         <node requireChild="true">
-            <name>Percentage</name>
-            <description>Percentage of items of a particular type.</description>
-            <node takesValue="true">
-               <name>#</name>
+            <node>
+               <name>Colder-than</name>
             </node>
-         </node>
-         <node requireChild="true">
-            <name>Ratio</name>
-            <node takesValue="true">
-               <name>#</name>
+            <node>
+               <name>Hot</name>
             </node>
-         </node>
-         <node requireChild="true">
-            <name>Repetition</name>
-            <description>When the same type of event such as a fixation on the exact same object happens multiple times and it might be necessary to distinguish the first look vs. others</description>
-            <node takesValue="true">
-               <name>#</name>
+            <node>
+               <name>Hotter-than</name>
             </node>
          </node>
       </node>
@@ -1951,8 +2358,13 @@
          <node relatedTag="True">
             <name>False</name>
          </node>
-         <node relatedTag="Unfamiliar">
+         <node relatedTag="Famous">
             <name>Familiar</name>
+            <description>Something known or encountered before.</description>
+         </node>
+         <node relatedTag="Unfamiliar">
+            <name>Famous</name>
+            <description>Something known by many people but necessarily because of direct contact.</description>
          </node>
          <node relatedTag="Medium">
             <name>High</name>
@@ -2018,8 +2430,9 @@
          <node relatedTag="Constrained">
             <name>Unconstrained</name>
          </node>
-         <node relatedTag="Familiar">
+         <node relatedTag="Famous">
             <name>Unfamiliar</name>
+            <description>Something not known or encountered before.</description>
          </node>
          <node>
             <name>Unmasked</name>
@@ -2038,9 +2451,6 @@
          <node>
             <name>Abstract</name>
          </node>
-         <node>
-            <name>Biological</name>
-         </node>
          <node>
             <name>Clinical</name>
          </node>
@@ -2050,15 +2460,6 @@
          <node>
             <name>Composite</name>
          </node>
-         <node>
-            <name>Electrical</name>
-         </node>
-         <node>
-            <name>Mechanical</name>
-         </node>
-         <node>
-            <name>Magnetic</name>
-         </node>
          <node>
             <name>Numerical</name>
          </node>
@@ -2073,13 +2474,13 @@
             <node>
                <name>Audible</name>
             </node>
-            <node requireChild="true">
+            <node>
                <name>Frequency</name>
                <node isNumeric="true" takesValue="true" unitClass="frequency">
                   <name>#</name>
                </node>
             </node>
-            <node requireChild="true">
+            <node>
                <name>Loudness</name>
                <node isNumeric="true" takesValue="true">
                   <name>#</name>
@@ -2160,10 +2561,10 @@
          </node>
          <node>
             <name>Visual</name>
-            <node requireChild="true">
+            <node>
                <name>Luminance</name>
             </node>
-            <node requireChild="true">
+            <node>
                <name>Color</name>
                <node>
                   <name>Color-shade</name>
@@ -2652,338 +3053,87 @@
                      <node>
                         <name>Azure</name>
                      </node>
-                     <node>
-                        <name>AliceBlue</name>
-                     </node>
-                     <node>
-                        <name>GhostWhite</name>
-                     </node>
-                     <node>
-                        <name>WhiteSmoke</name>
-                     </node>
-                     <node>
-                        <name>SeaShell</name>
-                     </node>
-                     <node>
-                        <name>Beige</name>
-                     </node>
-                     <node>
-                        <name>OldLace</name>
-                     </node>
-                     <node>
-                        <name>FloralWhite</name>
-                     </node>
-                     <node>
-                        <name>Ivory</name>
-                     </node>
-                     <node>
-                        <name>AntiqueWhite</name>
-                     </node>
-                     <node>
-                        <name>Linen</name>
-                     </node>
-                     <node>
-                        <name>LavenderBlush</name>
-                     </node>
-                     <node>
-                        <name>MistyRose</name>
-                     </node>
-                  </node>
-               </node>
-            </node>
-            <node>
-               <name>View</name>
-               <node>
-                  <name>2D-view</name>
-               </node>
-               <node>
-                  <name>3D-view</name>
-               </node>
-               <node>
-                  <name>Background-view</name>
-               </node>
-               <node>
-                  <name>Bistable-view</name>
-                  <description>Something having two stable visual forms that have two distinguishable stable forms as in optical illusions.</description>
-               </node>
-               <node>
-                  <name>Foreground-view</name>
-               </node>
-               <node>
-                  <name>Foveal-view</name>
-                  <description>Visual presentation directly on the fovea.</description>
-               </node>
-               <node>
-                  <name>Map-view</name>
-                  <description>A representation of a geographical location.</description>
-                  <node>
-                     <name>Aerial-view</name>
-                     <description>A representation from an overhead view such as captured by a drone.</description>
-                  </node>
-                  <node>
-                     <name>Satellite-view</name>
-                     <description>A representation as captured by technology such as a satellite.</description>
-                  </node>
-                  <node>
-                     <name>Street-view</name>
-                     <description>A panoramic view from a position on the ground.</description>
-                  </node>
-               </node>
-               <node>
-                  <name>Peripheral-view</name>
-               </node>
-            </node>
-         </node>
-      </node>
-      <node extensionAllowed="true">
-         <name>Spatiotemporal</name>
-         <node>
-            <name>Rate-of-change</name>
-            <node>
-               <name>Acceleration</name>
-               <node isNumeric="true" takesValue="true" unitClass="acceleration">
-                  <name>#</name>
-               </node>
-            </node>
-            <node>
-               <name>Jerk-rate</name>
-               <description>Rate at which an object's acceleration changes with respect to time.</description>
-               <node isNumeric="true" takesValue="true" unitClass="jerk">
-                  <name>#</name>
-               </node>
-            </node>
-            <node requireChild="true">
-               <name>Sampling-rate</name>
-               <description>Number of measurements per unit time.</description>
-               <node takesValue="true" unitClass="frequency">
-                  <name>#</name>
-               </node>
-            </node>
-            <node requireChild="true">
-               <name>Refresh-rate</name>
-               <description>Number of times per second a device displays an image. Also known as the frame rate.</description>
-               <node isNumeric="true" takesValue="true">
-                  <name>#</name>
-               </node>
-            </node>
-            <node>
-               <name>Temporal-rate</name>
-               <description>Number of occurrences in a unit of time.</description>
-               <node isNumeric="true" takesValue="true">
-                  <name>#</name>
-               </node>
-            </node>
-            <node>
-               <name>Velocity</name>
-               <node isNumeric="true" takesValue="true" unitClass="speed">
-                  <name>#</name>
-               </node>
-            </node>
-         </node>
-         <node>
-            <name>Resolution</name>
-            <node requireChild="true">
-               <name>IO-resolution</name>
-               <node requireChild="true">
-                  <name>Screen-resolution</name>
-                  <description>Number of pixels in each dimension for a digital display device.</description>
-                  <node takesValue="true">
-                     <name>#</name>
-                  </node>
-               </node>
-               <node requireChild="true">
-                  <name>Printer-resolution</name>
-                  <description>Number of dots-per-inch for a printer.</description>
-                  <node takesValue="true">
-                     <name>#</name>
-                  </node>
-               </node>
-            </node>
-            <node requireChild="true">
-               <name>Spatial-resolution</name>
-               <description>Linear spacing of a spatial measurement.</description>
-               <node takesValue="true">
-                  <name>#</name>
-               </node>
-            </node>
-            <node requireChild="true">
-               <name>Spectral-resolution</name>
-               <node takesValue="true">
-                  <name>#</name>
-               </node>
-            </node>
-            <node requireChild="true">
-               <name>Temporal-resolution</name>
-               <node takesValue="true">
-                  <name>#</name>
-               </node>
-            </node>
-         </node>
-         <node>
-            <name>Spatial</name>
-            <node>
-               <name>Direction</name>
-               <node isNumeric="true" takesValue="true">
-                  <name>#</name>
-               </node>
-            </node>
-            <node requireChild="true">
-               <name>Distance</name>
-               <description>Distance from a specified position in a specified Direction or grouped with an item from which the distance is measured.</description>
-               <node isNumeric="true" takesValue="true" unitClass="physicalLength">
-                  <name>#</name>
-               </node>
-            </node>
-            <node>
-               <name>Orientation</name>
-               <node isNumeric="true" takesValue="true">
-                  <name>#</name>
-               </node>
-            </node>
-            <node requireChild="true">
-               <name>Position</name>
-               <description>Coordinates with respect a specified frame of reference or the default Screen-frame if no frame is given.</description>
-               <node requireChild="true">
-                  <name>X-position</name>
-                  <node isNumeric="true" takesValue="true" unitClass="physicalLength">
-                     <name>#</name>
-                  </node>
-               </node>
-               <node requireChild="true">
-                  <name>Y-position</name>
-                  <node isNumeric="true" takesValue="true" unitClass="physicalLength">
-                     <name>#</name>
-                  </node>
-               </node>
-               <node requireChild="true">
-                  <name>Z-position</name>
-                  <node isNumeric="true" takesValue="true" unitClass="physicalLength">
-                     <name>#</name>
+                     <node>
+                        <name>AliceBlue</name>
+                     </node>
+                     <node>
+                        <name>GhostWhite</name>
+                     </node>
+                     <node>
+                        <name>WhiteSmoke</name>
+                     </node>
+                     <node>
+                        <name>SeaShell</name>
+                     </node>
+                     <node>
+                        <name>Beige</name>
+                     </node>
+                     <node>
+                        <name>OldLace</name>
+                     </node>
+                     <node>
+                        <name>FloralWhite</name>
+                     </node>
+                     <node>
+                        <name>Ivory</name>
+                     </node>
+                     <node>
+                        <name>AntiqueWhite</name>
+                     </node>
+                     <node>
+                        <name>Linen</name>
+                     </node>
+                     <node>
+                        <name>LavenderBlush</name>
+                     </node>
+                     <node>
+                        <name>MistyRose</name>
+                     </node>
                   </node>
                </node>
             </node>
             <node>
-               <name>Reference-frame</name>
-               <description>A frame of reference used to express spatial attributes.</description>
+               <name>View</name>
                <node>
-                  <name>Custom-frame</name>
-                  <description>A custom frame of reference which should be defined in terms of one of the default frames of reference or by a library.</description>
+                  <name>2D-view</name>
                </node>
                <node>
-                  <name>Room-frame</name>
+                  <name>3D-view</name>
                </node>
                <node>
-                  <name>Screen-frame</name>
-                  <description>HED default frame of reference with origin at center of screen used to display experimental stimuli. Looking out of the screen has +X is horizontal to the right. +Y is up and +Z is out of the front of the screen.</description>
+                  <name>Background-view</name>
                </node>
                <node>
-                  <name>Screen-facing-frame</name>
-                  <description>HED default frame of reference with origin at the subject Nasion. +X is horizontal to the subject right. +Y is to the subject front and +Z is vertical upward.</description>
+                  <name>Bistable-view</name>
+                  <description>Something having two stable visual forms that have two distinguishable stable forms as in optical illusions.</description>
                </node>
                <node>
-                  <name>World-frame</name>
-               </node>
-            </node>
-            <node requireChild="true">
-               <name>Size</name>
-               <node requireChild="true">
-                  <name>Area</name>
-                  <node isNumeric="true" takesValue="true" unitClass="area">
-                     <name>#</name>
-                  </node>
-               </node>
-               <node requireChild="true">
-                  <name>Length</name>
-                  <description>A measurement of the size along the longest dimension.</description>
-                  <node isNumeric="true" takesValue="true" unitClass="physicalLength">
-                     <name>#</name>
-                  </node>
+                  <name>Foreground-view</name>
                </node>
                <node>
-                  <name>Width</name>
-                  <description>A measurement along the shortest of two or three dimensions.</description>
-                  <node isNumeric="true" takesValue="true" unitClass="physicalLength">
-                     <name>#</name>
-                  </node>
+                  <name>Foveal-view</name>
+                  <description>Visual presentation directly on the fovea.</description>
                </node>
                <node>
-                  <name>Height</name>
-                  <description>A measurement in a direction perpendicular to Length and Width in 3D. In 2D, it is perpendicular to both the Length and Height.</description>
-                  <node isNumeric="true" takesValue="true" unitClass="physicalLength">
-                     <name>#</name>
+                  <name>Map-view</name>
+                  <description>A representation of a geographical location.</description>
+                  <node>
+                     <name>Aerial-view</name>
+                     <description>A representation from an overhead view such as captured by a drone.</description>
                   </node>
-               </node>
-               <node requireChild="true">
-                  <name>Volume</name>
-                  <node isNumeric="true" takesValue="true" unitClass="volume">
-                     <name>#</name>
+                  <node>
+                     <name>Satellite-view</name>
+                     <description>A representation as captured by technology such as a satellite.</description>
+                  </node>
+                  <node>
+                     <name>Street-view</name>
+                     <description>A panoramic view from a position on the ground.</description>
                   </node>
-               </node>
-            </node>
-            <node>
-               <name>Surface-properties</name>
-               <node>
-                  <name>Rough</name>
                </node>
                <node>
-                  <name>Smooth</name>
-               </node>
-            </node>
-         </node>
-         <node>
-            <name>Temporal</name>
-            <node requireChild="true">
-               <name>Delay</name>
-               <description>An indicator that the associated tag group represents something temporally offset from the current event. The delay value can be positive or negative and should always appear in a tag group indicating what is delayed.</description>
-               <node isNumeric="true" takesValue="true" unitClass="time">
-                  <name>#</name>
-               </node>
-            </node>
-            <node requireChild="true">
-               <name>Duration</name>
-               <description>An offset that is implicit after duration time passed from the onset.</description>
-               <node isNumeric="true" takesValue="true" unitClass="time">
-                  <name>#</name>
-               </node>
-            </node>
-            <node>
-               <name>Onset</name>
-            </node>
-            <node>
-               <name>Offset</name>
-            </node>
-            <node>
-               <name>Pause</name>
-               <description>Indicating something stopped such as a break or waiting for input.</description>
-            </node>
-            <node requireChild="true">
-               <name>Temporal-value</name>
-               <node isNumeric="true" takesValue="true" unitClass="time">
-                  <name>#</name>
+                  <name>Peripheral-view</name>
                </node>
             </node>
-            <node>
-               <name>Time-out</name>
-            </node>
-            <node>
-               <name>Time-sync</name>
-               <description>Indicates a marker inserted into the recorded data to allow post hoc synchronization of concurrently recorded data streams.</description>
-            </node>
-         </node>
-      </node>
-      <node>
-         <name>Thermodynamic</name>
-         <node>
-            <name>Energy</name>
-         </node>
-         <node>
-            <name>Pressure</name>
-         </node>
-         <node>
-            <name>Temperature</name>
-            <node isNumeric="true" takesValue="true">
-               <name>#</name>
-            </node>
          </node>
       </node>
       <node extensionAllowed="true">
@@ -3051,111 +3201,6 @@
       </node>
       <node>
          <name>Anatomical</name>
-         <node>
-            <name>Body-part</name>
-            <node>
-               <name>Head</name>
-               <node>
-                  <name>Hair</name>
-               </node>
-               <node>
-                  <name>Ear</name>
-               </node>
-               <node>
-                  <name>Face</name>
-                  <node>
-                     <name>Cheek</name>
-                  </node>
-                  <node>
-                     <name>Chin</name>
-                  </node>
-                  <node>
-                     <name>Eye</name>
-                  </node>
-                  <node>
-                     <name>Eyebrow</name>
-                  </node>
-                  <node>
-                     <name>Forehead</name>
-                  </node>
-                  <node>
-                     <name>Lip</name>
-                  </node>
-                  <node>
-                     <name>Nose</name>
-                  </node>
-                  <node>
-                     <name>Mouth</name>
-                  </node>
-                  <node>
-                     <name>Teeth</name>
-                  </node>
-               </node>
-            </node>
-            <node>
-               <name>Arm</name>
-               <node>
-                  <name>Elbow</name>
-               </node>
-               <node>
-                  <name>Hand</name>
-                  <node>
-                     <name>Finger</name>
-                     <node>
-                        <name>Index-finger</name>
-                     </node>
-                     <node>
-                        <name>Little-finger</name>
-                     </node>
-                     <node>
-                        <name>Middle-finger</name>
-                     </node>
-                     <node>
-                        <name>Ring-finger</name>
-                     </node>
-                     <node>
-                        <name>Thumb</name>
-                     </node>
-                  </node>
-               </node>
-               <node>
-                  <name>Wrist</name>
-               </node>
-            </node>
-            <node>
-               <name>Leg</name>
-               <node>
-                  <name>Ankle</name>
-               </node>
-               <node>
-                  <name>Foot</name>
-                  <node>
-                     <name>Toe</name>
-                  </node>
-               </node>
-               <node>
-                  <name>Knee</name>
-               </node>
-            </node>
-            <node>
-               <name>Torso</name>
-               <node>
-                  <name>Upper-torso</name>
-                  <node>
-                     <name>Chest</name>
-                  </node>
-               </node>
-               <node>
-                  <name>Lower-torso</name>
-                  <node>
-                     <name>Hips</name>
-                  </node>
-               </node>
-               <node>
-                  <name>Waist</name>
-               </node>
-            </node>
-         </node>
       </node>
    </node>
    <unitClasses>
diff --git a/hedweb/tests/data/ValidTwoColumnHED7_1_1.tsv b/hedweb/tests/data/ValidTwoColumnHED7_1_1.tsv
new file mode 100644
index 000000000..db7629c10
--- /dev/null
+++ b/hedweb/tests/data/ValidTwoColumnHED7_1_1.tsv
@@ -0,0 +1,5 @@
+Column1: Event Code	Column2: Combined tag
+1250	Event/Label/StartAreaE, Event/Category/Experiment control/Sequence/Block/Guard Area E, Event/Description/Start guarding Area E
+1311	Event/Label/ValidImage, Event/Category/Experimental stimulus, Event/Description/Show a valid ID to be verified, Item/Object/IDCard, Sensory presentation/Visual, Participant/Effect/Visual, Participant/Effect/Cognitive/Valid
+2120	Event/Label/ButtonDeny, Event/Description/Button push to deny access to the ID holder, Event/Category/Participant response, (Participant ~ Action/Button press/Keyboard ~ Participant/Effect/Body part/Arm/Hand/Finger),  (Participant ~ Action/Deny ~ Item/Object/Person/IDHolder)
+3111	Event/Label/TakeSurvey, Event/Category/Experimental stimulus/Instruction, Event/Description/Tell subject to start survey
diff --git a/hedweb/tests/data/example_dictionary.json b/hedweb/tests/data/example_dictionary.json
new file mode 100644
index 000000000..0f817becd
--- /dev/null
+++ b/hedweb/tests/data/example_dictionary.json
@@ -0,0 +1,82 @@
+{
+    "onset": {
+        "Description": "Onset of the go signal which is the disappearance of the cue bar",
+        "Units": "s"
+    },
+    "duration": {
+        "Description": "Duration of the event",
+        "Units": "s"
+    },
+	"event-type": {
+		"Description": "Subject presses both buttons causing cue bar to start count-down display",
+		"Levels" : {
+            "cue": "Subject presses both buttons causing cue bar to start count-down display",
+            "go": "Bar disappears cueing the subject to make a choice about which hand to raise",
+            "right-raised": "Subject releases right button and raises right hand",
+            "left-raised": "Subject releases left button and raises left hand",
+            "left-raised-match": "Subject raised left hand and computer presented image of left hand.",
+            "left-raised-nomatch": "Subject raised left hand and computer presented image of right hand.",
+            "right-raised-match": "Subject raised right hand and computer presented image of right hand.",
+            "right-raised-nomatch": "Subject raised right hand and computer presented image of left hand."
+        },
+        "HED": {
+          "cue": "Description/Subject presses both buttons causing cue bar to start count-down display, (Sensory-event, Visual, Cue, ((Rectangle, (Position, (Center-of, Screen)), (Size, Decreasing)), Appear)), (Agent-action, Experiment-subject, (Press, Hold-down, (Left-side, Button)), (Press, Hold-down, (Right-side, Button)))",
+          "go": "Description/Onset of the go signal which is the disappearance of the cue bar, Sensory-event, Visual, Experimental-stimulus, Instructional, Signal-go,(Rectangle, Disappear)",
+          "right-raised": "Description/Subject raised right hand thereby releasing right button, (Agent-action, Experiment-subject, (Lift, (Right-side, Hand)), (Release, (Right-side, Button)))",
+          "left-raised": "Description/Subject raised left hand thereby releasing left button, (Agent-action, Experiment-subject, (Lift, (Left-side, Hand)), (Release, (Left-side, Button)))",
+          "left-raised-match": "Description/Computer presented image of left hand thereby matching a previously raised left hand, (Sensory-event, Visual, (Drawing, ID/left_hand.png,(Left-side, Hand)), (Feedback, (Intended-effect, Penalty)))",
+          "left-raised-nomatch": "Description/Computer presented image of left hand thereby not matching previously raised right hand, (Sensory-event, Visual, (Drawing, ID/right_hand.png, (Left-side, Hand)), (Feedback, (Intended-effect, Reward)))",
+          "right-raised-match": "Description/Computer presented image of right hand thereby matching a previously raised right hand, (Sensory-event, Visual, (Drawing, ID/right_hand.png,(Right-side, Hand)), (Feedback, (Intended-effect, Penalty)))",
+          "right-raised-nomatch": "Description/Computer presented image of right hand thereby not matching a previously raised left hand, (Sensory-event, Visual, (Drawing, ID/right_hand.png, (Right-side, Hand)), (Feedback, (Intended-effect, Reward)))"
+        }
+	},
+    "sample": {
+        "Description": "The sample within the EEG data at which an event occurred"
+    },
+    "stage": {
+        "Description": "The current stage of the experiment.",
+        "Levels": {
+            "1": "Stage 1. BCI acts randomly",
+            "2": "Stage 2. BCI was trained on data from stage 1.",
+            "3": "Stage 3. BCI was trained on data from stages 1 and 2."
+        },
+		"HED": {
+            "1": "Description/BCI acts randomly, (Definition/Random-selection, Condition-variable, (Random, Predict)), Label-def/Random-selection",
+            "2": "Description/BCI was trained on data from stage 1., (Definition/Trained-on-random, Condition-variable), Label-def/Trained-on-random",
+            "3": "Description/BCI was trained on data from stages 1 and 2., (Definition/Trained-on-all, Condition-variable), Label-def/Trained-on-all"
+		}
+    },
+	"trial": {
+		"Description": "The number of the trial in the experiment.",
+		"HED": "Description/The number of the trial in the experiment, (Trial, Item-count/#)"
+	},
+    "latency": {
+        "Description": "Estimated beginning of the data chunk used for the BCI prediction with respect to the true event as measured by parallel port trigger in this trial.",
+        "Units": "ms"
+    },
+    "bci_prediction": {
+        "Description": "Which hand did the BCI predict was raised in this trial.",
+        "Levels": {
+            "left": "BCI predicts participant raised left hand",
+            "right": "BCI predicts participant raised right hand"
+        },
+		"HED": {
+          "left": "Description/BCI predicts participant raised left hand, Computed-prediction, (Computational-evidence, (Left-side, Hand))",
+          "right": "Description/BCI predicts participant raised right hand, Computed-prediction, (Computational-evidence, (Right-side, Hand))"
+        }
+    },
+    "bci_prediction_valid": {
+        "Description": "Did a prediction arrive on time (if not, a random prediction was made) in this trial.",
+        "Levels": {
+            "1": "Computational prediction arrived on time",
+            "2": "Computational prediction was late so random prediction was used."
+        },
+		"HED": {
+			"1": "Description/Computational prediction arrived on time, (Computational-agent, Predict)",
+			"2": "Description/Computational prediction was late so random prediction was used., Time-out, (Random, Predict)"
+		}
+    },
+    "n_repeated": {
+        "Description": "Number of trials that had to be repeated until the present trial because of invalid participant behavior (within this stage)."
+    }
+}
\ No newline at end of file
diff --git a/hedweb/tests/data/short_form_valid.json b/hedweb/tests/data/short_form_valid.json
new file mode 100644
index 000000000..a791a0f69
--- /dev/null
+++ b/hedweb/tests/data/short_form_valid.json
@@ -0,0 +1,21 @@
+{
+    "onset": {
+        "Description": "Onset of the go signal which is the disappearance of the cue bar",
+        "Units": "s"
+    },
+    "duration": {
+        "Description": "Duration of the event",
+        "Units": "s"
+    },
+	"event-type": {
+      "Description": "Subject presses both buttons causing cue bar to start count-down display",
+      "Levels": {
+        "cue": "Subject presses both buttons causing cue bar to start count-down display",
+        "go": "Bar disappears cueing the subject to make a choice about which hand to raise"
+      },
+      "HED": {
+        "cue": "Description/Subject presses both buttons causing cue bar to start count-down display, (Sensory-event, Visual, Cue, ((Rectangle, (Position, (Center-of, Screen)), (Size, Decreasing)))), (Agent-action, Experiment-participant, (Press, Hold-down, (Left-side, Button)), (Press, Hold-down, (Right-side, Button)))",
+        "go": "Description/Onset of the go signal which is the disappearance of the cue bar, Sensory-event, Visual, Experimental-stimulus, Instructional, Signal-go"
+      }
+    }
+}
\ No newline at end of file
diff --git a/hedweb/tests/test_dictionary.py b/hedweb/tests/test_dictionary.py
index 1e9b1409f..30dd3b795 100644
--- a/hedweb/tests/test_dictionary.py
+++ b/hedweb/tests/test_dictionary.py
@@ -1,62 +1,65 @@
-import unittest
-# from flask import current_app, jsonify, Response
-# from hed.web.utils import app_config
-# from hed.web.validation import generate_dictionary_validation_filename
-# from hed.web.app_factory import AppFactory
-# from hed.web.constants import file_constants, spreadsheet_constants
+
 import os
+import shutil
+import unittest
 
-# app = AppFactory.create_app('config.TestConfig')
-# with app.app_context():
-#     from hed.web import web_utils
-#     from hed.web.routes import route_blueprint
-#
-#     app.register_blueprint(route_blueprint, url_prefix=app.config['URL_PREFIX'])
-#     web_utils.create_upload_directory(app.config['UPLOAD_FOLDER'])
+from hed.web.app_factory import AppFactory
 
 
-class Test(unittest.TestCase):
-    def setUp(self):
-        print("Stuff")
-        # self.create_test_app()
-        # self.app = app.app.test_client()
-        # self.major_version_key = 'major_versions'
-        # self.hed_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/HED.xml')
-        # self.tsv_file1 = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/tsv_file1.txt')
-
-    # def create_test_app(self):
-    #     app = AppFactory.create_app('config.TestConfig')
-    #     with app.app_context():
-    #         from hed.web.routes import route_blueprint
-    #         app.register_blueprint(route_blueprint)
-    #         self.app = app.test_client()
+def test_dictionaries():
+    base_path = os.path.dirname(os.path.abspath(__file__))
+    test_dict = {'hed-xml-file': os.path.join(base_path, 'data/HED8.0.0-alpha.1.xml'),
+                 'hed-display-name': 'HED8.0.0-alpha.1.xml',
+                 'json-path': os.path.join(base_path, 'data/short_form_valid.json'),
+                 'json-file': 'short_form_valid.json',
+                 'check-for-warnings': True}
+    return test_dict
 
-    def test_generate_input_arguments_from_validation_form(self):
-        self.assertTrue(1, "Testing generate_arguments_from_dictionary_form")
 
-    def test_generate_spreadsheet_validation_filename(self):
-        self.assertTrue(1, "Testing generate_dictionary_validation_filename")
-        # dictionary_filename = 'abc.xls'
-        # expected_spreadsheet_filename = 'validated_' + dictionary_filename.rsplit('.')[0] + '.txt'
-        # validation_file_name = generate_dictionary_validation_filename(dictionary_filename, worksheet_name='')
-        # self.assertTrue(validation_file_name)
-        # self.assertEqual(expected_spreadsheet_filename, validation_file_name)
+class Test(unittest.TestCase):
+    @classmethod
+    def setUpClass(cls):
+        cls.upload_directory = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/upload')
+        app = AppFactory.create_app('config.TestConfig')
+        with app.app_context():
+            from hed.web.routes import route_blueprint
+            app.register_blueprint(route_blueprint)
+            if not os.path.exists(cls.upload_directory):
+                os.mkdir(cls.upload_directory)
+            app.config['UPLOAD_FOLDER'] = cls.upload_directory
+            cls.app = app
+            cls.app.test = app.test_client()
 
-    def test_get_uploaded_file_paths_from_forms(self):
-        self.assertTrue(1, "Testing get_uploaded_file_paths_from_forms")
+    @classmethod
+    def tearDownClass(cls):
+        shutil.rmtree(cls.upload_directory)
 
-    def test_report_eeg_events_validation_status(self):
-        self.assertTrue(1, "Testing report_eeg_events_validation_status")
+    def test_generate_input_arguments_from_validation_form(self):
+        from hed.web import dictionary
+        self.assertRaises(TypeError, dictionary.generate_arguments_from_dictionary_form, {},
+                          "An exception should be raised if an empty request is passed")
 
-    def test_report_spreadsheet_validation_status(self):
+    def test_report_dictionary_validation_status(self):
         self.assertTrue(1, "Testing report_dictionary_validation_status")
 
-    def test_save_validation_issues_to_file_in_upload_folder(self):
-        self.assertTrue(1, "Testing save_issues_to_upload_folder")
-
-    def test_validate_spreadsheet(self):
-        self.assertTrue(1, "Testing validate_dictionary")
+    def test_validate_dictionary(self):
+        from hed.web.dictionary import validate_dictionary
+        from hed.schema import hed_schema_file
+        inputs = test_dictionaries()
+        self.assertEqual("", validate_dictionary(inputs), "This dictionary should have no errors for 8.0.0")
+        hed8_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/HED7.1.2.xml')
 
+        hed7_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/HED7.1.2.xml')
+        hed7 = hed_schema_file.load_schema(hed7_path)
+        # response = validate_dictionary(inputs, hed_schema=hed7)
+        # inputs["hed-xml-file"] = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/HED7.1.2.xml')
+        # hed7 = hed_schema_file.load_schema(inputs["hed-xml_file"])
+        # self.assertEqual("", validate_dictionary(input_arguments, hed_schema=schema8),
+        #                  "This dictionary should have no errors for directly created 8.0.0")
+        # schema7 = HedSchema(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/HED7.1.2.xml'))
+        # x = validate_dictionary(input_arguments, hed_schema=schema7, return_response=False)
+        # self.assertEqual("", validate_dictionary(input_arguments, hed_schema=schema7,return_response=False),
+        #                  "This dictionary should have no errors for directly created 8.0.0")
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/hedweb/tests/test_routes.py b/hedweb/tests/test_routes.py
index f2ac8efd7..15ae56b31 100644
--- a/hedweb/tests/test_routes.py
+++ b/hedweb/tests/test_routes.py
@@ -27,8 +27,8 @@ def tearDownClass(cls):
         shutil.rmtree(cls.upload_directory)
 
     def test_delete_file_in_upload_directory(self):
-        response = self.app.test.post('/delete/file_that_does_not_exist')
-        # self.assertEqual(response.status_code, 404, "Non-existent file should cause a non-found error")
+        response = self.app.test.get('/delete/file_that_does_not_exist')
+        self.assertEqual(response.status_code, 404, "Non-existent file should cause a non-found error")
         hed_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/HED.xml')
         dummy_file = os.path.join(self.app.config['UPLOAD_FOLDER'], 'HED.xml')
         dummy_path = pathlib.Path(dummy_file)
@@ -50,28 +50,28 @@ def test_download_file_in_upload_directory(self):
         copyfile(hed_file, dummy_file)
         self.assertTrue(dummy_path.is_file(), "Dummy file now exists")
         response = self.app.test.get('/download-file/HED.xml')
-        print(response.status_code)
+
         # self.assertEqual(response.status_code, 204, "Dummy file should be deleted")
 
     def test_get_dictionary_validation_results(self):
-        response = self.app.get('/dictionary-validation-submit')
-        self.assertEqual(response.status_code, 404)
+        response = self.app.test.post('/dictionary-validation-submit')
+        self.assertEqual(400, response.status_code, 'Dictionary validation requires data')
 
     def test_get_events_validation_results(self):
-        response = self.app.get('/events-validation-submit')
-        self.assertEqual(response.status_code, 404)
+        response = self.app.test.post('/events-validation-submit')
+        self.assertEqual(400, response.status_code, 'Event validation requires data')
 
     def test_get_hed_services_results(self):
-        response = self.app.get('/hed-services-submit')
-        self.assertEqual(response.status_code, 404)
+        response = self.app.test.get('/hed-services-submit')
+        self.assertEqual(405, response.status_code, 'HED services require data')
 
     def test_get_hed_version(self):
-        response = self.app.post('/get-hed-version')
-        self.assertEqual(response.status_code, 400)
+        response = self.app.test.post('/get-hed-version')
+        self.assertEqual(400, response.status_code, 'Returning HED version requires data')
 
     def test_get_major_hed_versions(self):
-        response = self.app.post('/get-hed-major-versions')
-        self.assertEqual(response.status_code, 405)
+        response = self.app.test.post('/get-hed-major-versions')
+        self.assertEqual(405, response.status_code, 'Returning HED version list requires data')
         # import hed.web.constants.common_constants as constants
         # from hed.web.web_utils import find_major_hed_versions
         # hed_info = find_major_hed_versions()
@@ -79,60 +79,60 @@ def test_get_major_hed_versions(self):
         # self.assertTrue('7.1.2' in hed_info[constants.HED_MAJOR_VERSIONS], "7.1.2 is a major versions")
 
     def test_get_schema_compliance_check_results(self):
-        response = self.app.post('/schema-compliance-check-submit')
-        self.assertEqual(response.status_code, 400)
+        response = self.app.test.post('/schema-compliance-check-submit')
+        self.assertEqual(400, response.status_code, 'Checking schema compliance requires data')
 
     def test_get_schema_conversion_results(self):
-        response = self.app.post('/schema-conversion-submit')
-        self.assertEqual(response.status_code, 400)
+        response = self.app.test.post('/schema-conversion-submit')
+        self.assertEqual(400, response.status_code, 'Converting schema requires data')
 
     def test_get_spreadsheet_columns_info(self):
-        response = self.app.post('/get-spreadsheet-columns-info')
-        self.assertEqual(response.status_code, 400)
+        response = self.app.test.post('/get-spreadsheet-columns-info')
+        self.assertEqual(400, response.status_code, 'Returning spreadsheet column info requires data')
 
     def test_get_spreadsheet_validation_results(self):
-        response = self.app.post('/spreadsheet-validation-submit')
-        self.assertEqual(response.status_code, 400)
+        response = self.app.test.post('/spreadsheet-validation-submit')
+        self.assertEqual(400, response.status_code, 'Validating spreadsheet requires data')
 
     def test_get_worksheets_info(self):
-        response = self.app.post('/get-worksheets-info')
-        self.assertEqual(response.status_code, 400)
+        response = self.app.test.post('/get-worksheets-info')
+        self.assertEqual(400, response.status_code, 'Returning worksheet info requires data')
 
     def test_render_additional_examples_page(self):
         response = self.app.test.get('/additional-examples')
-        self.assertEqual(response.status_code, 200, "The additional-examples content page exists")
+        self.assertEqual(response.status_code, 200, "The additional-examples content page should exist")
 
     def test_render_common_error_page(self):
         response = self.app.test.get('/common-errors')
-        self.assertEqual(response.status_code, 200, "The common-errors content page exists")
+        self.assertEqual(response.status_code, 200, "The common-errors content page should exist")
 
     def test_render_dictionary_form(self):
-        response = self.app.get('/dictionary')
-        self.assertEqual(response.status_code, 200)
+        response = self.app.test.get('/dictionary')
+        self.assertEqual(response.status_code, 200, "The dictionary content page should exist")
 
     def test_render_events_form(self):
-        response = self.app.get('/events')
-        self.assertEqual(response.status_code, 200)
+        response = self.app.test.get('/events')
+        self.assertEqual(response.status_code, 200, "The events content page should exist")
 
     def test_render_hed_services_form(self):
-        response = self.app.get('/hed-services')
-        self.assertEqual(response.status_code, 200)
+        response = self.app.test.get('/hed-services')
+        self.assertEqual(response.status_code, 200, "The hed-services content page should exist")
 
     def test_render_help_page(self):
-        response = self.app.get('/hed-tools-help')
-        self.assertEqual(response.status_code, 200)
+        response = self.app.test.get('/hed-tools-help')
+        self.assertEqual(response.status_code, 200, "The hed-tools-help content page should exist" )
 
     def test_render_home_page(self):
-        response = self.app.get('/')
-        self.assertEqual(response.status_code, 200)
+        response = self.app.test.get('/')
+        self.assertEqual(response.status_code, 200, "The root hed home page should exist")
 
     def test_render_schema_form(self):
-        response = self.app.get('/schema')
-        self.assertEqual(response.status_code, 200)
+        response = self.app.test.get('/schema')
+        self.assertEqual(response.status_code, 200, "The schema page should exist")
 
     def test_render_spreadsheet_form(self):
-        response = self.app.get('/spreadsheet')
-        self.assertEqual(response.status_code, 200)
+        response = self.app.test.get('/spreadsheet')
+        self.assertEqual(response.status_code, 200, "The spreadsheet page should exist")
 
 
 if __name__ == '__main__':
diff --git a/hedweb/tests/test_schema.py b/hedweb/tests/test_schema.py
index 6950cefc8..0134f9567 100644
--- a/hedweb/tests/test_schema.py
+++ b/hedweb/tests/test_schema.py
@@ -34,7 +34,7 @@ def test_generate_input_from_schema_form(self):
         self.assertTrue(1, "Testing generate_input_from_schema_form")
 
     def test_get_schema_conversion(self):
-        self.assertTrue(1, "Testing get_schema_conversion")
+        self.assertTrue(1, "Testing convert_schema")
 
     def test_run_schema_compliance_check(self):
         self.assertTrue(1, "Testing run_schema_compliance_check")
diff --git a/hedweb/tests/test_spreadsheet.py b/hedweb/tests/test_spreadsheet.py
index 282068243..fb23a16a2 100644
--- a/hedweb/tests/test_spreadsheet.py
+++ b/hedweb/tests/test_spreadsheet.py
@@ -1,35 +1,28 @@
-import unittest
-# from flask import current_app, jsonify, Response
-# from hed.web.utils import app_config
-# from hed.web.validation import generate_dictionary_validation_filename
-# from hed.web.app_factory import AppFactory
-# from hed.web.constants import file_constants, spreadsheet_constants
 import os
-
-# app = AppFactory.create_app('config.TestConfig')
-# with app.app_context():
-#     from hed.web import web_utils
-#     from hed.web.routes import route_blueprint
-#
-#     app.register_blueprint(route_blueprint, url_prefix=app.config['URL_PREFIX'])
-#     web_utils.create_upload_directory(app.config['UPLOAD_FOLDER'])
+import shutil
+import unittest
+from unittest import mock
+from flask import Flask, current_app
+from hed.web.app_factory import AppFactory
 
 
 class Test(unittest.TestCase):
-    def setUp(self):
-        print("Stuff")
-        # self.create_test_app()
-        # self.app = app.app.test_client()
-        # self.major_version_key = 'major_versions'
-        # self.hed_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/HED.xml')
-        # self.tsv_file1 = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/tsv_file1.txt')
-
-    # def create_test_app(self):
-    #     app = AppFactory.create_app('config.TestConfig')
-    #     with app.app_context():
-    #         from hed.web.routes import route_blueprint
-    #         app.register_blueprint(route_blueprint)
-    #         self.app = app.test_client()
+    @classmethod
+    def setUpClass(cls):
+        cls.upload_directory = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/upload')
+        app = AppFactory.create_app('config.TestConfig')
+        with app.app_context():
+            from hed.web.routes import route_blueprint
+            app.register_blueprint(route_blueprint)
+            if not os.path.exists(cls.upload_directory):
+                os.mkdir(cls.upload_directory)
+            app.config['UPLOAD_FOLDER'] = cls.upload_directory
+            cls.app = app
+            cls.app.test = app.test_client()
+
+    @classmethod
+    def tearDownClass(cls):
+        shutil.rmtree(cls.upload_directory)
 
     def test_generate_input_from_validation_form(self):
         self.assertTrue(1, "Testing generate_input_from_validation_form")
@@ -39,6 +32,31 @@ def test_report_spreadsheet_validation_status(self):
 
     def test_validate_spreadsheet(self):
         self.assertTrue(1, "Testing validate_spreadsheet")
+        # from hed.web.spreadsheet import validate_spreadsheet
+        # temp_name = save_file_to_upload_folder('')
+        # self.assertEqual(temp_name, '', "A file with empty name cnnot be copied copied")
+        # some_file = '3k32j23kj1.txt'
+        # temp_name = save_file_to_upload_folder(some_file)
+        # self.assertEqual(temp_name, '', "A file that does not exist cannot be copied")
+        # hed_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/HED.xml')
+        # self.assertTrue(os.path.exists(hed_file), "The HED.xml file should exist in the data directory")
+        # spreadsheet_path =
+        # input_arguments = {''}
+
+
+def get_inputs():
+    spreadsheet_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/ExcelMultipleSheets.xlsx')
+    hed_file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/HED7.1.2.xml')
+    spreadsheet_file = 'ExcelMultipleSheets.xlsx'
+    worksheet_name ='LKT Events'
+    tag_columns = [2, 3]
+    other_columns = [4]
+    # inputs = {'spreadsheet_path': spreadsheet_path, 'hed_file_path': hed_file_path, \
+    #           'spreadsheet-file': spreadsheet_file, 'worksheet-name': worksheet_name, \
+    #           'tag-columns': tag_columns, 'has-column-names': true, \
+    #           'check-for-warnings:', True, 'column-prefix-dictionary': ''}
+    inputs = {}
+    return inputs
 
 
 if __name__ == '__main__':
diff --git a/hedweb/tests/test_utils.py b/hedweb/tests/test_spreadsheet_utils.py
similarity index 90%
rename from hedweb/tests/test_utils.py
rename to hedweb/tests/test_spreadsheet_utils.py
index a7924ef67..b4dce4f0d 100644
--- a/hedweb/tests/test_utils.py
+++ b/hedweb/tests/test_spreadsheet_utils.py
@@ -39,7 +39,7 @@ def test_get_column_delimiter_based_on_file_extension(self):
     #     self.assertEqual('', delimiter, "Excel files should have an empty delimiter")
 
     def test_get_excel_worksheet_names(self):
-        from hed.web.utils import get_excel_worksheet_names
+        from hed.web.spreadsheet_utils import get_excel_worksheet_names
         self.excel_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/ExcelMultipleSheets.xlsx')
         worksheet_names = get_excel_worksheet_names(self.excel_file)
         self.assertEqual(len(worksheet_names), 3, "This excel file has three worksheets")
@@ -74,12 +74,6 @@ def test_get_spreadsheet_specific_tag_column_indices(self):
         #     self.assertIsInstance(indices, dict)
         #
 
-    def test_get_spreadsheet_other_tag_column_indices(self):
-        self.assertTrue(1, "Testing get_spreadsheet_other_tag_column_indices")
-
-    def test_get_spreadsheet_specific_tag_column_indices(self):
-        self.assertTrue(1, "Testing get_spreadsheet_specific_tag_column_indices")
-
     def test_get_text_file_column_names(self):
         self.assertTrue(1, "Testing get_text_file_column_names")
         # def test_get_text_file_column_names(self):
@@ -95,11 +89,9 @@ def test_populate_spreadsheet_columns_info_dictionary(self):
         self.assertTrue(1, "Testing populate_spreadsheet_columns_info_dictionary")
 
     def test_populate_worksheets_info_dictionary(self):
+        info = {}
         self.assertTrue(1, "Testing populate_worksheets_info_dictionary")
 
-    def test_worksheet_name_present_in_form(self):
-        self.assertTrue(1, "Testing worksheet_name_present_in_form")
-
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/hedweb/tests/test_web_utils.py b/hedweb/tests/test_web_utils.py
index 817fe53f0..05c275567 100644
--- a/hedweb/tests/test_web_utils.py
+++ b/hedweb/tests/test_web_utils.py
@@ -28,18 +28,6 @@ def setUpClass(cls):
     def tearDownClass(cls):
         shutil.rmtree(cls.upload_directory)
 
-    def test_check_if_option_in_form(self):
-        self.assertTrue(1, "Testing form_has_option")
-        from hed.web.web_utils import form_has_option
-        mock_form = mock.Mock()
-        mock_dict = {'upload': 'me', 'download:': 'them'}
-        mock_form.values = mock_dict
-        self.assertTrue(form_has_option(mock_form, 'upload', 'me'),
-                        "True if option_name has target_value")
-        self.assertFalse(form_has_option(mock_form, 'upload', 'them'),
-                         "False if option_name is not target_value")
-        self.assertFalse(form_has_option(mock_form, 'temp', 'them'),
-                         "False if invalid option name")
 
     def test_convert_number_str_to_list(self):
         from hed.web.web_utils import convert_number_str_to_list
@@ -98,6 +86,25 @@ def test_find_all_str_indices_in_list(self):
         self.assertIsInstance(indices, list)
         self.assertEqual(expected_indices, indices)
 
+    def test_form_has_file(self):
+        self.assertTrue(1, "Testing form_has_file")
+
+    def test_form_has_option(self):
+        self.assertTrue(1, "Testing form_has_option")
+        from hed.web.web_utils import form_has_option
+        mock_form = mock.Mock()
+        mock_dict = {'upload': 'me', 'download:': 'them'}
+        mock_form.values = mock_dict
+        self.assertTrue(form_has_option(mock_form, 'upload', 'me'),
+                        "True if option_name has target_value")
+        self.assertFalse(form_has_option(mock_form, 'upload', 'them'),
+                         "False if option_name is not target_value")
+        self.assertFalse(form_has_option(mock_form, 'temp', 'them'),
+                         "False if invalid option name")
+
+    def test_form_has_url(self):
+        self.assertTrue(1, "Testing form_has_url")
+
     def test_generate_download_file_response(self):
         from hed.web.web_utils import generate_download_file_response
         hed_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/HED.xml')
@@ -158,7 +165,24 @@ def test_get_optional_form_field(self):
         self.assertTrue(1, "Testing get_optional_form_field")
 
     def test_get_uploaded_file_path_from_form(self):
-        self.assertTrue(1, "Testingget_uploaded_file_path_from_form")
+        from hed.web.web_utils import get_uploaded_file_path_from_form
+        # with self.app.test as client:
+        #     # send data as POST form to endpoint
+        #     sent = {'return_url': 'my_test_url'}
+        #     result = client.post(
+        #         '/',
+        #         data=sent
+        #     )
+        # mock_form = mock.Mock()
+        # mock_dict = {'upload': 'me', 'download:': 'them'}
+        #     mock_form.values = mock_dict
+        # text = 'save me now'
+        # filename = 'test_save.txt'
+        # actual_path = os.path.join(self.upload_directory, filename)
+        # self.assertEqual(0, os.path.isfile(actual_path), f"{actual_path} should not exist before saving")
+        # with self.app.app_context():
+        #     the_path = save_text_to_upload_folder(text, filename)
+        #     self.assertEqual(1, os.path.isfile(the_path), f"{the_path} should exist after saving")
 
     def test_handle_http_error(self):
         error_code = "CODE"
@@ -166,26 +190,51 @@ def test_handle_http_error(self):
 
         self.assertTrue(1, "Testing handle_http_error")
 
-    def test_find_hed_version_in_uploaded_file(self):
-            self.assertTrue(1, "Testing find_hed_version_in_uploaded_file")
-
     def test_save_file_to_upload_folder(self):
-        from hed.web.web_utils import save_file_to_upload_folder, app_config
-        temp_name = save_file_to_upload_folder('')
-        self.assertEqual(temp_name, '', "A file with empty name cnnot be copied copied")
-        some_file = '3k32j23kj1.txt'
-        temp_name = save_file_to_upload_folder(some_file)
-        self.assertEqual(temp_name, '', "A file that does not exist cannot be copied")
+        self.assertTrue(1, "Testing save_file_to_upload_folder")
+        from hed.web.web_utils import save_file_to_upload_folder
+        from werkzeug.datastructures import FileStorage
+        filename = 'HED.xml'
+        actual_path = os.path.join(self.upload_directory, filename)
+        self.assertEqual(0, os.path.isfile(actual_path), f"{actual_path} should not exist before saving")
         hed_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/HED.xml')
-        self.assertTrue(os.path.exists(hed_file), "The HED.xml file should exist in the data directory")
-        mock_file = mock.Mock()
-        mock_file.filename = hed_file
+        # with open(hed_file) as f:
+        #     upload_file = FileStorage(f, filename='HED.xml', content_type='text/xml',  content_length=0, stream=stream)
+        #     with self.app.app_context():
+        #         the_path = save_file_to_upload_folder(upload_file)
+        #         self.assertEqual(1, os.path.isfile(the_path), f"{the_path} should exist after saving")
+
+        # temp_name = save_file_to_upload_folder('')
+        # self.assertEqual(temp_name, '', "A file with empty name cnnot be copied copied")
+        # some_file = '3k32j23kj1.txt'
+        # temp_name = save_file_to_upload_folder(some_file)
+        # self.assertEqual(temp_name, '', "A file that does not exist cannot be copied")
+        # hed_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/HED.xml')
+        #
+        # self.assertTrue(os.path.exists(hed_file), "The HED.xml file should exist in the data directory")
+        # actual_path = os.path.join(self.upload_directory, filename)
+        # self.assertEqual(0, os.path.isfile(actual_path), f"{actual_path} should not exist before saving")
+        # with self.app.app_context():
+        #     the_path = save_text_to_upload_folder(text, filename)
+        #     self.assertEqual(1, os.path.isfile(the_path), f"{the_path} should exist after saving")
+        # mock_file = mock.Mock()
+        # mock_file.filename = hed_file
         # TODO: Context not working this is not tested
         # with Test.app_context():
         #     temp_name = save_file_to_upload_folder(mock_file)
         # self.assertNotEqual(mock_file, '', "It should create an actual file in the upload directory")
         # self.assertTrue(os.path.isfile(temp_name), "File should exist after it is uploaded")
 
+    def test_text_to_upload_folder(self):
+        from hed.web.web_utils import save_text_to_upload_folder
+        text = 'save me now'
+        filename = 'test_save.txt'
+        actual_path = os.path.join(self.upload_directory, filename)
+        self.assertEqual(0, os.path.isfile(actual_path), f"{actual_path} should not exist before saving")
+        with self.app.app_context():
+            the_path = save_text_to_upload_folder(text, filename)
+            self.assertEqual(1, os.path.isfile(the_path), f"{the_path} should exist after saving")
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/hedweb/tests/testing_dict_val.py b/hedweb/tests/testing_dict_val.py
deleted file mode 100644
index 18d636bcd..000000000
--- a/hedweb/tests/testing_dict_val.py
+++ /dev/null
@@ -1,15 +0,0 @@
-
-from hed.util.column_def_group import ColumnDefGroup
-from hed.util.hed_schema import HedSchema
-
-if __name__ == '__main__':
-    local_hed_xml = "data/HED8.0.0-alpha.1.xml"
-    hed_dictionary = HedSchema(local_hed_xml)
-    json_filename = "data/task_pennies_events.json"
-
-    json_file = ColumnDefGroup(json_filename)
-    # Print all the errors from the json file
-    errors = json_file.validate_entries(hed_dictionary)
-    for error in errors:
-        x = error
-        print(error["message"])
\ No newline at end of file
diff --git a/hedweb/tests/testing_dictionary_validate.py b/hedweb/tests/testing_dictionary_validate.py
new file mode 100644
index 000000000..1ce6916a3
--- /dev/null
+++ b/hedweb/tests/testing_dictionary_validate.py
@@ -0,0 +1,37 @@
+import os
+import json
+import os.path
+from urllib.parse import urlparse
+from shutil import move
+from hed.validator.hed_validator import HedValidator
+from hed.util.column_def_group import ColumnDefGroup
+from hed.schema.hed_schema_file import load_schema
+from hed.util.error_types import ErrorContext
+
+if __name__ == '__main__':
+
+    dir_path = os.path.dirname(os.path.realpath(__file__))
+    local_hed_file1 = os.path.join(dir_path, 'data/HED7.1.2.xml')
+    local_hed_file2 = os.path.join(dir_path, 'data/HED8.0.0-alpha.1.xml')
+    json_file = os.path.join(dir_path, 'data/example_dictionary.json')
+
+    # Example 1
+
+    hed_schema = load_schema(local_hed_file1)
+    json_dictionary = ColumnDefGroup(json_file)
+    issues = json_dictionary.validate_entries(hed_schema)
+    issue_list = []
+    for issue in issues:
+        code = issue.get('code', "")
+        message = issue.get('message', "")
+        column_name = issue.get(ErrorContext.SIDECAR_COLUMN_NAME, "")
+        if column_name:
+            column_name = column_name[0]
+        key_name = issue.get(ErrorContext.SIDECAR_KEY_NAME, "")
+        if key_name:
+            key_name = key_name[0]
+        hed_string = issue.get(ErrorContext.SIDECAR_HED_STRING, "")
+        issue_dict = {"code": code, "message": message, "column_name": column_name,
+                      "key_name": key_name, "hed_string": hed_string}
+        issue_list.append(issue_dict)
+    print(issue_list)
\ No newline at end of file
diff --git a/hedweb/tests/testing_dups.py b/hedweb/tests/testing_dups.py
index 12c65d9a5..f98286503 100644
--- a/hedweb/tests/testing_dups.py
+++ b/hedweb/tests/testing_dups.py
@@ -1,18 +1,27 @@
-import os
+import json
 import os.path
-from urllib.parse import urlparse
-from shutil import move
-from hed.schema import constants
-from hed.util.file_util import delete_file_if_it_exists, url_to_file, get_file_extension, write_text_iter_to_file
+
 
 if __name__ == '__main__':
     # hed_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/HED.xml')
     # result_dict = duplicate_nodes.check_for_duplicate_tags(hed_file)
     # output_location = result_dict[constants.HED_OUTPUT_LOCATION_KEY]
     # move(output_location, "duplicate_tags_in_HEDXML.txt")
-    hed_file_path = ''
-    delete_file_if_it_exists(hed_file_path)
-    hed_file_path = None
-    delete_file_if_it_exists(hed_file_path)
-    url = urlparse('')
-    print(url)
\ No newline at end of file
+    # hed_file_path = ''
+    # delete_file_if_it_exists(hed_file_path)
+    # hed_file_path = None
+    # delete_file_if_it_exists(hed_file_path)
+    # url = urlparse('')
+    # print(url)
+    # x = bytearray("abcd", 'utf-8')
+    # y = x.decode()
+    # print(y)
+    #
+    dir_path = os.path.dirname(os.path.realpath(__file__))
+    the_path = os.path.join(dir_path, 'static/resources/services.json')
+    RESOURCE_PATH = './static/resources/services.json'
+    with open(the_path) as f:
+        service_info = json.load(f)
+
+    print(service_info)
+
diff --git a/hedweb/tests/testing_string_validate.py b/hedweb/tests/testing_string_validate.py
new file mode 100644
index 000000000..e6de29b13
--- /dev/null
+++ b/hedweb/tests/testing_string_validate.py
@@ -0,0 +1,26 @@
+import os.path
+from hed.validator.hed_validator import HedValidator
+from hed.util.error_reporter import get_printable_issue_string
+
+
+if __name__ == '__main__':
+
+    dir_path = os.path.dirname(os.path.realpath(__file__))
+    local_hed_file1 = os.path.join(dir_path, 'data/HED7.1.2.xml')
+    local_hed_file2 = os.path.join(dir_path, 'data/HED8.0.0-alpha.1.xml')
+
+    hed_validator_current = HedValidator(hed_xml_file=local_hed_file2)
+
+    # Example 1a: Valid HED string for HED <= v7.1.1
+    hed_string_1 = 'Event/Label/ButtonPuskDeny, Event/Description/Button push to deny access to the ID holder,' \
+                   'Event/Category/Participant response, ' \
+                   '(Participant ~ Action/Button press/Keyboard ~ Participant/Effect/Body part/Arm/Hand/Finger)'
+
+    validation_issues = hed_validator_current.validate_input(hed_string_1)
+    print(get_printable_issue_string(validation_issues, title='[Example 1b] hed_string_1 has issues with the latest HED version'))
+
+    hed_list = [hed_string_1, hed_string_1]
+
+    validation_issues = hed_validator_current.validate_input(hed_list)
+    print(get_printable_issue_string(validation_issues,
+                                                  title='[Example 1b] hed_string_1 has issues with the latest HED version'))
diff --git a/hedweb/tests/try_schema.py b/hedweb/tests/try_schema.py
new file mode 100644
index 000000000..ba1c453c0
--- /dev/null
+++ b/hedweb/tests/try_schema.py
@@ -0,0 +1,13 @@
+import os
+
+from hed.schema import hed_schema_file
+
+if __name__ == '__main__':
+    dir_path = os.path.dirname(os.path.realpath(__file__))
+    local_hed_xml = os.path.join(dir_path, 'data/HED8.0.0-alpha.1.xml')
+    local_hed_wiki = os.path.join(dir_path, 'data/HED3.mediawiki')
+
+    # Test conversion from xml to mediawiki
+    local_hed_schema = hed_schema_file.load_schema(local_hed_xml)
+    converted_wiki, errors_wiki = local_hed_schema.save_as_xml()
+    print('to here')