diff --git a/.gitignore b/.gitignore index 97e24a2..22e147a 100755 --- a/.gitignore +++ b/.gitignore @@ -95,6 +95,7 @@ results.json # Optional: Test data if not intended to be part of the repo da-analyzer-results +sbom-test-data # Optional: User-specific test scripts if not shared test-commands.txt diff --git a/pyproject.toml b/pyproject.toml index d819399..1383790 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,8 @@ requires-python = ">=3.9" dependencies = [ "requests>=2.20.0", "GitPython>=3.1.40", + "spdx-tools>=0.8.0", + "cyclonedx-python-lib[validation]>=7.0.0", ] [project.scripts] diff --git a/src/workbench_cli/api/helpers/api_base.py b/src/workbench_cli/api/helpers/api_base.py index 8a5b83d..44ed90b 100644 --- a/src/workbench_cli/api/helpers/api_base.py +++ b/src/workbench_cli/api/helpers/api_base.py @@ -182,6 +182,10 @@ def _send_request(self, payload: dict, timeout: int = 1800) -> dict: except requests.exceptions.Timeout as e: logger.error("API request timed out: %s", e, exc_info=True) raise NetworkError("Request to API server timed out", details={"error": str(e)}) + except requests.exceptions.RequestException as e: + # Handle network-level errors (e.g., DNS failure, refused connection) + raise NetworkError(f"Network error while calling API: {e}") from e + except requests.exceptions.RequestException as e: logger.error("API request failed: %s", e, exc_info=True) - raise NetworkError(f"API request failed: {str(e)}", details={"error": str(e)}) \ No newline at end of file + raise NetworkError(f"API request failed: {str(e)}", details={"error": str(e)}) diff --git a/src/workbench_cli/api/helpers/process_waiters.py b/src/workbench_cli/api/helpers/process_waiters.py index 47d25a9..115b983 100644 --- a/src/workbench_cli/api/helpers/process_waiters.py +++ b/src/workbench_cli/api/helpers/process_waiters.py @@ -354,6 +354,9 @@ def wait_for_scan_to_finish( elif scan_type == "DEPENDENCY_ANALYSIS": operation_name = "Dependency Analysis" should_track_files = False + elif scan_type == "REPORT_IMPORT": + operation_name = "SBOM Import" + should_track_files = False else: raise ValueError(f"Unsupported scan type: {scan_type}") diff --git a/src/workbench_cli/api/helpers/project_scan_resolvers.py b/src/workbench_cli/api/helpers/project_scan_resolvers.py index edf8eca..f011c26 100644 --- a/src/workbench_cli/api/helpers/project_scan_resolvers.py +++ b/src/workbench_cli/api/helpers/project_scan_resolvers.py @@ -49,7 +49,7 @@ def resolve_project(self, project_name: str, create_if_missing: bool = False) -> raise ProjectNotFoundError(f"Project '{project_name}' not found") - def resolve_scan(self, scan_name: str, project_name: Optional[str], create_if_missing: bool, params: argparse.Namespace) -> Tuple[str, int]: + def resolve_scan(self, scan_name: str, project_name: Optional[str], create_if_missing: bool, params: argparse.Namespace, import_from_report: bool = False) -> Tuple[str, int]: """Find a scan by name, optionally creating it if not found.""" if project_name: # Look in specific project @@ -64,7 +64,13 @@ def resolve_scan(self, scan_name: str, project_name: Optional[str], create_if_mi # Create if requested if create_if_missing: print(f"Creating scan '{scan_name}' in project '{project_name}'...") - self.create_webapp_scan(project_code=project_code, scan_name=scan_name, **self._get_git_params(params)) + git_params = self._get_git_params(params) + self.create_webapp_scan( + project_code=project_code, + scan_name=scan_name, + import_from_report=import_from_report, + **git_params + ) time.sleep(2) # Brief wait for creation to process # Get the newly created scan diff --git a/src/workbench_cli/api/helpers/scan_status_checkers.py b/src/workbench_cli/api/helpers/scan_status_checkers.py index a7f33ca..b957bd7 100644 --- a/src/workbench_cli/api/helpers/scan_status_checkers.py +++ b/src/workbench_cli/api/helpers/scan_status_checkers.py @@ -1,6 +1,7 @@ import logging import requests -from typing import Dict, Any +import argparse +from typing import Dict, Any, List from ...exceptions import ( ApiError, NetworkError, @@ -133,79 +134,7 @@ def _standard_scan_status_accessor(self, data: Dict[str, Any]) -> str: logger.warning(f"Error accessing status keys in data: {data}", exc_info=True) return "ACCESS_ERROR" # Use the ACCESS_ERROR state - def ensure_process_can_start( - self, - process_type: str, - scan_code: str, - wait_max_tries: int, - wait_interval: int - ): - """ - Checks if a SCAN or DEPENDENCY_ANALYSIS can be started. - If the process is currently QUEUED or RUNNING, it waits for it to finish. - Args: - process_type: Type of process to check (SCAN or DEPENDENCY_ANALYSIS) - scan_code: Code of the scan to check - wait_max_tries: Max attempts to wait if process is running/queued. - wait_interval: Seconds between wait attempts. - - Raises: - CompatibilityError: If the process cannot be started due to incompatible state - ProcessError: If there are process-related issues - ApiError: If there are API issues - NetworkError: If there are network issues - ScanNotFoundError: If the scan doesn't exist - """ - process_type_upper = process_type.upper() - if process_type_upper not in ["SCAN", "DEPENDENCY_ANALYSIS"]: - raise ValueError(f"Invalid process_type '{process_type}' provided to ensure_process_can_start.") - - try: - scan_status = self.get_scan_status(process_type, scan_code) - # Use the standard accessor for consistent status checking - current_status = self._standard_scan_status_accessor(scan_status) - - # If queued or running, wait for it to finish first - if current_status in ["QUEUED", "RUNNING"]: - print() # Newline before waiting message - print(f"Existing {process_type} for '{scan_code}' is {current_status}. Waiting for it to complete...") - logger.info(f"Existing {process_type} for '{scan_code}' is {current_status}. Waiting...") - try: - self.wait_for_scan_to_finish(process_type, scan_code, wait_max_tries, wait_interval) - print(f"Previous {process_type} for '{scan_code}' finished. Proceeding...") - logger.info(f"Previous {process_type} for '{scan_code}' finished.") - # No need to re-check status, wait_for_scan handles terminal states - return # Allow proceeding - except (ProcessTimeoutError, ProcessError) as wait_err: - # If waiting failed, we cannot start the new process - raise ProcessError(f"Could not start {process_type} for '{scan_code}' because waiting for the existing process failed: {wait_err}", details=getattr(wait_err, 'details', None)) from wait_err - - # Allow starting if NEW, FINISHED, FAILED, or CANCELLED - allowed_statuses = ["NEW", "FINISHED", "FAILED", "CANCELLED"] - if current_status not in allowed_statuses: - raise CompatibilityError( - f"Cannot start {process_type.lower()} for '{scan_code}'. Current status is {current_status} (Must be one of {allowed_statuses})." - ) - logger.debug(f"The {process_type} for '{scan_code}' can start (Current status: {current_status}).") - except (ApiError, NetworkError, ScanNotFoundError, CompatibilityError): - raise - except (ProcessError, ProcessTimeoutError): - # Re-raise process-related errors without wrapping them - raise - except Exception as e: - raise ProcessError(f"Could not verify if {process_type.lower()} can start for '{scan_code}'", details={"error": str(e)}) - - def _get_process_status(self, process_type: str, scan_code: str) -> str: - """Helper to get status for a given process type.""" - - if process_type not in self.PROCESS_STATUS_MAP: - raise ValueError(f"Invalid process_type '{process_type}' provided to ensure_process_can_start.") - - status_method = self.PROCESS_STATUS_MAP[process_type] - status_data = status_method(scan_code) - - return status_data.get("status", "UNKNOWN") def get_scan_status(self, scan_type: str, scan_code: str) -> dict: """ @@ -225,3 +154,92 @@ def get_scan_status(self, scan_type: str, scan_code: str) -> dict: NotImplementedError: If called on the base class """ raise NotImplementedError("get_scan_status must be implemented by subclasses") + + def ensure_scan_is_idle( + self, + scan_code: str, + params: argparse.Namespace, + process_types_to_check: List[str] + ): + """ + Ensures specified background processes for a scan are idle (not RUNNING or QUEUED). + If a process is running/queued, waits for it to finish before proceeding. + + This method can handle multiple process types at once and supports various process types + including SCAN, DEPENDENCY_ANALYSIS, GIT_CLONE, EXTRACT_ARCHIVES, and REPORT_IMPORT. + + Args: + scan_code: Code of the scan to check + params: Command line parameters containing retry settings + process_types_to_check: List of process types to check (e.g., ["SCAN", "DEPENDENCY_ANALYSIS"]) + + Raises: + ProcessError: If there are process-related issues + ApiError: If there are API issues + NetworkError: If there are network issues + """ + logger.debug(f"Asserting idle status for processes {process_types_to_check} on scan '{scan_code}'...") + while True: + all_processes_idle_this_pass = True + logger.debug("Starting a new pass to check idle status...") + for process_type in process_types_to_check: + process_type_upper = process_type.upper() + logger.debug(f"Checking status for process type: {process_type_upper}") + current_status = "UNKNOWN" + try: + if process_type_upper == "GIT_CLONE": + current_status = self.check_status_download_content_from_git(scan_code).upper() + elif process_type_upper in ["SCAN", "DEPENDENCY_ANALYSIS", "REPORT_IMPORT"]: + status_data = self.get_scan_status(process_type_upper, scan_code) + current_status = status_data.get("status", "UNKNOWN").upper() + elif process_type_upper == "EXTRACT_ARCHIVES": + # EXTRACT_ARCHIVES status checking is handled differently + # Check if status checking is supported for this process type + if self._is_status_check_supported(scan_code, "EXTRACT_ARCHIVES"): + # Use the specialized method for checking archive extraction status + try: + status_data = self.get_scan_status("EXTRACT_ARCHIVES", scan_code) + current_status = self._standard_scan_status_accessor(status_data) + except (ApiError, ScanNotFoundError) as e: + logger.debug(f"Could not check EXTRACT_ARCHIVES status, assuming finished: {e}") + current_status = "FINISHED" + else: + logger.debug(f"EXTRACT_ARCHIVES status checking not supported. Assuming idle.") + current_status = "FINISHED" + else: + logger.warning(f"Unknown process type '{process_type_upper}' requested for idle check. Skipping.") + continue + logger.debug(f"Current status for {process_type_upper}: {current_status}") + except ScanNotFoundError: + logger.debug(f"Scan '{scan_code}' not found during idle check for {process_type_upper}. Assuming idle.") + print(f" - {process_type_upper}: Not found (considered idle).") + continue + except (ApiError, NetworkError) as e: + raise ProcessError(f"Cannot proceed: Failed to check status for {process_type_upper} due to API/Network error: {e}") from e + except Exception as e: + raise ProcessError(f"Cannot proceed: Unexpected error checking status for {process_type_upper}: {e}") from e + + if current_status in ["RUNNING", "QUEUED", "NOT FINISHED"]: + all_processes_idle_this_pass = False + print(f" - {process_type_upper}: Status is {current_status}. Waiting for completion...") + try: + if process_type_upper == "GIT_CLONE": + _, _ = self.wait_for_git_clone(scan_code, params.scan_number_of_tries, params.scan_wait_time) + elif process_type_upper == "EXTRACT_ARCHIVES": + _, _ = self.wait_for_archive_extraction(scan_code, params.scan_number_of_tries, params.scan_wait_time) + else: + _, _ = self.wait_for_scan_to_finish(process_type_upper, scan_code, params.scan_number_of_tries, params.scan_wait_time) + print(f" - {process_type_upper}: Previous run finished.") + logger.debug(f"Breaking inner loop after waiting for {process_type_upper} to re-check all statuses.") + break + except (ProcessTimeoutError, ProcessError) as wait_err: + raise ProcessError(f"Cannot proceed: Waiting for existing {process_type_upper} failed: {wait_err}") from wait_err + except Exception as wait_exc: + raise ProcessError(f"Cannot proceed: Unexpected error waiting for {process_type_upper}: {wait_exc}") from wait_exc + else: + print(f" - {process_type_upper}: Status is {current_status} (considered idle).") + + if all_processes_idle_this_pass: + logger.debug("All processes confirmed idle in this pass. Exiting check loop.") + break + print("All Scan processes confirmed idle! Proceeding...") diff --git a/src/workbench_cli/api/helpers/upload_helpers.py b/src/workbench_cli/api/helpers/upload_helpers.py index f6beae6..34394d5 100644 --- a/src/workbench_cli/api/helpers/upload_helpers.py +++ b/src/workbench_cli/api/helpers/upload_helpers.py @@ -210,4 +210,4 @@ def _perform_upload(self, file_path: str, headers: dict): raise NetworkError(f"Network error during file upload: {e}") from e finally: if file_handle and not file_handle.closed: - file_handle.close() \ No newline at end of file + file_handle.close() diff --git a/src/workbench_cli/api/scans_api.py b/src/workbench_cli/api/scans_api.py index 4a5771b..559ed9b 100644 --- a/src/workbench_cli/api/scans_api.py +++ b/src/workbench_cli/api/scans_api.py @@ -341,7 +341,8 @@ def create_webapp_scan( git_branch: Optional[str] = None, git_tag: Optional[str] = None, git_commit: Optional[str] = None, - git_depth: Optional[int] = None + git_depth: Optional[int] = None, + import_from_report: bool = False ) -> bool: """ Creates a new webapp scan inside a project, handling Git parameters as needed. @@ -354,6 +355,7 @@ def create_webapp_scan( git_tag: Optional tag name (if git_url is provided, alternative to branch). git_commit: Optional commit hash (if git_url is provided, alternative to branch or tag). git_depth: Optional git clone depth (if git_url is provided). + import_from_report: Whether to import the scan from an existing report Returns: True if the scan was successfully created, raises exception otherwise. @@ -370,6 +372,11 @@ def create_webapp_scan( "project_code": project_code, } + # Add import_from_report parameter if specified + if import_from_report: + payload_data["import_from_report"] = "1" + logger.debug(" Setting scan for report import mode") + # --- Correct Git Parameter Handling --- git_ref_value = None git_ref_type = None @@ -632,12 +639,13 @@ def run_scan( NetworkError: If there are network issues """ try: - self.ensure_process_can_start( - "SCAN", - scan_code, - wait_max_tries=60, # Use a fixed reasonable default - wait_interval=30 + # Create a minimal params namespace for ensure_scan_is_idle + import argparse + params_for_idle_check = argparse.Namespace( + scan_number_of_tries=60, + scan_wait_time=30 ) + self.ensure_scan_is_idle(scan_code, params_for_idle_check, ["SCAN"]) except Exception as e: logger.error(f"Pre-scan check failed for '{scan_code}': {e}") raise @@ -720,12 +728,13 @@ def start_dependency_analysis(self, scan_code: str, import_only: bool = False): NetworkError: If there are network issues """ try: - self.ensure_process_can_start( - "DEPENDENCY_ANALYSIS", - scan_code, - wait_max_tries=60, # Use a fixed reasonable default - wait_interval=30 + # Create a minimal params namespace for ensure_scan_is_idle + import argparse + params_for_idle_check = argparse.Namespace( + scan_number_of_tries=60, + scan_wait_time=30 ) + self.ensure_scan_is_idle(scan_code, params_for_idle_check, ["DEPENDENCY_ANALYSIS"]) except Exception as e: logger.error(f"Pre-analysis check failed for '{scan_code}': {e}") raise @@ -836,3 +845,31 @@ def check_scan_report_status(self, process_id: int, scan_code: str) -> Dict[str, else: error_msg = response.get("error", f"Unexpected response: {response}") raise ApiError(f"Failed to check report status for process {process_id} (scan '{scan_code}'): {error_msg}", details=response) + + def import_report(self, scan_code: str): + """ + Imports an SBOM report into a scan. + + Args: + scan_code: Code of the scan to import the report into + + Raises: + ApiError: If there are API issues + ScanNotFoundError: If the scan doesn't exist + NetworkError: If there are network issues + """ + logger.info(f"Starting SBOM report import for '{scan_code}'...") + payload = { + "group": "scans", + "action": "import_report", + "data": { + "scan_code": scan_code + }, + } + response = self._send_request(payload) + if response.get("status") != "1": + error_msg = response.get("error", "Unknown API error") + if "Scan not found" in error_msg or "row_not_found" in error_msg: + raise ScanNotFoundError(f"Scan '{scan_code}' not found") + raise ApiError(f"Failed to start SBOM report import for '{scan_code}': {error_msg}", details=response) + logger.info(f"SBOM report import for '{scan_code}' started successfully.") diff --git a/src/workbench_cli/api/upload_api.py b/src/workbench_cli/api/upload_api.py index 487ace5..22f5afe 100644 --- a/src/workbench_cli/api/upload_api.py +++ b/src/workbench_cli/api/upload_api.py @@ -8,7 +8,8 @@ from ..exceptions import ( NetworkError, FileSystemError, - WorkbenchCLIError + WorkbenchCLIError, + ApiError ) # Assume logger is configured in main.py @@ -53,6 +54,13 @@ def upload_scan_target(self, scan_code: str, path: str): self._perform_upload(upload_path, headers) + except (ApiError, NetworkError) as e: + # Re-raise known exceptions + raise + except Exception as e: + # Wrap unexpected exceptions + raise WorkbenchCLIError(f"An unexpected error occurred during the upload process: {e}") from e + finally: if archive_path and os.path.exists(archive_path): os.remove(archive_path) @@ -82,5 +90,26 @@ def upload_dependency_analysis_results(self, scan_code: str, path: str): } self._perform_upload(path, headers) - + def upload_sbom_file(self, scan_code: str, path: str): + """ + Uploads an SBOM file to a scan. + + Args: + scan_code: Code of the scan to upload to + path: Path to the SBOM file to upload + """ + if not os.path.exists(path) or not os.path.isfile(path): + raise FileSystemError(f"SBOM file does not exist: {path}") + + upload_basename = os.path.basename(path) + name_b64 = base64.b64encode(upload_basename.encode()).decode("utf-8") + scan_code_b64 = base64.b64encode(scan_code.encode()).decode("utf-8") + + headers = { + "FOSSID-SCAN-CODE": scan_code_b64, + "FOSSID-FILE-NAME": name_b64, + "Accept": "*/*" + } + + self._perform_upload(path, headers) diff --git a/src/workbench_cli/cli.py b/src/workbench_cli/cli.py index 51d3873..1da017d 100644 --- a/src/workbench_cli/cli.py +++ b/src/workbench_cli/cli.py @@ -87,6 +87,10 @@ def parse_cmdline_args(): workbench-cli --api-url --api-user --api-token \\ import-da --project-name MYPROJ --scan-name MYSCAN03 --path ./ort-test-data/analyzer-result.json + # Import SBOM file + workbench-cli --api-url --api-user --api-token \\ + import-sbom --project-name MYPROJ --scan-name MYSCAN04 --path ./sbom-data/bom.json + # Show results for an existing scan workbench-cli --api-url --api-user --api-token \\ show-results --project-name MYPROJ --scan-name MYSCAN01 --show-licenses --show-components @@ -175,6 +179,19 @@ def parse_cmdline_args(): add_common_monitoring_options(import_da_parser) add_common_result_options(import_da_parser) + # --- 'import-sbom' Subcommand --- + import_sbom_parser = subparsers.add_parser( + 'import-sbom', + help='Import SBOM (Software Bill of Materials) from a file.', + description='Import SBOM data from CycloneDX JSON (v1.4-1.6) or SPDX (v2.0-2.3) in JSON/RDF/XML formats. SPDX JSON files are automatically converted to RDF format for compatibility.', + formatter_class=RawTextHelpFormatter + ) + import_sbom_parser.add_argument("--project-name", help="Project name to associate the scan with.", type=str, required=True, metavar="NAME") + import_sbom_parser.add_argument("--scan-name", help="Scan name to import SBOM into.", type=str, required=True, metavar="NAME") + import_sbom_parser.add_argument("--path", help="Path to the SBOM file to be imported (supports CycloneDX JSON and SPDX JSON/RDF/XML formats).", type=str, required=True) + add_common_monitoring_options(import_sbom_parser) + add_common_result_options(import_sbom_parser) + # --- 'show-results' Subcommand --- show_results_parser = subparsers.add_parser( 'show-results', diff --git a/src/workbench_cli/handlers/__init__.py b/src/workbench_cli/handlers/__init__.py index e2c486a..b3cd199 100644 --- a/src/workbench_cli/handlers/__init__.py +++ b/src/workbench_cli/handlers/__init__.py @@ -9,6 +9,7 @@ from .scan import handle_scan from .scan_git import handle_scan_git from .import_da import handle_import_da +from .import_sbom import handle_import_sbom from .show_results import handle_show_results from .evaluate_gates import handle_evaluate_gates from .download_reports import handle_download_reports @@ -17,6 +18,7 @@ 'handle_scan', 'handle_scan_git', 'handle_import_da', + 'handle_import_sbom', 'handle_show_results', 'handle_evaluate_gates', 'handle_download_reports' diff --git a/src/workbench_cli/handlers/evaluate_gates.py b/src/workbench_cli/handlers/evaluate_gates.py index aecf75d..6c49206 100644 --- a/src/workbench_cli/handlers/evaluate_gates.py +++ b/src/workbench_cli/handlers/evaluate_gates.py @@ -14,7 +14,7 @@ ProcessTimeoutError, ValidationError ) -from ..utilities.scan_workflows import wait_for_scan_completion, get_workbench_links +from ..utilities.scan_workflows import get_workbench_links # Get logger from the handlers package from . import logger @@ -362,12 +362,13 @@ def handle_evaluate_gates(workbench: "WorkbenchAPI", params: "argparse.Namespace params=params ) - # Wait for scan and dependency analysis to complete - print("\nVerifying scan completion...") - scan_completed, da_completed, _ = wait_for_scan_completion(workbench, params, scan_code) - - if not scan_completed: - print("\nāŒ Gate Evaluation Failed: KB Scan has not completed successfully.") + # Ensure scan processes are idle before evaluating gates + print("\nEnsuring scans finished before evaluating gates...") + try: + workbench.ensure_scan_is_idle(scan_code, params, ["SCAN", "DEPENDENCY_ANALYSIS"]) + print("Verified all Scan processes are idle. Proceeding with gate evaluation...") + except (ProcessTimeoutError, ProcessError, ApiError, NetworkError) as e: + print(f"\nāŒ Gate Evaluation Failed: Could not verify scan completion: {e}") return False # Generate all Workbench links once for use throughout the handler diff --git a/src/workbench_cli/handlers/import_da.py b/src/workbench_cli/handlers/import_da.py index d13666f..f9f77f3 100644 --- a/src/workbench_cli/handlers/import_da.py +++ b/src/workbench_cli/handlers/import_da.py @@ -17,7 +17,6 @@ FileSystemError, ) from ..utilities.scan_workflows import ( - assert_scan_is_idle, wait_for_scan_completion, print_operation_summary, fetch_display_save_results @@ -81,9 +80,9 @@ def handle_import_da(workbench: "WorkbenchAPI", params: argparse.Namespace) -> b # Ensure scan is compatible with the current operation ensure_scan_compatibility(workbench, params, scan_code) - # Assert scan is idle before starting dependency analysis import + # Ensure scan is idle before starting dependency analysis import print("\nEnsuring the Scan is idle before starting dependency analysis import...") - assert_scan_is_idle(workbench, scan_code, params, ["DEPENDENCY_ANALYSIS"]) + workbench.ensure_scan_is_idle(scan_code, params, ["DEPENDENCY_ANALYSIS"]) # Upload dependency analysis file print("\n--- Uploading Dependency Analysis File ---") @@ -96,20 +95,7 @@ def handle_import_da(workbench: "WorkbenchAPI", params: argparse.Namespace) -> b # Start dependency analysis import print("\n--- Starting Dependency Analysis Import ---") - - # Verify DA import can start - CRITICAL: Match old implementation - print("Verifying Dependency Analysis can start...") - try: - workbench.ensure_process_can_start( - "DEPENDENCY_ANALYSIS", - scan_code, - wait_max_tries=params.scan_number_of_tries, - wait_interval=params.scan_wait_time - ) - except Exception as e: - logger.error(f"Cannot start dependency analysis import for '{scan_code}': {e}", exc_info=True) - raise WorkbenchCLIError(f"Cannot start dependency analysis import: {e}", details={"error": str(e)}) from e - + try: workbench.start_dependency_analysis(scan_code=scan_code, import_only=True) print("Dependency analysis import initiated successfully.") diff --git a/src/workbench_cli/handlers/import_sbom.py b/src/workbench_cli/handlers/import_sbom.py new file mode 100644 index 0000000..8fae372 --- /dev/null +++ b/src/workbench_cli/handlers/import_sbom.py @@ -0,0 +1,245 @@ +# workbench_cli/handlers/import_sbom.py + +import logging +import argparse +import os +from typing import TYPE_CHECKING, Dict, Tuple, Any +from ..utilities.error_handling import handler_error_wrapper +from ..exceptions import ( + WorkbenchCLIError, + ApiError, + NetworkError, + ValidationError, + ProcessError, + ProcessTimeoutError, + ProjectNotFoundError, + ScanNotFoundError, + FileSystemError, +) +from ..utilities.scan_workflows import ( + print_operation_summary, + fetch_display_save_results, + get_workbench_links +) +from ..utilities.scan_target_validators import ensure_scan_compatibility +from ..utilities.sbom_validator import SBOMValidator + +if TYPE_CHECKING: + from ..api import WorkbenchAPI + +logger = logging.getLogger("workbench-cli") + +def _validate_sbom_file(file_path: str) -> Tuple[str, str, Dict, Any]: + """ + Validates SBOM file and returns format information and parsed document. + + Args: + file_path: Path to the SBOM file to validate + + Returns: + tuple[str, str, Dict, Any]: (format, version, metadata, parsed_document) + + Raises: + ValidationError: If SBOM validation fails + FileSystemError: If file doesn't exist or can't be read + """ + try: + sbom_format, version, metadata, parsed_document = SBOMValidator.validate_sbom_file(file_path) + logger.debug(f"SBOM validation successful: {sbom_format} v{version}") + return sbom_format, version, metadata, parsed_document + except Exception as e: + logger.error(f"SBOM validation failed for '{file_path}': {e}") + raise + +def _prepare_sbom_for_upload(file_path: str, sbom_format: str, parsed_document: Any) -> Tuple[str, bool]: + """ + Prepares SBOM file for upload, converting format if needed. + + Args: + file_path: Original file path + sbom_format: Detected SBOM format + parsed_document: Parsed document from validation + + Returns: + tuple[str, bool]: (upload_path, temp_file_created) + + Raises: + ValidationError: If preparation/conversion fails + """ + try: + upload_path = SBOMValidator.prepare_sbom_for_upload(file_path, sbom_format, parsed_document) + temp_file_created = (upload_path != file_path) + logger.debug(f"SBOM preparation successful: upload_path={upload_path}, converted={temp_file_created}") + return upload_path, temp_file_created + except Exception as e: + logger.error(f"SBOM preparation failed for '{file_path}': {e}") + raise + +def _get_project_and_scan_codes(workbench: "WorkbenchAPI", params: argparse.Namespace) -> tuple[str, str]: + """ + Resolve project and scan codes for SBOM import. + + Args: + workbench: The Workbench API client instance + params: Command line parameters + + Returns: + tuple[str, str]: Project code and scan code + """ + project_code = workbench.resolve_project(params.project_name, create_if_missing=True) + + # Create scan with import_from_report=True + scan_code, _ = workbench.resolve_scan( + params.scan_name, + params.project_name, + create_if_missing=True, + params=params, + import_from_report=True + ) + return project_code, scan_code + +def _print_validation_summary(sbom_format: str, version: str, metadata: Dict): + """Prints a summary of the SBOM validation results.""" + print(f"SBOM validation successful:") + print(f" Format: {sbom_format.upper()}") + print(f" Version: {version}") + if sbom_format == "cyclonedx": + print(f" Components: {metadata.get('components_count', 'Unknown')}") + if metadata.get('serial_number'): + print(f" Serial Number: {metadata['serial_number']}") + elif sbom_format == "spdx": + print(f" Document Name: {metadata.get('name', 'Unknown')}") + print(f" Packages: {metadata.get('packages_count', 'Unknown')}") + print(f" Files: {metadata.get('files_count', 'Unknown')}") + +@handler_error_wrapper +def handle_import_sbom(workbench: "WorkbenchAPI", params: argparse.Namespace) -> bool: + """ + Handler for the 'import-sbom' command. Imports SBOM data from a file. + + Args: + workbench: The Workbench API client instance + params: Command line parameters + + Returns: + bool: True if the operation completed successfully + """ + print(f"\n--- Running {params.command.upper()} Command ---") + + # Initialize timing dictionary + durations = { + "sbom_import": 0.0 + } + + # Track upload path for cleanup + upload_path = None + temp_file_created = False + + try: + # Validate SBOM file FIRST - before any project/scan creation + print("\n--- Validating SBOM File ---") + sbom_format, version, metadata, parsed_document = _validate_sbom_file(params.path) + _print_validation_summary(sbom_format, version, metadata) + + # Prepare SBOM file for upload (convert if needed) + print("\n--- Preparing SBOM for Upload ---") + upload_path, temp_file_created = _prepare_sbom_for_upload(params.path, sbom_format, parsed_document) + + if temp_file_created: + print(f" Converted for upload: {os.path.basename(upload_path)}") + else: + print(f" Using original file format") + + # Resolve project and scan (find or create) - AFTER validation and preparation + print("\nChecking if the Project and Scan exist or need to be created...") + project_code, scan_code = _get_project_and_scan_codes(workbench, params) + + print(f"Processing SBOM import for scan '{scan_code}' in project '{project_code}'...") + print(f"Importing from: {params.path}") + + # Ensure scan is compatible with the current operation + ensure_scan_compatibility(workbench, params, scan_code) + + # Ensure scan is idle before starting SBOM import + print("\nEnsuring the Scan is idle before starting SBOM import...") + workbench.ensure_scan_is_idle(scan_code, params, ["REPORT_IMPORT"]) + + # Upload SBOM file using the prepared upload path + print("\n--- Uploading SBOM File ---") + try: + workbench.upload_sbom_file(scan_code=scan_code, path=upload_path) + print(f"SBOM file uploaded successfully from: {upload_path}") + except Exception as e: + logger.error(f"Failed to upload SBOM file for '{scan_code}': {e}", exc_info=True) + raise WorkbenchCLIError(f"Failed to upload SBOM file: {e}", details={"error": str(e)}) from e + + # Start SBOM import + print("\n--- Starting SBOM Import ---") + + try: + workbench.import_report(scan_code=scan_code) + print("SBOM import initiated successfully.") + except Exception as e: + logger.error(f"Failed to start SBOM import for '{scan_code}': {e}", exc_info=True) + raise WorkbenchCLIError(f"Failed to start SBOM import: {e}", details={"error": str(e)}) from e + + # Wait for SBOM import to complete + sbom_completed = False + try: + print("\nWaiting for SBOM import to complete...") + # Use optimized 2-second wait interval for import-only mode + _, import_duration = workbench.wait_for_scan_to_finish( + "REPORT_IMPORT", + scan_code, + params.scan_number_of_tries, + 2 # Use 2-second wait interval for import-only mode as it finishes faster + ) + + # Store the SBOM import duration + durations["sbom_import"] = import_duration + sbom_completed = True + + print("SBOM import completed successfully.") + + except (ProcessTimeoutError, ProcessError) as e: + logger.error(f"Error during SBOM import for '{scan_code}': {e}", exc_info=True) + raise + except Exception as e: + logger.error(f"Unexpected error during SBOM import for '{scan_code}': {e}", exc_info=True) + raise WorkbenchCLIError(f"Error during SBOM import: {e}", details={"error": str(e)}) from e + + # Print operation summary + print_operation_summary(params, sbom_completed, project_code, scan_code, durations) + + # Fetch and display results - CRITICAL: Match import-da implementation behavior + if sbom_completed: + print("\n--- Fetching Results ---") + try: + fetch_display_save_results(workbench, params, scan_code) + except Exception as e: + logger.warning(f"Failed to fetch and display results: {e}") + print(f"Warning: Failed to fetch and display results: {e}") + + # Add Workbench link for easy navigation to view SBOM results + try: + scan_info = workbench.get_scan_information(scan_code) + scan_id = scan_info.get('id') + if scan_id: + links = get_workbench_links(workbench.api_url, int(scan_id)) + main_link = links.get('main', {}) + if main_link.get('url'): + print(f"\nšŸ”— {main_link['message']}: {main_link['url']}") + except Exception as e: + logger.debug(f"Could not generate Workbench link: {e}") + # Don't fail the whole operation if link generation fails + + return sbom_completed + + finally: + # Clean up temporary file if one was created + if temp_file_created and upload_path: + try: + SBOMValidator.cleanup_temp_file(upload_path) + except Exception as e: + logger.warning(f"Failed to clean up temporary file: {e}") + # Don't fail the operation if cleanup fails diff --git a/src/workbench_cli/handlers/scan.py b/src/workbench_cli/handlers/scan.py index 88476be..6f4ecc4 100644 --- a/src/workbench_cli/handlers/scan.py +++ b/src/workbench_cli/handlers/scan.py @@ -85,8 +85,7 @@ def handle_scan(workbench: "WorkbenchAPI", params: argparse.Namespace) -> bool: # Assert scan is idle before uploading code print("\nEnsuring the Scan is idle before uploading code...") - workbench.ensure_process_can_start("SCAN", scan_code, wait_max_tries=60, wait_interval=30) - workbench.ensure_process_can_start("DEPENDENCY_ANALYSIS", scan_code, wait_max_tries=60, wait_interval=30) + workbench.ensure_scan_is_idle(scan_code, params, ["EXTRACT_ARCHIVES", "SCAN", "DEPENDENCY_ANALYSIS"]) # Clear existing scan content print("\nClearing existing scan content...") @@ -129,12 +128,7 @@ def handle_scan(workbench: "WorkbenchAPI", params: argparse.Namespace) -> bool: print("No archives to extract. Continuing with scan...") # Verify scan can start - workbench.ensure_process_can_start( - "SCAN", - scan_code, - params.scan_number_of_tries, - params.scan_wait_time - ) + workbench.ensure_scan_is_idle(scan_code, params, ["EXTRACT_ARCHIVES", "SCAN", "DEPENDENCY_ANALYSIS"]) # Determine which scan operations to run scan_operations = determine_scans_to_run(params) diff --git a/src/workbench_cli/handlers/scan_git.py b/src/workbench_cli/handlers/scan_git.py index 0c3fba8..63fb80c 100644 --- a/src/workbench_cli/handlers/scan_git.py +++ b/src/workbench_cli/handlers/scan_git.py @@ -16,7 +16,6 @@ ScanExistsError, ) from ..utilities.scan_workflows import ( - assert_scan_is_idle, wait_for_scan_completion, determine_scans_to_run, print_operation_summary, @@ -90,12 +89,7 @@ def handle_scan_git(workbench: "WorkbenchAPI", params: argparse.Namespace) -> bo # Ensure scan is idle before triggering Git clone print("\nEnsuring the Scan is idle before triggering Git clone...") - workbench.ensure_process_can_start( - "SCAN", - scan_code, - wait_max_tries=params.scan_number_of_tries, - wait_interval=params.scan_wait_time - ) + workbench.ensure_scan_is_idle(scan_code, params, ["GIT_CLONE", "SCAN", "DEPENDENCY_ANALYSIS"]) # Trigger Git clone git_ref_type = "tag" if params.git_tag else ("commit" if params.git_commit else "branch") @@ -131,12 +125,7 @@ def handle_scan_git(workbench: "WorkbenchAPI", params: argparse.Namespace) -> bo try: # Verify scan can start - workbench.ensure_process_can_start( - "SCAN", - scan_code, - wait_max_tries=params.scan_number_of_tries, - wait_interval=params.scan_wait_time - ) + workbench.ensure_scan_is_idle(scan_code, params, ["GIT_CLONE", "SCAN", "DEPENDENCY_ANALYSIS"]) # Handle dependency analysis only mode if not scan_operations["run_kb_scan"] and scan_operations["run_dependency_analysis"]: diff --git a/src/workbench_cli/handlers/show_results.py b/src/workbench_cli/handlers/show_results.py index 924921a..3d12e28 100644 --- a/src/workbench_cli/handlers/show_results.py +++ b/src/workbench_cli/handlers/show_results.py @@ -52,40 +52,11 @@ def handle_show_results(workbench: "WorkbenchAPI", params: argparse.Namespace) - params=params ) - # Wait for scan to complete before fetching results - print("\nChecking scan completion status...") - # This try/except block is necessary for the handler's logic to continue even if scan - # status checking fails - we still want to attempt to show results + # Ensure scan processes are idle before fetching results + print("\nEnsuring scans finished before showing results...") try: - # Check KB scan completion - kb_scan_completed = False - da_completed = False - - try: - kb_status_data = workbench.get_scan_status("SCAN", scan_code) - kb_scan_status = kb_status_data.get("status", "UNKNOWN").upper() - kb_scan_completed = (kb_scan_status == "FINISHED") - except Exception as e: - logger.warning(f"Could not check KB scan status for '{scan_code}': {e}") - - # Check dependency analysis completion - try: - da_status_data = workbench.get_scan_status("DEPENDENCY_ANALYSIS", scan_code) - da_scan_status = da_status_data.get("status", "UNKNOWN").upper() - da_completed = (da_scan_status == "FINISHED") - except Exception as e: - logger.debug(f"Could not check DA scan status for '{scan_code}': {e}") - # DA might not be available for this scan, which is fine - - if not kb_scan_completed: - print("\nWarning: The KB scan has not completed successfully. Results may be incomplete.") - logger.warning(f"Showing results for scan '{scan_code}' that has not completed successfully.") - - # Dependency analysis might not be needed for all result types, so just warn - if not da_completed and any([params.show_dependencies, params.show_vulnerabilities]): - print("\nNote: Dependency Analysis has not completed. Dependency-related results may be incomplete.") - logger.warning(f"Showing dependency results for scan '{scan_code}' without completed DA.") - + workbench.ensure_scan_is_idle(scan_code, params, ["SCAN", "DEPENDENCY_ANALYSIS"]) + except (ProcessTimeoutError, ProcessError, ApiError, NetworkError) as e: logger.warning(f"Could not verify scan completion for '{scan_code}': {e}. Proceeding anyway.") print("\nWarning: Could not verify scan completion status. Results may be incomplete.") diff --git a/src/workbench_cli/main.py b/src/workbench_cli/main.py index 19dfe35..124bc3d 100644 --- a/src/workbench_cli/main.py +++ b/src/workbench_cli/main.py @@ -26,6 +26,7 @@ from .handlers import ( handle_scan, handle_import_da, + handle_import_sbom, handle_show_results, handle_evaluate_gates, handle_download_reports, @@ -58,7 +59,7 @@ def main() -> int: console_handler = logging.StreamHandler(sys.stdout) console_formatter = logging.Formatter('%(levelname)s: %(message)s') # Simpler format for console console_handler.setFormatter(console_formatter) - console_handler.setLevel(logging.INFO if log_level <= logging.INFO else log_level) + console_handler.setLevel(log_level) # Use the same level as configured by user logging.getLogger().addHandler(console_handler) logger = logging.getLogger("workbench-cli") @@ -83,6 +84,7 @@ def main() -> int: COMMAND_HANDLERS = { "scan": handle_scan, "import-da": handle_import_da, + "import-sbom": handle_import_sbom, "show-results": handle_show_results, "evaluate-gates": handle_evaluate_gates, "download-reports": handle_download_reports, diff --git a/src/workbench_cli/utilities/__init__.py b/src/workbench_cli/utilities/__init__.py index 9614515..539f854 100644 --- a/src/workbench_cli/utilities/__init__.py +++ b/src/workbench_cli/utilities/__init__.py @@ -7,7 +7,6 @@ from .error_handling import format_and_print_error, handler_error_wrapper from .scan_workflows import ( - assert_scan_is_idle, wait_for_scan_completion, determine_scans_to_run, fetch_results, @@ -28,7 +27,6 @@ 'format_and_print_error', 'handler_error_wrapper', # Scan workflows - 'assert_scan_is_idle', 'wait_for_scan_completion', 'determine_scans_to_run', 'fetch_results', @@ -42,4 +40,4 @@ 'validate_reuse_source', # Archive preparation 'UploadArchivePrep', -] \ No newline at end of file +] diff --git a/src/workbench_cli/utilities/error_handling.py b/src/workbench_cli/utilities/error_handling.py index f417917..c6e1ee9 100644 --- a/src/workbench_cli/utilities/error_handling.py +++ b/src/workbench_cli/utilities/error_handling.py @@ -234,4 +234,4 @@ def wrapper(workbench, params): # Raise the wrapped error for proper exit code handling raise cli_error - return wrapper \ No newline at end of file + return wrapper diff --git a/src/workbench_cli/utilities/sbom_validator.py b/src/workbench_cli/utilities/sbom_validator.py new file mode 100644 index 0000000..9e340c2 --- /dev/null +++ b/src/workbench_cli/utilities/sbom_validator.py @@ -0,0 +1,404 @@ +# workbench_cli/utilities/sbom_validator.py + +import os +import json +import logging +import tempfile +from typing import Tuple, Dict, Any, Optional, Union +from pathlib import Path + +from ..exceptions import ValidationError, FileSystemError + +logger = logging.getLogger("workbench-cli") + +class SBOMValidator: + """ + Utility class for validating SBOM files and converting them to Workbench-compatible formats. + Supports CycloneDX JSON and SPDX in multiple formats (JSON, RDF, XML). + """ + + SUPPORTED_EXTENSIONS = {'.json', '.rdf', '.xml', '.spdx'} + + @staticmethod + def validate_sbom_file(file_path: str) -> Tuple[str, str, Dict[str, Any], Any]: + """ + Validates an SBOM file and returns format information and parsed document. + + Args: + file_path: Path to the SBOM file to validate + + Returns: + Tuple[str, str, Dict[str, Any], Any]: (format, version, metadata, parsed_document) + - format: "cyclonedx" or "spdx" + - version: version string (e.g., "1.6", "2.3") + - metadata: additional metadata about the document + - parsed_document: parsed document object for reuse in preparation + + Raises: + FileSystemError: If the file doesn't exist or can't be read + ValidationError: If the file is not a valid SBOM or unsupported format/version + """ + if not os.path.exists(file_path): + raise FileSystemError(f"SBOM file does not exist: {file_path}") + + if not os.path.isfile(file_path): + raise ValidationError(f"Path must be a file: {file_path}") + + file_ext = Path(file_path).suffix.lower() + if file_ext not in SBOMValidator.SUPPORTED_EXTENSIONS: + raise ValidationError(f"Unsupported file extension '{file_ext}'. Supported extensions: {', '.join(SBOMValidator.SUPPORTED_EXTENSIONS)}") + + logger.debug(f"Validating SBOM file: {file_path}") + + # Detect format by content, not extension + sbom_format = SBOMValidator._detect_sbom_format(file_path) + logger.debug(f"Detected SBOM format: {sbom_format}") + + if sbom_format == "cyclonedx": + return SBOMValidator._validate_cyclonedx(file_path) + elif sbom_format == "spdx": + return SBOMValidator._validate_spdx(file_path) + + # This case is defensive, as _detect_sbom_format should have already raised an error + raise ValidationError(f"Unable to determine SBOM format for file: {file_path}") + + @staticmethod + def prepare_sbom_for_upload(file_path: str, sbom_format: str, parsed_document: Any) -> str: + """ + Prepares an SBOM file for upload to Workbench, converting format if needed. + + Args: + file_path: Original file path + sbom_format: Format detected during validation ("cyclonedx" or "spdx") + parsed_document: Parsed document from validation step + + Returns: + str: Path to file ready for upload (original or converted temp file) + + Raises: + ValidationError: If conversion fails + """ + if sbom_format == "cyclonedx": + # CycloneDX is already in JSON format that Workbench expects + return file_path + elif sbom_format == "spdx": + return SBOMValidator._prepare_spdx_for_upload(file_path, parsed_document) + else: + raise ValidationError(f"Unknown SBOM format: {sbom_format}") + + @staticmethod + def validate_and_prepare_sbom(file_path: str) -> Tuple[str, str, Dict[str, Any], str]: + """ + Validates an SBOM file and prepares it for upload to Workbench. + This is a convenience method that combines validation and preparation. + + Args: + file_path: Path to the SBOM file to validate + + Returns: + Tuple[str, str, Dict[str, Any], str]: (format, version, metadata, upload_path) + - format: "cyclonedx" or "spdx" + - version: version string (e.g., "1.6", "2.3") + - metadata: additional metadata about the document + - upload_path: path to file ready for upload (original or converted temp file) + + Raises: + FileSystemError: If the file doesn't exist or can't be read + ValidationError: If the file is not a valid SBOM or unsupported format/version + """ + # Validate the SBOM file + sbom_format, version, metadata, parsed_document = SBOMValidator.validate_sbom_file(file_path) + + # Prepare for upload + upload_path = SBOMValidator.prepare_sbom_for_upload(file_path, sbom_format, parsed_document) + + return sbom_format, version, metadata, upload_path + + @staticmethod + def _detect_sbom_format(file_path: str) -> str: + """ + Detects SBOM format by examining file content. + + Returns: + str: "cyclonedx" or "spdx" + """ + try: + with open(file_path, 'r', encoding='utf-8') as f: + # Read first few KB to detect format + content_preview = f.read(8192) + except UnicodeDecodeError: + # If it's not UTF-8, it might be RDF/XML + try: + with open(file_path, 'r', encoding='latin-1') as f: + content_preview = f.read(8192) + except Exception as e: + raise ValidationError(f"Unable to read file content: {e}") + except Exception as e: + raise ValidationError(f"Unable to read file: {e}") + + content_lower = content_preview.lower() + + # Check for CycloneDX markers + if '"bomformat"' in content_lower and '"cyclonedx"' in content_lower: + return "cyclonedx" + if '"bomFormat"' in content_preview and '"CycloneDX"' in content_preview: + return "cyclonedx" + + # Check for SPDX markers + spdx_markers = [ + '"spdxVersion"', '"spdxversion"', # JSON format + '"SPDXID"', '"spdxid"', # JSON format + 'spdx:Document', 'spdx:document', # RDF format + ' Tuple[str, str, Dict[str, Any], Dict]: + """ + Validates a CycloneDX file (JSON format). + + Returns: + Tuple[str, str, Dict[str, Any], Dict]: (format, version, metadata, parsed_bom) + """ + try: + from cyclonedx.validation.json import JsonStrictValidator + from cyclonedx.schema import SchemaVersion + except ImportError as e: + raise ValidationError("CycloneDX library not available. Please install cyclonedx-python-lib.") from e + + try: + # Read the JSON file + with open(file_path, 'r', encoding='utf-8') as f: + content = f.read() + + # Parse JSON to check format and extract metadata + bom_data = json.loads(content) + + # Check if it looks like a CycloneDX BOM + if "bomFormat" not in bom_data or bom_data.get("bomFormat") != "CycloneDX": + raise ValidationError("File does not appear to be a CycloneDX BOM (missing or incorrect bomFormat)") + + # Get spec version + spec_version = bom_data.get("specVersion", "") + if not spec_version: + raise ValidationError("CycloneDX BOM is missing specVersion field") + + # Map spec version to SchemaVersion enum + version_mapping = { + "1.6": SchemaVersion.V1_6, + "1.5": SchemaVersion.V1_5, + "1.4": SchemaVersion.V1_4, + "1.3": SchemaVersion.V1_3, + "1.2": SchemaVersion.V1_2, + "1.1": SchemaVersion.V1_1, + "1.0": SchemaVersion.V1_0 + } + + schema_version = version_mapping.get(spec_version) + if not schema_version: + raise ValidationError(f"Unknown CycloneDX version {spec_version}. Supported versions for validation: {', '.join(version_mapping.keys())}") + + # Validate using the official validator for the detected version + validator = JsonStrictValidator(schema_version) + try: + validation_errors = list(validator.validate_str(content)) + if validation_errors: + error_messages = [str(error) for error in validation_errors[:5]] # Show first 5 errors + raise ValidationError(f"CycloneDX validation failed: {'; '.join(error_messages)}") + except ValidationError: + raise # Re-raise validation errors as-is + except Exception as validation_error: + # If the validator itself fails, still try to proceed but log the issue + logger.warning(f"CycloneDX validator encountered an issue: {validation_error}") + # We'll still proceed if basic structure is valid + + # Check if version is supported for upload (1.4-1.6) + supported_upload_versions = ["1.4", "1.5", "1.6"] + if spec_version not in supported_upload_versions: + raise ValidationError(f"Valid CycloneDX {spec_version} SBOM detected, but only versions {', '.join(supported_upload_versions)} are supported for import. Please convert your SBOM to a supported version.") + + logger.debug(f"Successfully validated CycloneDX file, version {spec_version}") + + # Extract metadata + metadata = { + "spec_version": spec_version, + "serial_number": bom_data.get("serialNumber"), + "version": bom_data.get("version", 1), + "components_count": len(bom_data.get("components", [])) + } + + return "cyclonedx", spec_version, metadata, bom_data + + except json.JSONDecodeError as e: + raise ValidationError(f"Invalid JSON format: {e}") from e + except FileNotFoundError: + raise FileSystemError(f"SBOM file not found: {file_path}") + except ValidationError: + raise # Re-raise validation errors as-is + except Exception as e: + logger.error(f"Unexpected error validating CycloneDX file '{file_path}': {e}", exc_info=True) + raise ValidationError(f"Failed to validate CycloneDX file: {e}") from e + + @staticmethod + def _validate_spdx(file_path: str) -> Tuple[str, str, Dict[str, Any], Any]: + """ + Validates an SPDX file in any supported format. + + Returns: + Tuple[str, str, Dict[str, Any], Any]: (format, version, metadata, parsed_document) + """ + try: + from spdx_tools.spdx.parser.parse_anything import parse_file + from spdx_tools.spdx.model import Document, Version + from spdx_tools.spdx.validation.document_validator import validate_full_spdx_document + except ImportError as e: + raise ValidationError("SPDX tools library not available. Please install spdx-tools.") from e + + try: + # Parse the SPDX file (handles JSON, RDF, XML, etc.) + document = parse_file(file_path) + + if not isinstance(document, Document): + raise ValidationError("File does not contain a valid SPDX document") + + # Validate the document + validation_messages = validate_full_spdx_document(document) + if validation_messages: + error_messages = [msg.validation_message for msg in validation_messages] + raise ValidationError(f"SPDX document validation failed: {'; '.join(error_messages[:5])}") # Show first 5 errors + + # Get version + spdx_version = document.creation_info.spdx_version + if isinstance(spdx_version, Version): + version_str = spdx_version.value.replace("SPDX-", "") + else: + version_str = str(spdx_version).replace("SPDX-", "") + + # Check if version is supported (2.0-2.3) + supported_versions = {"2.0", "2.1", "2.2", "2.3"} + if version_str not in supported_versions: + raise ValidationError(f"SPDX version {version_str} is not supported. Supported versions: {', '.join(supported_versions)}") + + logger.debug(f"Successfully validated SPDX file, version {version_str}") + + metadata = { + "spdx_version": version_str, + "name": document.creation_info.name, + "document_namespace": document.creation_info.document_namespace, + "packages_count": len(document.packages) if document.packages else 0, + "files_count": len(document.files) if document.files else 0 + } + + return "spdx", version_str, metadata, document + + except ValidationError: + raise # Re-raise validation errors as-is + except FileNotFoundError: + raise FileSystemError(f"SBOM file not found: {file_path}") + except Exception as e: + logger.error(f"Unexpected error validating SPDX file '{file_path}': {e}", exc_info=True) + raise ValidationError(f"Failed to validate SPDX file: {e}") from e + + @staticmethod + def _prepare_spdx_for_upload(file_path: str, document: Any) -> str: + """ + Prepares SPDX document for upload, converting to RDF format if needed. + + Args: + file_path: Original file path + document: Parsed SPDX document + + Returns: + str: Path to file ready for upload (original or converted temp file) + """ + # Check if we need to convert to RDF format for Workbench + file_ext = Path(file_path).suffix.lower() + if file_ext == '.json': + # Convert JSON SPDX to RDF format + logger.debug("Converting SPDX JSON to RDF format for Workbench compatibility") + + try: + from spdx_tools.spdx.writer.write_anything import write_file + except ImportError as e: + raise ValidationError("SPDX tools library not available for conversion. Please install spdx-tools.") from e + + # Create temporary RDF file + temp_fd, temp_path = tempfile.mkstemp(suffix='.rdf', prefix='spdx_converted_') + try: + os.close(temp_fd) # Close the file descriptor + + # Write document as RDF + write_file(document, temp_path, validate=False) # Already validated above + + logger.debug(f"Successfully converted SPDX to RDF format: {temp_path}") + return temp_path + + except Exception as e: + # Clean up temp file if conversion fails + try: + os.unlink(temp_path) + except Exception: + pass + raise ValidationError(f"Failed to convert SPDX JSON to RDF format: {e}") from e + else: + # Already in RDF/XML format, use original file + return file_path + + @staticmethod + def get_supported_formats() -> Dict[str, Dict[str, Any]]: + """ + Returns information about supported SBOM formats. + + Returns: + Dict containing supported formats and their details + """ + return { + "cyclonedx": { + "name": "CycloneDX", + "supported_versions": ["1.4", "1.5", "1.6"], + "supported_extensions": [".json"], + "description": "CycloneDX JSON format" + }, + "spdx": { + "name": "SPDX", + "supported_versions": ["2.0", "2.1", "2.2", "2.3"], + "supported_extensions": [".json", ".rdf", ".xml", ".spdx"], + "description": "SPDX in JSON, RDF, or XML format (converted to RDF for upload)" + } + } + + @staticmethod + def cleanup_temp_file(file_path: str) -> None: + """ + Clean up temporary files created during conversion. + + Args: + file_path: Path to temporary file to clean up + """ + if file_path and os.path.exists(file_path) and file_path.startswith(tempfile.gettempdir()): + try: + os.unlink(file_path) + logger.debug(f"Cleaned up temporary file: {file_path}") + except Exception as e: + logger.warning(f"Failed to clean up temporary file {file_path}: {e}") + + # Keep the old method for backward compatibility but mark as deprecated + @staticmethod + def validate_sbom_file_deprecated(file_path: str) -> Tuple[str, str, Dict[str, Any]]: + """ + DEPRECATED: Use validate_sbom_file or validate_and_prepare_sbom instead. + This method is kept for backward compatibility. + """ + logger.warning("This validate_sbom_file method is deprecated. Use the new validate_sbom_file or validate_and_prepare_sbom instead.") + format_name, version, metadata, _ = SBOMValidator.validate_sbom_file(file_path) + return format_name, version, metadata diff --git a/src/workbench_cli/utilities/scan_target_validators.py b/src/workbench_cli/utilities/scan_target_validators.py index eb2ed94..c79eadd 100644 --- a/src/workbench_cli/utilities/scan_target_validators.py +++ b/src/workbench_cli/utilities/scan_target_validators.py @@ -7,7 +7,7 @@ import logging import argparse -from typing import Optional, Tuple +from typing import TYPE_CHECKING, Optional, Tuple from ..exceptions import ( WorkbenchCLIError, @@ -20,10 +20,13 @@ ScanNotFoundError ) +if TYPE_CHECKING: + from ..api import WorkbenchAPI + # Assume logger is configured in main.py logger = logging.getLogger("workbench-cli") -def ensure_scan_compatibility(workbench: 'WorkbenchAPI', params: argparse.Namespace, scan_code: str): +def ensure_scan_compatibility(workbench: "WorkbenchAPI", params: argparse.Namespace, scan_code: str): """ Checks if the existing scan configuration is compatible with the current command. Fetches scan information directly from the API. @@ -54,6 +57,10 @@ def ensure_scan_compatibility(workbench: 'WorkbenchAPI', params: argparse.Namesp # The API puts both branch and tag *values* in the 'git_branch' field existing_git_ref_value = existing_scan_info.get("git_branch") existing_git_ref_type = existing_scan_info.get("git_ref_type") # Directly get the type ('tag' or 'branch') + existing_is_from_report = existing_scan_info.get("is_from_report", "0") # Default to "0" if not present + + # Convert string to boolean for easier comparison + existing_is_report_scan = existing_is_from_report in ["1", 1, True, "true"] # --- Read current command info --- current_command = params.command @@ -69,10 +76,14 @@ def ensure_scan_compatibility(workbench: 'WorkbenchAPI', params: argparse.Namesp # --- Compatibility Checks --- if current_command == 'scan': - if existing_git_repo: + if existing_is_report_scan: + error_message = f"Scan '{scan_code}' was created for SBOM import and cannot be reused for code upload via --path." + elif existing_git_repo: error_message = f"Scan '{scan_code}' was created for Git scanning (Repo: {existing_git_repo}) and cannot be reused for code upload via --path." elif current_command == 'scan-git': - if not existing_git_repo: + if existing_is_report_scan: + error_message = f"Scan '{scan_code}' was created for SBOM import and cannot be reused for Git scanning." + elif not existing_git_repo: error_message = f"Scan '{scan_code}' was created for code upload (using --path) and cannot be reused for Git scanning." elif existing_git_repo != current_git_url: error_message = (f"Scan '{scan_code}' already exists but is configured for a different Git repository " @@ -88,8 +99,11 @@ def ensure_scan_compatibility(workbench: 'WorkbenchAPI', params: argparse.Namesp f"but current command specified {current_git_ref_type or 'ref'} '{current_git_ref_value}'. " f"Please use a different --scan-name or use the matching ref.") elif current_command == 'import-da': - # DA import doesn't care about the original scan type. - pass + if existing_is_report_scan: + error_message = f"Scan '{scan_code}' was created for SBOM import and cannot be reused for dependency analysis import." + elif current_command == 'import-sbom': + if not existing_is_report_scan: + error_message = f"Scan '{scan_code}' was not created for SBOM import and cannot be reused for SBOM import. Only scans created with 'import-sbom' can be reused for SBOM operations." # --- Error Handling --- if error_message: @@ -106,8 +120,10 @@ def ensure_scan_compatibility(workbench: 'WorkbenchAPI', params: argparse.Namesp logger.debug(f"Reusing existing scan '{scan_code}' configured for code upload.") elif current_command == 'import-da': logger.debug(f"Reusing existing scan '{scan_code}' for DA import.") + elif current_command == 'import-sbom': + logger.debug(f"Reusing existing scan '{scan_code}' for SBOM import (report scan: {existing_is_report_scan}).") -def validate_reuse_source(workbench: 'WorkbenchAPI', params: argparse.Namespace) -> Tuple[Optional[str], Optional[str]]: +def validate_reuse_source(workbench: "WorkbenchAPI", params: argparse.Namespace) -> Tuple[Optional[str], Optional[str]]: """ Validates ID reuse source (project or scan) before uploading code or starting a scan to prevent unnecessary work if the source doesn't exist. diff --git a/src/workbench_cli/utilities/scan_workflows.py b/src/workbench_cli/utilities/scan_workflows.py index d1dbd62..6737328 100644 --- a/src/workbench_cli/utilities/scan_workflows.py +++ b/src/workbench_cli/utilities/scan_workflows.py @@ -74,81 +74,6 @@ def get_workbench_links(api_url: str, scan_id: int) -> Dict[str, Dict[str, str]] # --- Process Waiters and Checkers --- -def assert_scan_is_idle( - workbench: 'WorkbenchAPI', - scan_code: str, - params: argparse.Namespace, - process_types_to_check: List[str] -): - """ - Checks if specified background processes for a scan are idle (not RUNNING or QUEUED). - If a process is running/queued, waits for it to finish. - """ - logger.debug(f"Asserting idle status for processes {process_types_to_check} on scan '{scan_code}'...") - while True: - all_processes_idle_this_pass = True - logger.debug("Starting a new pass to check idle status...") - for process_type in process_types_to_check: - process_type_upper = process_type.upper() - logger.debug(f"Checking status for process type: {process_type_upper}") - current_status = "UNKNOWN" - try: - if process_type_upper == "GIT_CLONE": - current_status = workbench.check_status_download_content_from_git(scan_code).upper() - elif process_type_upper in ["SCAN", "DEPENDENCY_ANALYSIS"]: - status_data = workbench.get_scan_status(process_type_upper, scan_code) - current_status = status_data.get("status", "UNKNOWN").upper() - elif process_type_upper == "EXTRACT_ARCHIVES": - # EXTRACT_ARCHIVES status checking is handled differently - # Check if status checking is supported for this process type - if workbench._is_status_check_supported(scan_code, "EXTRACT_ARCHIVES"): - # Use the specialized method for checking archive extraction status - try: - status_data = workbench.get_scan_status("EXTRACT_ARCHIVES", scan_code) - current_status = workbench._standard_scan_status_accessor(status_data) - except (ApiError, ScanNotFoundError) as e: - logger.debug(f"Could not check EXTRACT_ARCHIVES status, assuming finished: {e}") - current_status = "FINISHED" - else: - logger.debug(f"EXTRACT_ARCHIVES status checking not supported. Assuming idle.") - current_status = "FINISHED" - else: - logger.warning(f"Unknown process type '{process_type_upper}' requested for idle check. Skipping.") - continue - logger.debug(f"Current status for {process_type_upper}: {current_status}") - except ScanNotFoundError: - logger.debug(f"Scan '{scan_code}' not found during idle check for {process_type_upper}. Assuming idle.") - print(f" - {process_type_upper}: Not found (considered idle).") - continue - except (ApiError, NetworkError) as e: - raise ProcessError(f"Cannot proceed: Failed to check status for {process_type_upper} due to API/Network error: {e}") from e - except Exception as e: - raise ProcessError(f"Cannot proceed: Unexpected error checking status for {process_type_upper}: {e}") from e - - if current_status in ["RUNNING", "QUEUED", "NOT FINISHED"]: - all_processes_idle_this_pass = False - print(f" - {process_type_upper}: Status is {current_status}. Waiting for completion...") - try: - if process_type_upper == "GIT_CLONE": - _, _ = workbench.wait_for_git_clone(scan_code, params.scan_number_of_tries, params.scan_wait_time) - elif process_type_upper == "EXTRACT_ARCHIVES": - _, _ = workbench.wait_for_archive_extraction(scan_code, params.scan_number_of_tries, params.scan_wait_time) - else: - _, _ = workbench.wait_for_scan_to_finish(process_type_upper, scan_code, params.scan_number_of_tries, params.scan_wait_time) - print(f" - {process_type_upper}: Previous run finished.") - logger.debug(f"Breaking inner loop after waiting for {process_type_upper} to re-check all statuses.") - break - except (ProcessTimeoutError, ProcessError) as wait_err: - raise ProcessError(f"Cannot proceed: Waiting for existing {process_type_upper} failed: {wait_err}") from wait_err - except Exception as wait_exc: - raise ProcessError(f"Cannot proceed: Unexpected error waiting for {process_type_upper}: {wait_exc}") from wait_exc - else: - print(f" - {process_type_upper}: Status is {current_status} (considered idle).") - - if all_processes_idle_this_pass: - logger.debug("All processes confirmed idle in this pass. Exiting check loop.") - break - print("All Scan status checks passed! Proceeding...") def wait_for_scan_completion(workbench: 'WorkbenchAPI', params: argparse.Namespace, scan_code: str) -> Tuple[bool, bool, Dict[str, float]]: """ @@ -572,6 +497,9 @@ def print_operation_summary(params: argparse.Namespace, da_completed: bool, proj elif params.command == 'import-da': print(f" - Method: Dependency Analysis Import") print(f" - Source Path: {getattr(params, 'path', 'N/A')}") + elif params.command == 'import-sbom': + print(f" - Method: SBOM Import") + print(f" - Source Path: {getattr(params, 'path', 'N/A')}") else: print(f" - Method: Unknown ({params.command})") @@ -602,7 +530,9 @@ def print_operation_summary(params: argparse.Namespace, da_completed: bool, proj print(f" - Dependency Analysis: Yes (Duration: {da_duration_str})") elif params.command == 'import-da': print(f" - Dependency Analysis: Imported") + elif params.command == 'import-sbom': + print(f" - SBOM Imported: Yes") else: print(f" - Dependency Analysis: No") - print("------------------------------------") \ No newline at end of file + print("------------------------------------") diff --git a/tests/fixtures/cyclonedx-bom.json b/tests/fixtures/cyclonedx-bom.json new file mode 100644 index 0000000..95e6dce --- /dev/null +++ b/tests/fixtures/cyclonedx-bom.json @@ -0,0 +1 @@ +{"bomFormat":"CycloneDX","specVersion":"1.5","serialNumber":"urn:uuid:f8239a85-0452-4eaa-8116-435cadf21725","version":1,"metadata":{"timestamp":"2025-06-20T22:19:01Z","authors":[{"name":"tomas.gonzalez@fossid.com","email":"tomas.gonzalez@fossid.com","phone":"000-000-0000"}],"properties":[{"name":"project_name","value":"ProjectMix_267"},{"name":"project_code","value":"ProjectMix"}],"tools":{"components":[{"name":"Workbench","type":"application","version":"2025.1.0#14868210464","supplier":{"name":"FossID","url":["https:\/\/fossid.com"]},"bom-ref":"Workbench_2025.1.0#14868210464_6e82ad71-3ed9-40fc-acb4-94a55fc8dacc"}]}},"components":[{"name":"android_frameworks_base","type":"library","licenses":[{"license":{"id":"Apache-2.0","text":{"contentType":"text\/plain","encoding":"base64","content":"QXBhY2hlIExpY2Vuc2UKVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNApodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvCgpURVJNUyBBTkQgQ09ORElUSU9OUyBGT1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04KCjEuIERlZmluaXRpb25zLgoKIkxpY2Vuc2UiIHNoYWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBhcyBkZWZpbmVkIGJ5IFNlY3Rpb25zIDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuCgoiTGljZW5zb3IiIHNoYWxsIG1lYW4gdGhlIGNvcHlyaWdodCBvd25lciBvciBlbnRpdHkgYXV0aG9yaXplZCBieSB0aGUgY29weXJpZ2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhlIExpY2Vuc2UuCgoiTGVnYWwgRW50aXR5IiBzaGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsIG90aGVyIGVudGl0aWVzIHRoYXQgY29udHJvbCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRlciBjb21tb24gY29udHJvbCB3aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIsIGRpcmVjdCBvciBpbmRpcmVjdCwgdG8gY2F1c2UgdGhlIGRpcmVjdGlvbiBvciBtYW5hZ2VtZW50IG9mIHN1Y2ggZW50aXR5LCB3aGV0aGVyIGJ5IGNvbnRyYWN0IG9yIG90aGVyd2lzZSwgb3IgKGlpKSBvd25lcnNoaXAgb2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZSBvdXRzdGFuZGluZyBzaGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJzaGlwIG9mIHN1Y2ggZW50aXR5LgoKIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eSBleGVyY2lzaW5nIHBlcm1pc3Npb25zIGdyYW50ZWQgYnkgdGhpcyBMaWNlbnNlLgoKIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3IgbWFraW5nIG1vZGlmaWNhdGlvbnMsIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gc29mdHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRpb24gc291cmNlLCBhbmQgY29uZmlndXJhdGlvbiBmaWxlcy4KCiJPYmplY3QiIGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9ybSByZXN1bHRpbmcgZnJvbSBtZWNoYW5pY2FsIHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5zbGF0aW9uIG9mIGEgU291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gY29tcGlsZWQgb2JqZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLCBhbmQgY29udmVyc2lvbnMgdG8gb3RoZXIgbWVkaWEgdHlwZXMuCgoiV29yayIgc2hhbGwgbWVhbiB0aGUgd29yayBvZiBhdXRob3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgbWFkZSBhdmFpbGFibGUgdW5kZXIgdGhlIExpY2Vuc2UsIGFzIGluZGljYXRlZCBieSBhIGNvcHlyaWdodCBub3RpY2UgdGhhdCBpcyBpbmNsdWRlZCBpbiBvciBhdHRhY2hlZCB0byB0aGUgd29yayAoYW4gZXhhbXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBwZW5kaXggYmVsb3cpLgoKIkRlcml2YXRpdmUgV29ya3MiIHNoYWxsIG1lYW4gYW55IHdvcmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdCBmb3JtLCB0aGF0IGlzIGJhc2VkIG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBmb3Igd2hpY2ggdGhlIGVkaXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBlbGFib3JhdGlvbnMsIG9yIG90aGVyIG1vZGlmaWNhdGlvbnMgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBhbiBvcmlnaW5hbCB3b3JrIG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyBMaWNlbnNlLCBEZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQgcmVtYWluIHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAob3IgYmluZCBieSBuYW1lKSB0byB0aGUgaW50ZXJmYWNlcyBvZiwgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZi4KCiJDb250cmlidXRpb24iIHNoYWxsIG1lYW4gYW55IHdvcmsgb2YgYXV0aG9yc2hpcCwgaW5jbHVkaW5nIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBhbnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMgdG8gdGhhdCBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5IHN1Ym1pdHRlZCB0byBMaWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRoZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgYnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXplZCB0byBzdWJtaXQgb24gYmVoYWxmIG9mIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIiBtZWFucyBhbnkgZm9ybSBvZiBlbGVjdHJvbmljLCB2ZXJiYWwsIG9yIHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBzZW50IHRvIHRoZSBMaWNlbnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBtYWlsaW5nIGxpc3RzLCBzb3VyY2UgY29kZSBjb250cm9sIHN5c3RlbXMsIGFuZCBpc3N1ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQgYXJlIG1hbmFnZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwgdGhlIExpY2Vuc29yIGZvciB0aGUgcHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXByb3ZpbmcgdGhlIFdvcmssIGJ1dCBleGNsdWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlzIGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVyd2lzZSBkZXNpZ25hdGVkIGluIHdyaXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAiTm90IGEgQ29udHJpYnV0aW9uLiIKCiJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNvciBhbmQgYW55IGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IG9uIGJlaGFsZiBvZiB3aG9tIGEgQ29udHJpYnV0aW9uIGhhcyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZCBzdWJzZXF1ZW50bHkgaW5jb3Jwb3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCjIuIEdyYW50IG9mIENvcHlyaWdodCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB0aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1YWwsIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUsIGlycmV2b2NhYmxlIGNvcHlyaWdodCBsaWNlbnNlIHRvIHJlcHJvZHVjZSwgcHJlcGFyZSBEZXJpdmF0aXZlIFdvcmtzIG9mLCBwdWJsaWNseSBkaXNwbGF5LCBwdWJsaWNseSBwZXJmb3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUgV29yayBhbmQgc3VjaCBEZXJpdmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4KCjMuIEdyYW50IG9mIFBhdGVudCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB0aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1YWwsIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUsIGlycmV2b2NhYmxlIChleGNlcHQgYXMgc3RhdGVkIGluIHRoaXMgc2VjdGlvbikgcGF0ZW50IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLCB1c2UsIG9mZmVyIHRvIHNlbGwsIHNlbGwsIGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29yaywgd2hlcmUgc3VjaCBsaWNlbnNlIGFwcGxpZXMgb25seSB0byB0aG9zZSBwYXRlbnQgY2xhaW1zIGxpY2Vuc2FibGUgYnkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNlc3NhcmlseSBpbmZyaW5nZWQgYnkgdGhlaXIgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9yIGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENvbnRyaWJ1dGlvbihzKSB3aXRoIHRoZSBXb3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9uKHMpIHdhcyBzdWJtaXR0ZWQuIElmIFlvdSBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24gYWdhaW5zdCBhbnkgZW50aXR5IChpbmNsdWRpbmcgYSBjcm9zcy1jbGFpbSBvciBjb3VudGVyY2xhaW0gaW4gYSBsYXdzdWl0KSBhbGxlZ2luZyB0aGF0IHRoZSBXb3JrIG9yIGEgQ29udHJpYnV0aW9uIGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGlyZWN0IG9yIGNvbnRyaWJ1dG9yeSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGljZW5zZXMgZ3JhbnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsgc2hhbGwgdGVybWluYXRlIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0aWdhdGlvbiBpcyBmaWxlZC4KCjQuIFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBjb3BpZXMgb2YgdGhlIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mIGluIGFueSBtZWRpdW0sIHdpdGggb3Igd2l0aG91dCBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9yIE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdSBtZWV0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczoKCiAgICAgKGEpIFlvdSBtdXN0IGdpdmUgYW55IG90aGVyIHJlY2lwaWVudHMgb2YgdGhlIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgKGIpIFlvdSBtdXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBwcm9taW5lbnQgbm90aWNlcyBzdGF0aW5nIHRoYXQgWW91IGNoYW5nZWQgdGhlIGZpbGVzOyBhbmQKCiAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsbCBjb3B5cmlnaHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQgYXR0cmlidXRpb24gbm90aWNlcyBmcm9tIHRoZSBTb3VyY2UgZm9ybSBvZiB0aGUgV29yaywgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrczsgYW5kCgogICAgIChkKSBJZiB0aGUgV29yayBpbmNsdWRlcyBhICJOT1RJQ0UiIHRleHQgZmlsZSBhcyBwYXJ0IG9mIGl0cyBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0IGluY2x1ZGUgYSByZWFkYWJsZSBjb3B5IG9mIHRoZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZCB3aXRoaW4gc3VjaCBOT1RJQ0UgZmlsZSwgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiB3aXRoaW4gYSBOT1RJQ0UgdGV4dCBmaWxlIGRpc3RyaWJ1dGVkIGFzIHBhcnQgb2YgdGhlIERlcml2YXRpdmUgV29ya3M7IHdpdGhpbiB0aGUgU291cmNlIGZvcm0gb3IgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsIHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBhbmQgd2hlcmV2ZXIgc3VjaCB0aGlyZC1wYXJ0eSBub3RpY2VzIG5vcm1hbGx5IGFwcGVhci4gVGhlIGNvbnRlbnRzIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQgZG8gbm90IG1vZGlmeSB0aGUgTGljZW5zZS4gWW91IG1heSBhZGQgWW91ciBvd24gYXR0cmlidXRpb24gbm90aWNlcyB3aXRoaW4gRGVyaXZhdGl2ZSBXb3JrcyB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbG9uZ3NpZGUgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkIHRoYXQgc3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0aW9uIG5vdGljZXMgY2Fubm90IGJlIGNvbnN0cnVlZCBhcyBtb2RpZnlpbmcgdGhlIExpY2Vuc2UuCgogICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZCBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aCB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLCBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZSBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZSBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCjcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLCBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55IHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCjguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LCB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLCBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZSBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZyB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLCBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LCBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcyBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seSBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZiBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eSBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgpBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgpUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZyBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYSBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llciBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgpDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwp5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCllvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCgpVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCmRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgpTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCmxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLg=="},"url":"https:\/\/www.apache.org\/licenses\/LICENSE-2.0"}}],"version":"android-n-mr1-preview-1","purl":"pkg:github\/crdroidandroid\/android_frameworks_base@android-n-mr1-preview-1","supplier":{"name":"crdroidandroid"},"bom-ref":"android_frameworks_base_android-n-mr1-preview-1_e3edaf6e-04b6-4456-b26d-99427b51acfd","description":"","copyright":"\u2022 The Android Open Source Project (2005-2008)\n\u2022 The Apache Software Foundation (1999-2006)\n\u2022 The Apache Software Foundation (2005-2006)\n\u2022 Nuance Communications, but (2007-2007)\n\u2022 PacketVideo, but (1998-2009)\n\u2022 Apple Computer, Inc. but (2004-2004)\n\u2022 John Cowan (2002-2008)\n\u2022 VisualOn, but (2003-2010)\n\u2022 NXP Software (2004-2010)\n\u2022 The Android Open Source Project, but (2010-2010)\n\u2022 Unicode, Inc. (1991-2008)\n","properties":[{"name":"component_id","value":"12139"}]},{"name":"ofp","type":"library","licenses":[{"license":{"id":"BSD-3-Clause","text":{"contentType":"text\/plain","encoding":"base64","content":"Q29weXJpZ2h0IChjKSA8eWVhcj4gPG93bmVyPi4gCgpSZWRpc3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdpdGhvdXQgbW9kaWZpY2F0aW9uLCBhcmUgcGVybWl0dGVkIHByb3ZpZGVkIHRoYXQgdGhlIGZvbGxvd2luZyBjb25kaXRpb25zIGFyZSBtZXQ6CgoxLiBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNvZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuCgoyLiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIgaW4gdGhlIGRvY3VtZW50YXRpb24gYW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92aWRlZCB3aXRoIHRoZSBkaXN0cmlidXRpb24uCgozLiBOZWl0aGVyIHRoZSBuYW1lIG9mIHRoZSBjb3B5cmlnaHQgaG9sZGVyIG5vciB0aGUgbmFtZXMgb2YgaXRzIGNvbnRyaWJ1dG9ycyBtYXkgYmUgdXNlZCB0byBlbmRvcnNlIG9yIHByb21vdGUgcHJvZHVjdHMgZGVyaXZlZCBmcm9tIHRoaXMgc29mdHdhcmUgd2l0aG91dCBzcGVjaWZpYyBwcmlvciB3cml0dGVuIHBlcm1pc3Npb24uCgpUSElTIFNPRlRXQVJFIElTIFBST1ZJREVEIEJZIFRIRSBDT1BZUklHSFQgSE9MREVSUyBBTkQgQ09OVFJJQlVUT1JTICJBUyBJUyIgQU5EIEFOWSBFWFBSRVNTIE9SIElNUExJRUQgV0FSUkFOVElFUywgSU5DTFVESU5HLCBCVVQgTk9UIExJTUlURUQgVE8sIFRIRSBJTVBMSUVEIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBUkUgRElTQ0xBSU1FRC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIENPUFlSSUdIVCBIT0xERVIgT1IgQ09OVFJJQlVUT1JTIEJFIExJQUJMRSBGT1IgQU5ZIERJUkVDVCwgSU5ESVJFQ1QsIElOQ0lERU5UQUwsIFNQRUNJQUwsIEVYRU1QTEFSWSwgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTIChJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgUFJPQ1VSRU1FTlQgT0YgU1VCU1RJVFVURSBHT09EUyBPUiBTRVJWSUNFUzsgTE9TUyBPRiBVU0UsIERBVEEsIE9SIFBST0ZJVFM7IE9SIEJVU0lORVNTIElOVEVSUlVQVElPTikgSE9XRVZFUiBDQVVTRUQgQU5EIE9OIEFOWSBUSEVPUlkgT0YgTElBQklMSVRZLCBXSEVUSEVSIElOIENPTlRSQUNULCBTVFJJQ1QgTElBQklMSVRZLCBPUiBUT1JUIChJTkNMVURJTkcgTkVHTElHRU5DRSBPUiBPVEhFUldJU0UpIEFSSVNJTkcgSU4gQU5ZIFdBWSBPVVQgT0YgVEhFIFVTRSBPRiBUSElTIFNPRlRXQVJFLCBFVkVOIElGIEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GIFNVQ0ggREFNQUdFLg=="},"url":"https:\/\/opensource.org\/licenses\/BSD-3-Clause"}}],"version":"1.1","bom-ref":"ofp_1.1_fe6c4922-52f8-4ad7-9252-5406ef563844","description":"","copyright":"","properties":[{"name":"component_id","value":"1"}]},{"name":"samba","type":"library","licenses":[{"license":{"id":"GPL-3.0-only","text":{"contentType":"text\/plain","encoding":"base64","content":"R05VIEdFTkVSQUwgUFVCTElDIExJQ0VOU0UKVmVyc2lvbiAzLCAyOSBKdW5lIDIwMDcKCkNvcHlyaWdodCDCqSAyMDA3IEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgSW5jLiA8aHR0cDovL2ZzZi5vcmcvPgoKRXZlcnlvbmUgaXMgcGVybWl0dGVkIHRvIGNvcHkgYW5kIGRpc3RyaWJ1dGUgdmVyYmF0aW0gY29waWVzIG9mIHRoaXMgbGljZW5zZSBkb2N1bWVudCwgYnV0IGNoYW5naW5nIGl0IGlzIG5vdCBhbGxvd2VkLgoKUHJlYW1ibGUKClRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBpcyBhIGZyZWUsIGNvcHlsZWZ0IGxpY2Vuc2UgZm9yIHNvZnR3YXJlIGFuZCBvdGhlciBraW5kcyBvZiB3b3Jrcy4KClRoZSBsaWNlbnNlcyBmb3IgbW9zdCBzb2Z0d2FyZSBhbmQgb3RoZXIgcHJhY3RpY2FsIHdvcmtzIGFyZSBkZXNpZ25lZCB0byB0YWtlIGF3YXkgeW91ciBmcmVlZG9tIHRvIHNoYXJlIGFuZCBjaGFuZ2UgdGhlIHdvcmtzLiBCeSBjb250cmFzdCwgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGlzIGludGVuZGVkIHRvIGd1YXJhbnRlZSB5b3VyIGZyZWVkb20gdG8gc2hhcmUgYW5kIGNoYW5nZSBhbGwgdmVyc2lvbnMgb2YgYSBwcm9ncmFtLS10byBtYWtlIHN1cmUgaXQgcmVtYWlucyBmcmVlIHNvZnR3YXJlIGZvciBhbGwgaXRzIHVzZXJzLiBXZSwgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdXNlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9zdCBvZiBvdXIgc29mdHdhcmU7IGl0IGFwcGxpZXMgYWxzbyB0byBhbnkgb3RoZXIgd29yayByZWxlYXNlZCB0aGlzIHdheSBieSBpdHMgYXV0aG9ycy4gWW91IGNhbiBhcHBseSBpdCB0byB5b3VyIHByb2dyYW1zLCB0b28uCgpXaGVuIHdlIHNwZWFrIG9mIGZyZWUgc29mdHdhcmUsIHdlIGFyZSByZWZlcnJpbmcgdG8gZnJlZWRvbSwgbm90IHByaWNlLiBPdXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZXMgYXJlIGRlc2lnbmVkIHRvIG1ha2Ugc3VyZSB0aGF0IHlvdSBoYXZlIHRoZSBmcmVlZG9tIHRvIGRpc3RyaWJ1dGUgY29waWVzIG9mIGZyZWUgc29mdHdhcmUgKGFuZCBjaGFyZ2UgZm9yIHRoZW0gaWYgeW91IHdpc2gpLCB0aGF0IHlvdSByZWNlaXZlIHNvdXJjZSBjb2RlIG9yIGNhbiBnZXQgaXQgaWYgeW91IHdhbnQgaXQsIHRoYXQgeW91IGNhbiBjaGFuZ2UgdGhlIHNvZnR3YXJlIG9yIHVzZSBwaWVjZXMgb2YgaXQgaW4gbmV3IGZyZWUgcHJvZ3JhbXMsIGFuZCB0aGF0IHlvdSBrbm93IHlvdSBjYW4gZG8gdGhlc2UgdGhpbmdzLgoKVG8gcHJvdGVjdCB5b3VyIHJpZ2h0cywgd2UgbmVlZCB0byBwcmV2ZW50IG90aGVycyBmcm9tIGRlbnlpbmcgeW91IHRoZXNlIHJpZ2h0cyBvciBhc2tpbmcgeW91IHRvIHN1cnJlbmRlciB0aGUgcmlnaHRzLiBUaGVyZWZvcmUsIHlvdSBoYXZlIGNlcnRhaW4gcmVzcG9uc2liaWxpdGllcyBpZiB5b3UgZGlzdHJpYnV0ZSBjb3BpZXMgb2YgdGhlIHNvZnR3YXJlLCBvciBpZiB5b3UgbW9kaWZ5IGl0OiByZXNwb25zaWJpbGl0aWVzIHRvIHJlc3BlY3QgdGhlIGZyZWVkb20gb2Ygb3RoZXJzLgoKRm9yIGV4YW1wbGUsIGlmIHlvdSBkaXN0cmlidXRlIGNvcGllcyBvZiBzdWNoIGEgcHJvZ3JhbSwgd2hldGhlciBncmF0aXMgb3IgZm9yIGEgZmVlLCB5b3UgbXVzdCBwYXNzIG9uIHRvIHRoZSByZWNpcGllbnRzIHRoZSBzYW1lIGZyZWVkb21zIHRoYXQgeW91IHJlY2VpdmVkLiBZb3UgbXVzdCBtYWtlIHN1cmUgdGhhdCB0aGV5LCB0b28sIHJlY2VpdmUgb3IgY2FuIGdldCB0aGUgc291cmNlIGNvZGUuIEFuZCB5b3UgbXVzdCBzaG93IHRoZW0gdGhlc2UgdGVybXMgc28gdGhleSBrbm93IHRoZWlyIHJpZ2h0cy4KCkRldmVsb3BlcnMgdGhhdCB1c2UgdGhlIEdOVSBHUEwgcHJvdGVjdCB5b3VyIHJpZ2h0cyB3aXRoIHR3byBzdGVwczogKDEpIGFzc2VydCBjb3B5cmlnaHQgb24gdGhlIHNvZnR3YXJlLCBhbmQgKDIpIG9mZmVyIHlvdSB0aGlzIExpY2Vuc2UgZ2l2aW5nIHlvdSBsZWdhbCBwZXJtaXNzaW9uIHRvIGNvcHksIGRpc3RyaWJ1dGUgYW5kL29yIG1vZGlmeSBpdC4KCkZvciB0aGUgZGV2ZWxvcGVycycgYW5kIGF1dGhvcnMnIHByb3RlY3Rpb24sIHRoZSBHUEwgY2xlYXJseSBleHBsYWlucyB0aGF0IHRoZXJlIGlzIG5vIHdhcnJhbnR5IGZvciB0aGlzIGZyZWUgc29mdHdhcmUuIEZvciBib3RoIHVzZXJzJyBhbmQgYXV0aG9ycycgc2FrZSwgdGhlIEdQTCByZXF1aXJlcyB0aGF0IG1vZGlmaWVkIHZlcnNpb25zIGJlIG1hcmtlZCBhcyBjaGFuZ2VkLCBzbyB0aGF0IHRoZWlyIHByb2JsZW1zIHdpbGwgbm90IGJlIGF0dHJpYnV0ZWQgZXJyb25lb3VzbHkgdG8gYXV0aG9ycyBvZiBwcmV2aW91cyB2ZXJzaW9ucy4KClNvbWUgZGV2aWNlcyBhcmUgZGVzaWduZWQgdG8gZGVueSB1c2VycyBhY2Nlc3MgdG8gaW5zdGFsbCBvciBydW4gbW9kaWZpZWQgdmVyc2lvbnMgb2YgdGhlIHNvZnR3YXJlIGluc2lkZSB0aGVtLCBhbHRob3VnaCB0aGUgbWFudWZhY3R1cmVyIGNhbiBkbyBzby4gVGhpcyBpcyBmdW5kYW1lbnRhbGx5IGluY29tcGF0aWJsZSB3aXRoIHRoZSBhaW0gb2YgcHJvdGVjdGluZyB1c2VycycgZnJlZWRvbSB0byBjaGFuZ2UgdGhlIHNvZnR3YXJlLiBUaGUgc3lzdGVtYXRpYyBwYXR0ZXJuIG9mIHN1Y2ggYWJ1c2Ugb2NjdXJzIGluIHRoZSBhcmVhIG9mIHByb2R1Y3RzIGZvciBpbmRpdmlkdWFscyB0byB1c2UsIHdoaWNoIGlzIHByZWNpc2VseSB3aGVyZSBpdCBpcyBtb3N0IHVuYWNjZXB0YWJsZS4gVGhlcmVmb3JlLCB3ZSBoYXZlIGRlc2lnbmVkIHRoaXMgdmVyc2lvbiBvZiB0aGUgR1BMIHRvIHByb2hpYml0IHRoZSBwcmFjdGljZSBmb3IgdGhvc2UgcHJvZHVjdHMuIElmIHN1Y2ggcHJvYmxlbXMgYXJpc2Ugc3Vic3RhbnRpYWxseSBpbiBvdGhlciBkb21haW5zLCB3ZSBzdGFuZCByZWFkeSB0byBleHRlbmQgdGhpcyBwcm92aXNpb24gdG8gdGhvc2UgZG9tYWlucyBpbiBmdXR1cmUgdmVyc2lvbnMgb2YgdGhlIEdQTCwgYXMgbmVlZGVkIHRvIHByb3RlY3QgdGhlIGZyZWVkb20gb2YgdXNlcnMuCgpGaW5hbGx5LCBldmVyeSBwcm9ncmFtIGlzIHRocmVhdGVuZWQgY29uc3RhbnRseSBieSBzb2Z0d2FyZSBwYXRlbnRzLiBTdGF0ZXMgc2hvdWxkIG5vdCBhbGxvdyBwYXRlbnRzIHRvIHJlc3RyaWN0IGRldmVsb3BtZW50IGFuZCB1c2Ugb2Ygc29mdHdhcmUgb24gZ2VuZXJhbC1wdXJwb3NlIGNvbXB1dGVycywgYnV0IGluIHRob3NlIHRoYXQgZG8sIHdlIHdpc2ggdG8gYXZvaWQgdGhlIHNwZWNpYWwgZGFuZ2VyIHRoYXQgcGF0ZW50cyBhcHBsaWVkIHRvIGEgZnJlZSBwcm9ncmFtIGNvdWxkIG1ha2UgaXQgZWZmZWN0aXZlbHkgcHJvcHJpZXRhcnkuIFRvIHByZXZlbnQgdGhpcywgdGhlIEdQTCBhc3N1cmVzIHRoYXQgcGF0ZW50cyBjYW5ub3QgYmUgdXNlZCB0byByZW5kZXIgdGhlIHByb2dyYW0gbm9uLWZyZWUuCgpUaGUgcHJlY2lzZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgY29weWluZywgZGlzdHJpYnV0aW9uIGFuZCBtb2RpZmljYXRpb24gZm9sbG93LgoKVEVSTVMgQU5EIENPTkRJVElPTlMKCjAuIERlZmluaXRpb25zLgoK4oCcVGhpcyBMaWNlbnNl4oCdIHJlZmVycyB0byB2ZXJzaW9uIDMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlLgoK4oCcQ29weXJpZ2h04oCdIGFsc28gbWVhbnMgY29weXJpZ2h0LWxpa2UgbGF3cyB0aGF0IGFwcGx5IHRvIG90aGVyIGtpbmRzIG9mIHdvcmtzLCBzdWNoIGFzIHNlbWljb25kdWN0b3IgbWFza3MuCgrigJxUaGUgUHJvZ3JhbeKAnSByZWZlcnMgdG8gYW55IGNvcHlyaWdodGFibGUgd29yayBsaWNlbnNlZCB1bmRlciB0aGlzIExpY2Vuc2UuIEVhY2ggbGljZW5zZWUgaXMgYWRkcmVzc2VkIGFzIOKAnHlvdeKAnS4g4oCcTGljZW5zZWVz4oCdIGFuZCDigJxyZWNpcGllbnRz4oCdIG1heSBiZSBpbmRpdmlkdWFscyBvciBvcmdhbml6YXRpb25zLgoKVG8g4oCcbW9kaWZ54oCdIGEgd29yayBtZWFucyB0byBjb3B5IGZyb20gb3IgYWRhcHQgYWxsIG9yIHBhcnQgb2YgdGhlIHdvcmsgaW4gYSBmYXNoaW9uIHJlcXVpcmluZyBjb3B5cmlnaHQgcGVybWlzc2lvbiwgb3RoZXIgdGhhbiB0aGUgbWFraW5nIG9mIGFuIGV4YWN0IGNvcHkuIFRoZSByZXN1bHRpbmcgd29yayBpcyBjYWxsZWQgYSDigJxtb2RpZmllZCB2ZXJzaW9u4oCdIG9mIHRoZSBlYXJsaWVyIHdvcmsgb3IgYSB3b3JrIOKAnGJhc2VkIG9u4oCdIHRoZSBlYXJsaWVyIHdvcmsuCgpBIOKAnGNvdmVyZWQgd29ya+KAnSBtZWFucyBlaXRoZXIgdGhlIHVubW9kaWZpZWQgUHJvZ3JhbSBvciBhIHdvcmsgYmFzZWQgb24gdGhlIFByb2dyYW0uCgpUbyDigJxwcm9wYWdhdGXigJ0gYSB3b3JrIG1lYW5zIHRvIGRvIGFueXRoaW5nIHdpdGggaXQgdGhhdCwgd2l0aG91dCBwZXJtaXNzaW9uLCB3b3VsZCBtYWtlIHlvdSBkaXJlY3RseSBvciBzZWNvbmRhcmlseSBsaWFibGUgZm9yIGluZnJpbmdlbWVudCB1bmRlciBhcHBsaWNhYmxlIGNvcHlyaWdodCBsYXcsIGV4Y2VwdCBleGVjdXRpbmcgaXQgb24gYSBjb21wdXRlciBvciBtb2RpZnlpbmcgYSBwcml2YXRlIGNvcHkuIFByb3BhZ2F0aW9uIGluY2x1ZGVzIGNvcHlpbmcsIGRpc3RyaWJ1dGlvbiAod2l0aCBvciB3aXRob3V0IG1vZGlmaWNhdGlvbiksIG1ha2luZyBhdmFpbGFibGUgdG8gdGhlIHB1YmxpYywgYW5kIGluIHNvbWUgY291bnRyaWVzIG90aGVyIGFjdGl2aXRpZXMgYXMgd2VsbC4KClRvIOKAnGNvbnZleeKAnSBhIHdvcmsgbWVhbnMgYW55IGtpbmQgb2YgcHJvcGFnYXRpb24gdGhhdCBlbmFibGVzIG90aGVyIHBhcnRpZXMgdG8gbWFrZSBvciByZWNlaXZlIGNvcGllcy4gTWVyZSBpbnRlcmFjdGlvbiB3aXRoIGEgdXNlciB0aHJvdWdoIGEgY29tcHV0ZXIgbmV0d29yaywgd2l0aCBubyB0cmFuc2ZlciBvZiBhIGNvcHksIGlzIG5vdCBjb252ZXlpbmcuCgpBbiBpbnRlcmFjdGl2ZSB1c2VyIGludGVyZmFjZSBkaXNwbGF5cyDigJxBcHByb3ByaWF0ZSBMZWdhbCBOb3RpY2Vz4oCdIHRvIHRoZSBleHRlbnQgdGhhdCBpdCBpbmNsdWRlcyBhIGNvbnZlbmllbnQgYW5kIHByb21pbmVudGx5IHZpc2libGUgZmVhdHVyZSB0aGF0ICgxKSBkaXNwbGF5cyBhbiBhcHByb3ByaWF0ZSBjb3B5cmlnaHQgbm90aWNlLCBhbmQgKDIpIHRlbGxzIHRoZSB1c2VyIHRoYXQgdGhlcmUgaXMgbm8gd2FycmFudHkgZm9yIHRoZSB3b3JrIChleGNlcHQgdG8gdGhlIGV4dGVudCB0aGF0IHdhcnJhbnRpZXMgYXJlIHByb3ZpZGVkKSwgdGhhdCBsaWNlbnNlZXMgbWF5IGNvbnZleSB0aGUgd29yayB1bmRlciB0aGlzIExpY2Vuc2UsIGFuZCBob3cgdG8gdmlldyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlLiBJZiB0aGUgaW50ZXJmYWNlIHByZXNlbnRzIGEgbGlzdCBvZiB1c2VyIGNvbW1hbmRzIG9yIG9wdGlvbnMsIHN1Y2ggYXMgYSBtZW51LCBhIHByb21pbmVudCBpdGVtIGluIHRoZSBsaXN0IG1lZXRzIHRoaXMgY3JpdGVyaW9uLgoKMS4gU291cmNlIENvZGUuClRoZSDigJxzb3VyY2UgY29kZeKAnSBmb3IgYSB3b3JrIG1lYW5zIHRoZSBwcmVmZXJyZWQgZm9ybSBvZiB0aGUgd29yayBmb3IgbWFraW5nIG1vZGlmaWNhdGlvbnMgdG8gaXQuIOKAnE9iamVjdCBjb2Rl4oCdIG1lYW5zIGFueSBub24tc291cmNlIGZvcm0gb2YgYSB3b3JrLgoKQSDigJxTdGFuZGFyZCBJbnRlcmZhY2XigJ0gbWVhbnMgYW4gaW50ZXJmYWNlIHRoYXQgZWl0aGVyIGlzIGFuIG9mZmljaWFsIHN0YW5kYXJkIGRlZmluZWQgYnkgYSByZWNvZ25pemVkIHN0YW5kYXJkcyBib2R5LCBvciwgaW4gdGhlIGNhc2Ugb2YgaW50ZXJmYWNlcyBzcGVjaWZpZWQgZm9yIGEgcGFydGljdWxhciBwcm9ncmFtbWluZyBsYW5ndWFnZSwgb25lIHRoYXQgaXMgd2lkZWx5IHVzZWQgYW1vbmcgZGV2ZWxvcGVycyB3b3JraW5nIGluIHRoYXQgbGFuZ3VhZ2UuCgpUaGUg4oCcU3lzdGVtIExpYnJhcmllc+KAnSBvZiBhbiBleGVjdXRhYmxlIHdvcmsgaW5jbHVkZSBhbnl0aGluZywgb3RoZXIgdGhhbiB0aGUgd29yayBhcyBhIHdob2xlLCB0aGF0IChhKSBpcyBpbmNsdWRlZCBpbiB0aGUgbm9ybWFsIGZvcm0gb2YgcGFja2FnaW5nIGEgTWFqb3IgQ29tcG9uZW50LCBidXQgd2hpY2ggaXMgbm90IHBhcnQgb2YgdGhhdCBNYWpvciBDb21wb25lbnQsIGFuZCAoYikgc2VydmVzIG9ubHkgdG8gZW5hYmxlIHVzZSBvZiB0aGUgd29yayB3aXRoIHRoYXQgTWFqb3IgQ29tcG9uZW50LCBvciB0byBpbXBsZW1lbnQgYSBTdGFuZGFyZCBJbnRlcmZhY2UgZm9yIHdoaWNoIGFuIGltcGxlbWVudGF0aW9uIGlzIGF2YWlsYWJsZSB0byB0aGUgcHVibGljIGluIHNvdXJjZSBjb2RlIGZvcm0uIEEg4oCcTWFqb3IgQ29tcG9uZW504oCdLCBpbiB0aGlzIGNvbnRleHQsIG1lYW5zIGEgbWFqb3IgZXNzZW50aWFsIGNvbXBvbmVudCAoa2VybmVsLCB3aW5kb3cgc3lzdGVtLCBhbmQgc28gb24pIG9mIHRoZSBzcGVjaWZpYyBvcGVyYXRpbmcgc3lzdGVtIChpZiBhbnkpIG9uIHdoaWNoIHRoZSBleGVjdXRhYmxlIHdvcmsgcnVucywgb3IgYSBjb21waWxlciB1c2VkIHRvIHByb2R1Y2UgdGhlIHdvcmssIG9yIGFuIG9iamVjdCBjb2RlIGludGVycHJldGVyIHVzZWQgdG8gcnVuIGl0LgoKVGhlIOKAnENvcnJlc3BvbmRpbmcgU291cmNl4oCdIGZvciBhIHdvcmsgaW4gb2JqZWN0IGNvZGUgZm9ybSBtZWFucyBhbGwgdGhlIHNvdXJjZSBjb2RlIG5lZWRlZCB0byBnZW5lcmF0ZSwgaW5zdGFsbCwgYW5kIChmb3IgYW4gZXhlY3V0YWJsZSB3b3JrKSBydW4gdGhlIG9iamVjdCBjb2RlIGFuZCB0byBtb2RpZnkgdGhlIHdvcmssIGluY2x1ZGluZyBzY3JpcHRzIHRvIGNvbnRyb2wgdGhvc2UgYWN0aXZpdGllcy4gSG93ZXZlciwgaXQgZG9lcyBub3QgaW5jbHVkZSB0aGUgd29yaydzIFN5c3RlbSBMaWJyYXJpZXMsIG9yIGdlbmVyYWwtcHVycG9zZSB0b29scyBvciBnZW5lcmFsbHkgYXZhaWxhYmxlIGZyZWUgcHJvZ3JhbXMgd2hpY2ggYXJlIHVzZWQgdW5tb2RpZmllZCBpbiBwZXJmb3JtaW5nIHRob3NlIGFjdGl2aXRpZXMgYnV0IHdoaWNoIGFyZSBub3QgcGFydCBvZiB0aGUgd29yay4gRm9yIGV4YW1wbGUsIENvcnJlc3BvbmRpbmcgU291cmNlIGluY2x1ZGVzIGludGVyZmFjZSBkZWZpbml0aW9uIGZpbGVzIGFzc29jaWF0ZWQgd2l0aCBzb3VyY2UgZmlsZXMgZm9yIHRoZSB3b3JrLCBhbmQgdGhlIHNvdXJjZSBjb2RlIGZvciBzaGFyZWQgbGlicmFyaWVzIGFuZCBkeW5hbWljYWxseSBsaW5rZWQgc3VicHJvZ3JhbXMgdGhhdCB0aGUgd29yayBpcyBzcGVjaWZpY2FsbHkgZGVzaWduZWQgdG8gcmVxdWlyZSwgc3VjaCBhcyBieSBpbnRpbWF0ZSBkYXRhIGNvbW11bmljYXRpb24gb3IgY29udHJvbCBmbG93IGJldHdlZW4gdGhvc2Ugc3VicHJvZ3JhbXMgYW5kIG90aGVyIHBhcnRzIG9mIHRoZSB3b3JrLgoKVGhlIENvcnJlc3BvbmRpbmcgU291cmNlIG5lZWQgbm90IGluY2x1ZGUgYW55dGhpbmcgdGhhdCB1c2VycyBjYW4gcmVnZW5lcmF0ZSBhdXRvbWF0aWNhbGx5IGZyb20gb3RoZXIgcGFydHMgb2YgdGhlIENvcnJlc3BvbmRpbmcgU291cmNlLgoKVGhlIENvcnJlc3BvbmRpbmcgU291cmNlIGZvciBhIHdvcmsgaW4gc291cmNlIGNvZGUgZm9ybSBpcyB0aGF0IHNhbWUgd29yay4KCjIuIEJhc2ljIFBlcm1pc3Npb25zLgpBbGwgcmlnaHRzIGdyYW50ZWQgdW5kZXIgdGhpcyBMaWNlbnNlIGFyZSBncmFudGVkIGZvciB0aGUgdGVybSBvZiBjb3B5cmlnaHQgb24gdGhlIFByb2dyYW0sIGFuZCBhcmUgaXJyZXZvY2FibGUgcHJvdmlkZWQgdGhlIHN0YXRlZCBjb25kaXRpb25zIGFyZSBtZXQuIFRoaXMgTGljZW5zZSBleHBsaWNpdGx5IGFmZmlybXMgeW91ciB1bmxpbWl0ZWQgcGVybWlzc2lvbiB0byBydW4gdGhlIHVubW9kaWZpZWQgUHJvZ3JhbS4gVGhlIG91dHB1dCBmcm9tIHJ1bm5pbmcgYSBjb3ZlcmVkIHdvcmsgaXMgY292ZXJlZCBieSB0aGlzIExpY2Vuc2Ugb25seSBpZiB0aGUgb3V0cHV0LCBnaXZlbiBpdHMgY29udGVudCwgY29uc3RpdHV0ZXMgYSBjb3ZlcmVkIHdvcmsuIFRoaXMgTGljZW5zZSBhY2tub3dsZWRnZXMgeW91ciByaWdodHMgb2YgZmFpciB1c2Ugb3Igb3RoZXIgZXF1aXZhbGVudCwgYXMgcHJvdmlkZWQgYnkgY29weXJpZ2h0IGxhdy4KCllvdSBtYXkgbWFrZSwgcnVuIGFuZCBwcm9wYWdhdGUgY292ZXJlZCB3b3JrcyB0aGF0IHlvdSBkbyBub3QgY29udmV5LCB3aXRob3V0IGNvbmRpdGlvbnMgc28gbG9uZyBhcyB5b3VyIGxpY2Vuc2Ugb3RoZXJ3aXNlIHJlbWFpbnMgaW4gZm9yY2UuIFlvdSBtYXkgY29udmV5IGNvdmVyZWQgd29ya3MgdG8gb3RoZXJzIGZvciB0aGUgc29sZSBwdXJwb3NlIG9mIGhhdmluZyB0aGVtIG1ha2UgbW9kaWZpY2F0aW9ucyBleGNsdXNpdmVseSBmb3IgeW91LCBvciBwcm92aWRlIHlvdSB3aXRoIGZhY2lsaXRpZXMgZm9yIHJ1bm5pbmcgdGhvc2Ugd29ya3MsIHByb3ZpZGVkIHRoYXQgeW91IGNvbXBseSB3aXRoIHRoZSB0ZXJtcyBvZiB0aGlzIExpY2Vuc2UgaW4gY29udmV5aW5nIGFsbCBtYXRlcmlhbCBmb3Igd2hpY2ggeW91IGRvIG5vdCBjb250cm9sIGNvcHlyaWdodC4gVGhvc2UgdGh1cyBtYWtpbmcgb3IgcnVubmluZyB0aGUgY292ZXJlZCB3b3JrcyBmb3IgeW91IG11c3QgZG8gc28gZXhjbHVzaXZlbHkgb24geW91ciBiZWhhbGYsIHVuZGVyIHlvdXIgZGlyZWN0aW9uIGFuZCBjb250cm9sLCBvbiB0ZXJtcyB0aGF0IHByb2hpYml0IHRoZW0gZnJvbSBtYWtpbmcgYW55IGNvcGllcyBvZiB5b3VyIGNvcHlyaWdodGVkIG1hdGVyaWFsIG91dHNpZGUgdGhlaXIgcmVsYXRpb25zaGlwIHdpdGggeW91LgoKQ29udmV5aW5nIHVuZGVyIGFueSBvdGhlciBjaXJjdW1zdGFuY2VzIGlzIHBlcm1pdHRlZCBzb2xlbHkgdW5kZXIgdGhlIGNvbmRpdGlvbnMgc3RhdGVkIGJlbG93LiBTdWJsaWNlbnNpbmcgaXMgbm90IGFsbG93ZWQ7IHNlY3Rpb24gMTAgbWFrZXMgaXQgdW5uZWNlc3NhcnkuCgozLiBQcm90ZWN0aW5nIFVzZXJzJyBMZWdhbCBSaWdodHMgRnJvbSBBbnRpLUNpcmN1bXZlbnRpb24gTGF3LgpObyBjb3ZlcmVkIHdvcmsgc2hhbGwgYmUgZGVlbWVkIHBhcnQgb2YgYW4gZWZmZWN0aXZlIHRlY2hub2xvZ2ljYWwgbWVhc3VyZSB1bmRlciBhbnkgYXBwbGljYWJsZSBsYXcgZnVsZmlsbGluZyBvYmxpZ2F0aW9ucyB1bmRlciBhcnRpY2xlIDExIG9mIHRoZSBXSVBPIGNvcHlyaWdodCB0cmVhdHkgYWRvcHRlZCBvbiAyMCBEZWNlbWJlciAxOTk2LCBvciBzaW1pbGFyIGxhd3MgcHJvaGliaXRpbmcgb3IgcmVzdHJpY3RpbmcgY2lyY3VtdmVudGlvbiBvZiBzdWNoIG1lYXN1cmVzLgoKV2hlbiB5b3UgY29udmV5IGEgY292ZXJlZCB3b3JrLCB5b3Ugd2FpdmUgYW55IGxlZ2FsIHBvd2VyIHRvIGZvcmJpZCBjaXJjdW12ZW50aW9uIG9mIHRlY2hub2xvZ2ljYWwgbWVhc3VyZXMgdG8gdGhlIGV4dGVudCBzdWNoIGNpcmN1bXZlbnRpb24gaXMgZWZmZWN0ZWQgYnkgZXhlcmNpc2luZyByaWdodHMgdW5kZXIgdGhpcyBMaWNlbnNlIHdpdGggcmVzcGVjdCB0byB0aGUgY292ZXJlZCB3b3JrLCBhbmQgeW91IGRpc2NsYWltIGFueSBpbnRlbnRpb24gdG8gbGltaXQgb3BlcmF0aW9uIG9yIG1vZGlmaWNhdGlvbiBvZiB0aGUgd29yayBhcyBhIG1lYW5zIG9mIGVuZm9yY2luZywgYWdhaW5zdCB0aGUgd29yaydzIHVzZXJzLCB5b3VyIG9yIHRoaXJkIHBhcnRpZXMnIGxlZ2FsIHJpZ2h0cyB0byBmb3JiaWQgY2lyY3VtdmVudGlvbiBvZiB0ZWNobm9sb2dpY2FsIG1lYXN1cmVzLgoKNC4gQ29udmV5aW5nIFZlcmJhdGltIENvcGllcy4KWW91IG1heSBjb252ZXkgdmVyYmF0aW0gY29waWVzIG9mIHRoZSBQcm9ncmFtJ3Mgc291cmNlIGNvZGUgYXMgeW91IHJlY2VpdmUgaXQsIGluIGFueSBtZWRpdW0sIHByb3ZpZGVkIHRoYXQgeW91IGNvbnNwaWN1b3VzbHkgYW5kIGFwcHJvcHJpYXRlbHkgcHVibGlzaCBvbiBlYWNoIGNvcHkgYW4gYXBwcm9wcmlhdGUgY29weXJpZ2h0IG5vdGljZTsga2VlcCBpbnRhY3QgYWxsIG5vdGljZXMgc3RhdGluZyB0aGF0IHRoaXMgTGljZW5zZSBhbmQgYW55IG5vbi1wZXJtaXNzaXZlIHRlcm1zIGFkZGVkIGluIGFjY29yZCB3aXRoIHNlY3Rpb24gNyBhcHBseSB0byB0aGUgY29kZTsga2VlcCBpbnRhY3QgYWxsIG5vdGljZXMgb2YgdGhlIGFic2VuY2Ugb2YgYW55IHdhcnJhbnR5OyBhbmQgZ2l2ZSBhbGwgcmVjaXBpZW50cyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlIGFsb25nIHdpdGggdGhlIFByb2dyYW0uCgpZb3UgbWF5IGNoYXJnZSBhbnkgcHJpY2Ugb3Igbm8gcHJpY2UgZm9yIGVhY2ggY29weSB0aGF0IHlvdSBjb252ZXksIGFuZCB5b3UgbWF5IG9mZmVyIHN1cHBvcnQgb3Igd2FycmFudHkgcHJvdGVjdGlvbiBmb3IgYSBmZWUuCgo1LiBDb252ZXlpbmcgTW9kaWZpZWQgU291cmNlIFZlcnNpb25zLgpZb3UgbWF5IGNvbnZleSBhIHdvcmsgYmFzZWQgb24gdGhlIFByb2dyYW0sIG9yIHRoZSBtb2RpZmljYXRpb25zIHRvIHByb2R1Y2UgaXQgZnJvbSB0aGUgUHJvZ3JhbSwgaW4gdGhlIGZvcm0gb2Ygc291cmNlIGNvZGUgdW5kZXIgdGhlIHRlcm1zIG9mIHNlY3Rpb24gNCwgcHJvdmlkZWQgdGhhdCB5b3UgYWxzbyBtZWV0IGFsbCBvZiB0aGVzZSBjb25kaXRpb25zOgoKICAgICBhKSBUaGUgd29yayBtdXN0IGNhcnJ5IHByb21pbmVudCBub3RpY2VzIHN0YXRpbmcgdGhhdCB5b3UgbW9kaWZpZWQgaXQsIGFuZCBnaXZpbmcgYSByZWxldmFudCBkYXRlLgoKICAgICBiKSBUaGUgd29yayBtdXN0IGNhcnJ5IHByb21pbmVudCBub3RpY2VzIHN0YXRpbmcgdGhhdCBpdCBpcyByZWxlYXNlZCB1bmRlciB0aGlzIExpY2Vuc2UgYW5kIGFueSBjb25kaXRpb25zIGFkZGVkIHVuZGVyIHNlY3Rpb24gNy4gVGhpcyByZXF1aXJlbWVudCBtb2RpZmllcyB0aGUgcmVxdWlyZW1lbnQgaW4gc2VjdGlvbiA0IHRvIOKAnGtlZXAgaW50YWN0IGFsbCBub3RpY2Vz4oCdLgoKICAgICBjKSBZb3UgbXVzdCBsaWNlbnNlIHRoZSBlbnRpcmUgd29yaywgYXMgYSB3aG9sZSwgdW5kZXIgdGhpcyBMaWNlbnNlIHRvIGFueW9uZSB3aG8gY29tZXMgaW50byBwb3NzZXNzaW9uIG9mIGEgY29weS4gVGhpcyBMaWNlbnNlIHdpbGwgdGhlcmVmb3JlIGFwcGx5LCBhbG9uZyB3aXRoIGFueSBhcHBsaWNhYmxlIHNlY3Rpb24gNyBhZGRpdGlvbmFsIHRlcm1zLCB0byB0aGUgd2hvbGUgb2YgdGhlIHdvcmssIGFuZCBhbGwgaXRzIHBhcnRzLCByZWdhcmRsZXNzIG9mIGhvdyB0aGV5IGFyZSBwYWNrYWdlZC4gVGhpcyBMaWNlbnNlIGdpdmVzIG5vIHBlcm1pc3Npb24gdG8gbGljZW5zZSB0aGUgd29yayBpbiBhbnkgb3RoZXIgd2F5LCBidXQgaXQgZG9lcyBub3QgaW52YWxpZGF0ZSBzdWNoIHBlcm1pc3Npb24gaWYgeW91IGhhdmUgc2VwYXJhdGVseSByZWNlaXZlZCBpdC4KCiAgICAgZCkgSWYgdGhlIHdvcmsgaGFzIGludGVyYWN0aXZlIHVzZXIgaW50ZXJmYWNlcywgZWFjaCBtdXN0IGRpc3BsYXkgQXBwcm9wcmlhdGUgTGVnYWwgTm90aWNlczsgaG93ZXZlciwgaWYgdGhlIFByb2dyYW0gaGFzIGludGVyYWN0aXZlIGludGVyZmFjZXMgdGhhdCBkbyBub3QgZGlzcGxheSBBcHByb3ByaWF0ZSBMZWdhbCBOb3RpY2VzLCB5b3VyIHdvcmsgbmVlZCBub3QgbWFrZSB0aGVtIGRvIHNvLgoKQSBjb21waWxhdGlvbiBvZiBhIGNvdmVyZWQgd29yayB3aXRoIG90aGVyIHNlcGFyYXRlIGFuZCBpbmRlcGVuZGVudCB3b3Jrcywgd2hpY2ggYXJlIG5vdCBieSB0aGVpciBuYXR1cmUgZXh0ZW5zaW9ucyBvZiB0aGUgY292ZXJlZCB3b3JrLCBhbmQgd2hpY2ggYXJlIG5vdCBjb21iaW5lZCB3aXRoIGl0IHN1Y2ggYXMgdG8gZm9ybSBhIGxhcmdlciBwcm9ncmFtLCBpbiBvciBvbiBhIHZvbHVtZSBvZiBhIHN0b3JhZ2Ugb3IgZGlzdHJpYnV0aW9uIG1lZGl1bSwgaXMgY2FsbGVkIGFuIOKAnGFnZ3JlZ2F0ZeKAnSBpZiB0aGUgY29tcGlsYXRpb24gYW5kIGl0cyByZXN1bHRpbmcgY29weXJpZ2h0IGFyZSBub3QgdXNlZCB0byBsaW1pdCB0aGUgYWNjZXNzIG9yIGxlZ2FsIHJpZ2h0cyBvZiB0aGUgY29tcGlsYXRpb24ncyB1c2VycyBiZXlvbmQgd2hhdCB0aGUgaW5kaXZpZHVhbCB3b3JrcyBwZXJtaXQuIEluY2x1c2lvbiBvZiBhIGNvdmVyZWQgd29yayBpbiBhbiBhZ2dyZWdhdGUgZG9lcyBub3QgY2F1c2UgdGhpcyBMaWNlbnNlIHRvIGFwcGx5IHRvIHRoZSBvdGhlciBwYXJ0cyBvZiB0aGUgYWdncmVnYXRlLgoKNi4gQ29udmV5aW5nIE5vbi1Tb3VyY2UgRm9ybXMuCllvdSBtYXkgY29udmV5IGEgY292ZXJlZCB3b3JrIGluIG9iamVjdCBjb2RlIGZvcm0gdW5kZXIgdGhlIHRlcm1zIG9mIHNlY3Rpb25zIDQgYW5kIDUsIHByb3ZpZGVkIHRoYXQgeW91IGFsc28gY29udmV5IHRoZSBtYWNoaW5lLXJlYWRhYmxlIENvcnJlc3BvbmRpbmcgU291cmNlIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGlzIExpY2Vuc2UsIGluIG9uZSBvZiB0aGVzZSB3YXlzOgoKICAgICBhKSBDb252ZXkgdGhlIG9iamVjdCBjb2RlIGluLCBvciBlbWJvZGllZCBpbiwgYSBwaHlzaWNhbCBwcm9kdWN0IChpbmNsdWRpbmcgYSBwaHlzaWNhbCBkaXN0cmlidXRpb24gbWVkaXVtKSwgYWNjb21wYW5pZWQgYnkgdGhlIENvcnJlc3BvbmRpbmcgU291cmNlIGZpeGVkIG9uIGEgZHVyYWJsZSBwaHlzaWNhbCBtZWRpdW0gY3VzdG9tYXJpbHkgdXNlZCBmb3Igc29mdHdhcmUgaW50ZXJjaGFuZ2UuCgogICAgIGIpIENvbnZleSB0aGUgb2JqZWN0IGNvZGUgaW4sIG9yIGVtYm9kaWVkIGluLCBhIHBoeXNpY2FsIHByb2R1Y3QgKGluY2x1ZGluZyBhIHBoeXNpY2FsIGRpc3RyaWJ1dGlvbiBtZWRpdW0pLCBhY2NvbXBhbmllZCBieSBhIHdyaXR0ZW4gb2ZmZXIsIHZhbGlkIGZvciBhdCBsZWFzdCB0aHJlZSB5ZWFycyBhbmQgdmFsaWQgZm9yIGFzIGxvbmcgYXMgeW91IG9mZmVyIHNwYXJlIHBhcnRzIG9yIGN1c3RvbWVyIHN1cHBvcnQgZm9yIHRoYXQgcHJvZHVjdCBtb2RlbCwgdG8gZ2l2ZSBhbnlvbmUgd2hvIHBvc3Nlc3NlcyB0aGUgb2JqZWN0IGNvZGUgZWl0aGVyICgxKSBhIGNvcHkgb2YgdGhlIENvcnJlc3BvbmRpbmcgU291cmNlIGZvciBhbGwgdGhlIHNvZnR3YXJlIGluIHRoZSBwcm9kdWN0IHRoYXQgaXMgY292ZXJlZCBieSB0aGlzIExpY2Vuc2UsIG9uIGEgZHVyYWJsZSBwaHlzaWNhbCBtZWRpdW0gY3VzdG9tYXJpbHkgdXNlZCBmb3Igc29mdHdhcmUgaW50ZXJjaGFuZ2UsIGZvciBhIHByaWNlIG5vIG1vcmUgdGhhbiB5b3VyIHJlYXNvbmFibGUgY29zdCBvZiBwaHlzaWNhbGx5IHBlcmZvcm1pbmcgdGhpcyBjb252ZXlpbmcgb2Ygc291cmNlLCBvciAoMikgYWNjZXNzIHRvIGNvcHkgdGhlIENvcnJlc3BvbmRpbmcgU291cmNlIGZyb20gYSBuZXR3b3JrIHNlcnZlciBhdCBubyBjaGFyZ2UuCgogICAgIGMpIENvbnZleSBpbmRpdmlkdWFsIGNvcGllcyBvZiB0aGUgb2JqZWN0IGNvZGUgd2l0aCBhIGNvcHkgb2YgdGhlIHdyaXR0ZW4gb2ZmZXIgdG8gcHJvdmlkZSB0aGUgQ29ycmVzcG9uZGluZyBTb3VyY2UuIFRoaXMgYWx0ZXJuYXRpdmUgaXMgYWxsb3dlZCBvbmx5IG9jY2FzaW9uYWxseSBhbmQgbm9uY29tbWVyY2lhbGx5LCBhbmQgb25seSBpZiB5b3UgcmVjZWl2ZWQgdGhlIG9iamVjdCBjb2RlIHdpdGggc3VjaCBhbiBvZmZlciwgaW4gYWNjb3JkIHdpdGggc3Vic2VjdGlvbiA2Yi4KCiAgICAgZCkgQ29udmV5IHRoZSBvYmplY3QgY29kZSBieSBvZmZlcmluZyBhY2Nlc3MgZnJvbSBhIGRlc2lnbmF0ZWQgcGxhY2UgKGdyYXRpcyBvciBmb3IgYSBjaGFyZ2UpLCBhbmQgb2ZmZXIgZXF1aXZhbGVudCBhY2Nlc3MgdG8gdGhlIENvcnJlc3BvbmRpbmcgU291cmNlIGluIHRoZSBzYW1lIHdheSB0aHJvdWdoIHRoZSBzYW1lIHBsYWNlIGF0IG5vIGZ1cnRoZXIgY2hhcmdlLiBZb3UgbmVlZCBub3QgcmVxdWlyZSByZWNpcGllbnRzIHRvIGNvcHkgdGhlIENvcnJlc3BvbmRpbmcgU291cmNlIGFsb25nIHdpdGggdGhlIG9iamVjdCBjb2RlLiBJZiB0aGUgcGxhY2UgdG8gY29weSB0aGUgb2JqZWN0IGNvZGUgaXMgYSBuZXR3b3JrIHNlcnZlciwgdGhlIENvcnJlc3BvbmRpbmcgU291cmNlIG1heSBiZSBvbiBhIGRpZmZlcmVudCBzZXJ2ZXIgKG9wZXJhdGVkIGJ5IHlvdSBvciBhIHRoaXJkIHBhcnR5KSB0aGF0IHN1cHBvcnRzIGVxdWl2YWxlbnQgY29weWluZyBmYWNpbGl0aWVzLCBwcm92aWRlZCB5b3UgbWFpbnRhaW4gY2xlYXIgZGlyZWN0aW9ucyBuZXh0IHRvIHRoZSBvYmplY3QgY29kZSBzYXlpbmcgd2hlcmUgdG8gZmluZCB0aGUgQ29ycmVzcG9uZGluZyBTb3VyY2UuIFJlZ2FyZGxlc3Mgb2Ygd2hhdCBzZXJ2ZXIgaG9zdHMgdGhlIENvcnJlc3BvbmRpbmcgU291cmNlLCB5b3UgcmVtYWluIG9ibGlnYXRlZCB0byBlbnN1cmUgdGhhdCBpdCBpcyBhdmFpbGFibGUgZm9yIGFzIGxvbmcgYXMgbmVlZGVkIHRvIHNhdGlzZnkgdGhlc2UgcmVxdWlyZW1lbnRzLgoKICAgICBlKSBDb252ZXkgdGhlIG9iamVjdCBjb2RlIHVzaW5nIHBlZXItdG8tcGVlciB0cmFuc21pc3Npb24sIHByb3ZpZGVkIHlvdSBpbmZvcm0gb3RoZXIgcGVlcnMgd2hlcmUgdGhlIG9iamVjdCBjb2RlIGFuZCBDb3JyZXNwb25kaW5nIFNvdXJjZSBvZiB0aGUgd29yayBhcmUgYmVpbmcgb2ZmZXJlZCB0byB0aGUgZ2VuZXJhbCBwdWJsaWMgYXQgbm8gY2hhcmdlIHVuZGVyIHN1YnNlY3Rpb24gNmQuCgpBIHNlcGFyYWJsZSBwb3J0aW9uIG9mIHRoZSBvYmplY3QgY29kZSwgd2hvc2Ugc291cmNlIGNvZGUgaXMgZXhjbHVkZWQgZnJvbSB0aGUgQ29ycmVzcG9uZGluZyBTb3VyY2UgYXMgYSBTeXN0ZW0gTGlicmFyeSwgbmVlZCBub3QgYmUgaW5jbHVkZWQgaW4gY29udmV5aW5nIHRoZSBvYmplY3QgY29kZSB3b3JrLgoKQSDigJxVc2VyIFByb2R1Y3TigJ0gaXMgZWl0aGVyICgxKSBhIOKAnGNvbnN1bWVyIHByb2R1Y3TigJ0sIHdoaWNoIG1lYW5zIGFueSB0YW5naWJsZSBwZXJzb25hbCBwcm9wZXJ0eSB3aGljaCBpcyBub3JtYWxseSB1c2VkIGZvciBwZXJzb25hbCwgZmFtaWx5LCBvciBob3VzZWhvbGQgcHVycG9zZXMsIG9yICgyKSBhbnl0aGluZyBkZXNpZ25lZCBvciBzb2xkIGZvciBpbmNvcnBvcmF0aW9uIGludG8gYSBkd2VsbGluZy4gSW4gZGV0ZXJtaW5pbmcgd2hldGhlciBhIHByb2R1Y3QgaXMgYSBjb25zdW1lciBwcm9kdWN0LCBkb3VidGZ1bCBjYXNlcyBzaGFsbCBiZSByZXNvbHZlZCBpbiBmYXZvciBvZiBjb3ZlcmFnZS4gRm9yIGEgcGFydGljdWxhciBwcm9kdWN0IHJlY2VpdmVkIGJ5IGEgcGFydGljdWxhciB1c2VyLCDigJxub3JtYWxseSB1c2Vk4oCdIHJlZmVycyB0byBhIHR5cGljYWwgb3IgY29tbW9uIHVzZSBvZiB0aGF0IGNsYXNzIG9mIHByb2R1Y3QsIHJlZ2FyZGxlc3Mgb2YgdGhlIHN0YXR1cyBvZiB0aGUgcGFydGljdWxhciB1c2VyIG9yIG9mIHRoZSB3YXkgaW4gd2hpY2ggdGhlIHBhcnRpY3VsYXIgdXNlciBhY3R1YWxseSB1c2VzLCBvciBleHBlY3RzIG9yIGlzIGV4cGVjdGVkIHRvIHVzZSwgdGhlIHByb2R1Y3QuIEEgcHJvZHVjdCBpcyBhIGNvbnN1bWVyIHByb2R1Y3QgcmVnYXJkbGVzcyBvZiB3aGV0aGVyIHRoZSBwcm9kdWN0IGhhcyBzdWJzdGFudGlhbCBjb21tZXJjaWFsLCBpbmR1c3RyaWFsIG9yIG5vbi1jb25zdW1lciB1c2VzLCB1bmxlc3Mgc3VjaCB1c2VzIHJlcHJlc2VudCB0aGUgb25seSBzaWduaWZpY2FudCBtb2RlIG9mIHVzZSBvZiB0aGUgcHJvZHVjdC4KCuKAnEluc3RhbGxhdGlvbiBJbmZvcm1hdGlvbuKAnSBmb3IgYSBVc2VyIFByb2R1Y3QgbWVhbnMgYW55IG1ldGhvZHMsIHByb2NlZHVyZXMsIGF1dGhvcml6YXRpb24ga2V5cywgb3Igb3RoZXIgaW5mb3JtYXRpb24gcmVxdWlyZWQgdG8gaW5zdGFsbCBhbmQgZXhlY3V0ZSBtb2RpZmllZCB2ZXJzaW9ucyBvZiBhIGNvdmVyZWQgd29yayBpbiB0aGF0IFVzZXIgUHJvZHVjdCBmcm9tIGEgbW9kaWZpZWQgdmVyc2lvbiBvZiBpdHMgQ29ycmVzcG9uZGluZyBTb3VyY2UuIFRoZSBpbmZvcm1hdGlvbiBtdXN0IHN1ZmZpY2UgdG8gZW5zdXJlIHRoYXQgdGhlIGNvbnRpbnVlZCBmdW5jdGlvbmluZyBvZiB0aGUgbW9kaWZpZWQgb2JqZWN0IGNvZGUgaXMgaW4gbm8gY2FzZSBwcmV2ZW50ZWQgb3IgaW50ZXJmZXJlZCB3aXRoIHNvbGVseSBiZWNhdXNlIG1vZGlmaWNhdGlvbiBoYXMgYmVlbiBtYWRlLgoKSWYgeW91IGNvbnZleSBhbiBvYmplY3QgY29kZSB3b3JrIHVuZGVyIHRoaXMgc2VjdGlvbiBpbiwgb3Igd2l0aCwgb3Igc3BlY2lmaWNhbGx5IGZvciB1c2UgaW4sIGEgVXNlciBQcm9kdWN0LCBhbmQgdGhlIGNvbnZleWluZyBvY2N1cnMgYXMgcGFydCBvZiBhIHRyYW5zYWN0aW9uIGluIHdoaWNoIHRoZSByaWdodCBvZiBwb3NzZXNzaW9uIGFuZCB1c2Ugb2YgdGhlIFVzZXIgUHJvZHVjdCBpcyB0cmFuc2ZlcnJlZCB0byB0aGUgcmVjaXBpZW50IGluIHBlcnBldHVpdHkgb3IgZm9yIGEgZml4ZWQgdGVybSAocmVnYXJkbGVzcyBvZiBob3cgdGhlIHRyYW5zYWN0aW9uIGlzIGNoYXJhY3Rlcml6ZWQpLCB0aGUgQ29ycmVzcG9uZGluZyBTb3VyY2UgY29udmV5ZWQgdW5kZXIgdGhpcyBzZWN0aW9uIG11c3QgYmUgYWNjb21wYW5pZWQgYnkgdGhlIEluc3RhbGxhdGlvbiBJbmZvcm1hdGlvbi4gQnV0IHRoaXMgcmVxdWlyZW1lbnQgZG9lcyBub3QgYXBwbHkgaWYgbmVpdGhlciB5b3Ugbm9yIGFueSB0aGlyZCBwYXJ0eSByZXRhaW5zIHRoZSBhYmlsaXR5IHRvIGluc3RhbGwgbW9kaWZpZWQgb2JqZWN0IGNvZGUgb24gdGhlIFVzZXIgUHJvZHVjdCAoZm9yIGV4YW1wbGUsIHRoZSB3b3JrIGhhcyBiZWVuIGluc3RhbGxlZCBpbiBST00pLgoKVGhlIHJlcXVpcmVtZW50IHRvIHByb3ZpZGUgSW5zdGFsbGF0aW9uIEluZm9ybWF0aW9uIGRvZXMgbm90IGluY2x1ZGUgYSByZXF1aXJlbWVudCB0byBjb250aW51ZSB0byBwcm92aWRlIHN1cHBvcnQgc2VydmljZSwgd2FycmFudHksIG9yIHVwZGF0ZXMgZm9yIGEgd29yayB0aGF0IGhhcyBiZWVuIG1vZGlmaWVkIG9yIGluc3RhbGxlZCBieSB0aGUgcmVjaXBpZW50LCBvciBmb3IgdGhlIFVzZXIgUHJvZHVjdCBpbiB3aGljaCBpdCBoYXMgYmVlbiBtb2RpZmllZCBvciBpbnN0YWxsZWQuIEFjY2VzcyB0byBhIG5ldHdvcmsgbWF5IGJlIGRlbmllZCB3aGVuIHRoZSBtb2RpZmljYXRpb24gaXRzZWxmIG1hdGVyaWFsbHkgYW5kIGFkdmVyc2VseSBhZmZlY3RzIHRoZSBvcGVyYXRpb24gb2YgdGhlIG5ldHdvcmsgb3IgdmlvbGF0ZXMgdGhlIHJ1bGVzIGFuZCBwcm90b2NvbHMgZm9yIGNvbW11bmljYXRpb24gYWNyb3NzIHRoZSBuZXR3b3JrLgoKQ29ycmVzcG9uZGluZyBTb3VyY2UgY29udmV5ZWQsIGFuZCBJbnN0YWxsYXRpb24gSW5mb3JtYXRpb24gcHJvdmlkZWQsIGluIGFjY29yZCB3aXRoIHRoaXMgc2VjdGlvbiBtdXN0IGJlIGluIGEgZm9ybWF0IHRoYXQgaXMgcHVibGljbHkgZG9jdW1lbnRlZCAoYW5kIHdpdGggYW4gaW1wbGVtZW50YXRpb24gYXZhaWxhYmxlIHRvIHRoZSBwdWJsaWMgaW4gc291cmNlIGNvZGUgZm9ybSksIGFuZCBtdXN0IHJlcXVpcmUgbm8gc3BlY2lhbCBwYXNzd29yZCBvciBrZXkgZm9yIHVucGFja2luZywgcmVhZGluZyBvciBjb3B5aW5nLgoKNy4gQWRkaXRpb25hbCBUZXJtcy4K4oCcQWRkaXRpb25hbCBwZXJtaXNzaW9uc+KAnSBhcmUgdGVybXMgdGhhdCBzdXBwbGVtZW50IHRoZSB0ZXJtcyBvZiB0aGlzIExpY2Vuc2UgYnkgbWFraW5nIGV4Y2VwdGlvbnMgZnJvbSBvbmUgb3IgbW9yZSBvZiBpdHMgY29uZGl0aW9ucy4gQWRkaXRpb25hbCBwZXJtaXNzaW9ucyB0aGF0IGFyZSBhcHBsaWNhYmxlIHRvIHRoZSBlbnRpcmUgUHJvZ3JhbSBzaGFsbCBiZSB0cmVhdGVkIGFzIHRob3VnaCB0aGV5IHdlcmUgaW5jbHVkZWQgaW4gdGhpcyBMaWNlbnNlLCB0byB0aGUgZXh0ZW50IHRoYXQgdGhleSBhcmUgdmFsaWQgdW5kZXIgYXBwbGljYWJsZSBsYXcuIElmIGFkZGl0aW9uYWwgcGVybWlzc2lvbnMgYXBwbHkgb25seSB0byBwYXJ0IG9mIHRoZSBQcm9ncmFtLCB0aGF0IHBhcnQgbWF5IGJlIHVzZWQgc2VwYXJhdGVseSB1bmRlciB0aG9zZSBwZXJtaXNzaW9ucywgYnV0IHRoZSBlbnRpcmUgUHJvZ3JhbSByZW1haW5zIGdvdmVybmVkIGJ5IHRoaXMgTGljZW5zZSB3aXRob3V0IHJlZ2FyZCB0byB0aGUgYWRkaXRpb25hbCBwZXJtaXNzaW9ucy4KCldoZW4geW91IGNvbnZleSBhIGNvcHkgb2YgYSBjb3ZlcmVkIHdvcmssIHlvdSBtYXkgYXQgeW91ciBvcHRpb24gcmVtb3ZlIGFueSBhZGRpdGlvbmFsIHBlcm1pc3Npb25zIGZyb20gdGhhdCBjb3B5LCBvciBmcm9tIGFueSBwYXJ0IG9mIGl0LiAoQWRkaXRpb25hbCBwZXJtaXNzaW9ucyBtYXkgYmUgd3JpdHRlbiB0byByZXF1aXJlIHRoZWlyIG93biByZW1vdmFsIGluIGNlcnRhaW4gY2FzZXMgd2hlbiB5b3UgbW9kaWZ5IHRoZSB3b3JrLikgWW91IG1heSBwbGFjZSBhZGRpdGlvbmFsIHBlcm1pc3Npb25zIG9uIG1hdGVyaWFsLCBhZGRlZCBieSB5b3UgdG8gYSBjb3ZlcmVkIHdvcmssIGZvciB3aGljaCB5b3UgaGF2ZSBvciBjYW4gZ2l2ZSBhcHByb3ByaWF0ZSBjb3B5cmlnaHQgcGVybWlzc2lvbi4KCk5vdHdpdGhzdGFuZGluZyBhbnkgb3RoZXIgcHJvdmlzaW9uIG9mIHRoaXMgTGljZW5zZSwgZm9yIG1hdGVyaWFsIHlvdSBhZGQgdG8gYSBjb3ZlcmVkIHdvcmssIHlvdSBtYXkgKGlmIGF1dGhvcml6ZWQgYnkgdGhlIGNvcHlyaWdodCBob2xkZXJzIG9mIHRoYXQgbWF0ZXJpYWwpIHN1cHBsZW1lbnQgdGhlIHRlcm1zIG9mIHRoaXMgTGljZW5zZSB3aXRoIHRlcm1zOgoKICAgICBhKSBEaXNjbGFpbWluZyB3YXJyYW50eSBvciBsaW1pdGluZyBsaWFiaWxpdHkgZGlmZmVyZW50bHkgZnJvbSB0aGUgdGVybXMgb2Ygc2VjdGlvbnMgMTUgYW5kIDE2IG9mIHRoaXMgTGljZW5zZTsgb3IKCiAgICAgYikgUmVxdWlyaW5nIHByZXNlcnZhdGlvbiBvZiBzcGVjaWZpZWQgcmVhc29uYWJsZSBsZWdhbCBub3RpY2VzIG9yIGF1dGhvciBhdHRyaWJ1dGlvbnMgaW4gdGhhdCBtYXRlcmlhbCBvciBpbiB0aGUgQXBwcm9wcmlhdGUgTGVnYWwgTm90aWNlcyBkaXNwbGF5ZWQgYnkgd29ya3MgY29udGFpbmluZyBpdDsgb3IKCiAgICAgYykgUHJvaGliaXRpbmcgbWlzcmVwcmVzZW50YXRpb24gb2YgdGhlIG9yaWdpbiBvZiB0aGF0IG1hdGVyaWFsLCBvciByZXF1aXJpbmcgdGhhdCBtb2RpZmllZCB2ZXJzaW9ucyBvZiBzdWNoIG1hdGVyaWFsIGJlIG1hcmtlZCBpbiByZWFzb25hYmxlIHdheXMgYXMgZGlmZmVyZW50IGZyb20gdGhlIG9yaWdpbmFsIHZlcnNpb247IG9yCgogICAgIGQpIExpbWl0aW5nIHRoZSB1c2UgZm9yIHB1YmxpY2l0eSBwdXJwb3NlcyBvZiBuYW1lcyBvZiBsaWNlbnNvcnMgb3IgYXV0aG9ycyBvZiB0aGUgbWF0ZXJpYWw7IG9yCgogICAgIGUpIERlY2xpbmluZyB0byBncmFudCByaWdodHMgdW5kZXIgdHJhZGVtYXJrIGxhdyBmb3IgdXNlIG9mIHNvbWUgdHJhZGUgbmFtZXMsIHRyYWRlbWFya3MsIG9yIHNlcnZpY2UgbWFya3M7IG9yCgogICAgIGYpIFJlcXVpcmluZyBpbmRlbW5pZmljYXRpb24gb2YgbGljZW5zb3JzIGFuZCBhdXRob3JzIG9mIHRoYXQgbWF0ZXJpYWwgYnkgYW55b25lIHdobyBjb252ZXlzIHRoZSBtYXRlcmlhbCAob3IgbW9kaWZpZWQgdmVyc2lvbnMgb2YgaXQpIHdpdGggY29udHJhY3R1YWwgYXNzdW1wdGlvbnMgb2YgbGlhYmlsaXR5IHRvIHRoZSByZWNpcGllbnQsIGZvciBhbnkgbGlhYmlsaXR5IHRoYXQgdGhlc2UgY29udHJhY3R1YWwgYXNzdW1wdGlvbnMgZGlyZWN0bHkgaW1wb3NlIG9uIHRob3NlIGxpY2Vuc29ycyBhbmQgYXV0aG9ycy4KCkFsbCBvdGhlciBub24tcGVybWlzc2l2ZSBhZGRpdGlvbmFsIHRlcm1zIGFyZSBjb25zaWRlcmVkIOKAnGZ1cnRoZXIgcmVzdHJpY3Rpb25z4oCdIHdpdGhpbiB0aGUgbWVhbmluZyBvZiBzZWN0aW9uIDEwLiBJZiB0aGUgUHJvZ3JhbSBhcyB5b3UgcmVjZWl2ZWQgaXQsIG9yIGFueSBwYXJ0IG9mIGl0LCBjb250YWlucyBhIG5vdGljZSBzdGF0aW5nIHRoYXQgaXQgaXMgZ292ZXJuZWQgYnkgdGhpcyBMaWNlbnNlIGFsb25nIHdpdGggYSB0ZXJtIHRoYXQgaXMgYSBmdXJ0aGVyIHJlc3RyaWN0aW9uLCB5b3UgbWF5IHJlbW92ZSB0aGF0IHRlcm0uIElmIGEgbGljZW5zZSBkb2N1bWVudCBjb250YWlucyBhIGZ1cnRoZXIgcmVzdHJpY3Rpb24gYnV0IHBlcm1pdHMgcmVsaWNlbnNpbmcgb3IgY29udmV5aW5nIHVuZGVyIHRoaXMgTGljZW5zZSwgeW91IG1heSBhZGQgdG8gYSBjb3ZlcmVkIHdvcmsgbWF0ZXJpYWwgZ292ZXJuZWQgYnkgdGhlIHRlcm1zIG9mIHRoYXQgbGljZW5zZSBkb2N1bWVudCwgcHJvdmlkZWQgdGhhdCB0aGUgZnVydGhlciByZXN0cmljdGlvbiBkb2VzIG5vdCBzdXJ2aXZlIHN1Y2ggcmVsaWNlbnNpbmcgb3IgY29udmV5aW5nLgoKSWYgeW91IGFkZCB0ZXJtcyB0byBhIGNvdmVyZWQgd29yayBpbiBhY2NvcmQgd2l0aCB0aGlzIHNlY3Rpb24sIHlvdSBtdXN0IHBsYWNlLCBpbiB0aGUgcmVsZXZhbnQgc291cmNlIGZpbGVzLCBhIHN0YXRlbWVudCBvZiB0aGUgYWRkaXRpb25hbCB0ZXJtcyB0aGF0IGFwcGx5IHRvIHRob3NlIGZpbGVzLCBvciBhIG5vdGljZSBpbmRpY2F0aW5nIHdoZXJlIHRvIGZpbmQgdGhlIGFwcGxpY2FibGUgdGVybXMuCgpBZGRpdGlvbmFsIHRlcm1zLCBwZXJtaXNzaXZlIG9yIG5vbi1wZXJtaXNzaXZlLCBtYXkgYmUgc3RhdGVkIGluIHRoZSBmb3JtIG9mIGEgc2VwYXJhdGVseSB3cml0dGVuIGxpY2Vuc2UsIG9yIHN0YXRlZCBhcyBleGNlcHRpb25zOyB0aGUgYWJvdmUgcmVxdWlyZW1lbnRzIGFwcGx5IGVpdGhlciB3YXkuCgo4LiBUZXJtaW5hdGlvbi4KWW91IG1heSBub3QgcHJvcGFnYXRlIG9yIG1vZGlmeSBhIGNvdmVyZWQgd29yayBleGNlcHQgYXMgZXhwcmVzc2x5IHByb3ZpZGVkIHVuZGVyIHRoaXMgTGljZW5zZS4gQW55IGF0dGVtcHQgb3RoZXJ3aXNlIHRvIHByb3BhZ2F0ZSBvciBtb2RpZnkgaXQgaXMgdm9pZCwgYW5kIHdpbGwgYXV0b21hdGljYWxseSB0ZXJtaW5hdGUgeW91ciByaWdodHMgdW5kZXIgdGhpcyBMaWNlbnNlIChpbmNsdWRpbmcgYW55IHBhdGVudCBsaWNlbnNlcyBncmFudGVkIHVuZGVyIHRoZSB0aGlyZCBwYXJhZ3JhcGggb2Ygc2VjdGlvbiAxMSkuCgpIb3dldmVyLCBpZiB5b3UgY2Vhc2UgYWxsIHZpb2xhdGlvbiBvZiB0aGlzIExpY2Vuc2UsIHRoZW4geW91ciBsaWNlbnNlIGZyb20gYSBwYXJ0aWN1bGFyIGNvcHlyaWdodCBob2xkZXIgaXMgcmVpbnN0YXRlZCAoYSkgcHJvdmlzaW9uYWxseSwgdW5sZXNzIGFuZCB1bnRpbCB0aGUgY29weXJpZ2h0IGhvbGRlciBleHBsaWNpdGx5IGFuZCBmaW5hbGx5IHRlcm1pbmF0ZXMgeW91ciBsaWNlbnNlLCBhbmQgKGIpIHBlcm1hbmVudGx5LCBpZiB0aGUgY29weXJpZ2h0IGhvbGRlciBmYWlscyB0byBub3RpZnkgeW91IG9mIHRoZSB2aW9sYXRpb24gYnkgc29tZSByZWFzb25hYmxlIG1lYW5zIHByaW9yIHRvIDYwIGRheXMgYWZ0ZXIgdGhlIGNlc3NhdGlvbi4KCk1vcmVvdmVyLCB5b3VyIGxpY2Vuc2UgZnJvbSBhIHBhcnRpY3VsYXIgY29weXJpZ2h0IGhvbGRlciBpcyByZWluc3RhdGVkIHBlcm1hbmVudGx5IGlmIHRoZSBjb3B5cmlnaHQgaG9sZGVyIG5vdGlmaWVzIHlvdSBvZiB0aGUgdmlvbGF0aW9uIGJ5IHNvbWUgcmVhc29uYWJsZSBtZWFucywgdGhpcyBpcyB0aGUgZmlyc3QgdGltZSB5b3UgaGF2ZSByZWNlaXZlZCBub3RpY2Ugb2YgdmlvbGF0aW9uIG9mIHRoaXMgTGljZW5zZSAoZm9yIGFueSB3b3JrKSBmcm9tIHRoYXQgY29weXJpZ2h0IGhvbGRlciwgYW5kIHlvdSBjdXJlIHRoZSB2aW9sYXRpb24gcHJpb3IgdG8gMzAgZGF5cyBhZnRlciB5b3VyIHJlY2VpcHQgb2YgdGhlIG5vdGljZS4KClRlcm1pbmF0aW9uIG9mIHlvdXIgcmlnaHRzIHVuZGVyIHRoaXMgc2VjdGlvbiBkb2VzIG5vdCB0ZXJtaW5hdGUgdGhlIGxpY2Vuc2VzIG9mIHBhcnRpZXMgd2hvIGhhdmUgcmVjZWl2ZWQgY29waWVzIG9yIHJpZ2h0cyBmcm9tIHlvdSB1bmRlciB0aGlzIExpY2Vuc2UuIElmIHlvdXIgcmlnaHRzIGhhdmUgYmVlbiB0ZXJtaW5hdGVkIGFuZCBub3QgcGVybWFuZW50bHkgcmVpbnN0YXRlZCwgeW91IGRvIG5vdCBxdWFsaWZ5IHRvIHJlY2VpdmUgbmV3IGxpY2Vuc2VzIGZvciB0aGUgc2FtZSBtYXRlcmlhbCB1bmRlciBzZWN0aW9uIDEwLgoKOS4gQWNjZXB0YW5jZSBOb3QgUmVxdWlyZWQgZm9yIEhhdmluZyBDb3BpZXMuCllvdSBhcmUgbm90IHJlcXVpcmVkIHRvIGFjY2VwdCB0aGlzIExpY2Vuc2UgaW4gb3JkZXIgdG8gcmVjZWl2ZSBvciBydW4gYSBjb3B5IG9mIHRoZSBQcm9ncmFtLiBBbmNpbGxhcnkgcHJvcGFnYXRpb24gb2YgYSBjb3ZlcmVkIHdvcmsgb2NjdXJyaW5nIHNvbGVseSBhcyBhIGNvbnNlcXVlbmNlIG9mIHVzaW5nIHBlZXItdG8tcGVlciB0cmFuc21pc3Npb24gdG8gcmVjZWl2ZSBhIGNvcHkgbGlrZXdpc2UgZG9lcyBub3QgcmVxdWlyZSBhY2NlcHRhbmNlLiBIb3dldmVyLCBub3RoaW5nIG90aGVyIHRoYW4gdGhpcyBMaWNlbnNlIGdyYW50cyB5b3UgcGVybWlzc2lvbiB0byBwcm9wYWdhdGUgb3IgbW9kaWZ5IGFueSBjb3ZlcmVkIHdvcmsuIFRoZXNlIGFjdGlvbnMgaW5mcmluZ2UgY29weXJpZ2h0IGlmIHlvdSBkbyBub3QgYWNjZXB0IHRoaXMgTGljZW5zZS4gVGhlcmVmb3JlLCBieSBtb2RpZnlpbmcgb3IgcHJvcGFnYXRpbmcgYSBjb3ZlcmVkIHdvcmssIHlvdSBpbmRpY2F0ZSB5b3VyIGFjY2VwdGFuY2Ugb2YgdGhpcyBMaWNlbnNlIHRvIGRvIHNvLgoKMTAuIEF1dG9tYXRpYyBMaWNlbnNpbmcgb2YgRG93bnN0cmVhbSBSZWNpcGllbnRzLgpFYWNoIHRpbWUgeW91IGNvbnZleSBhIGNvdmVyZWQgd29yaywgdGhlIHJlY2lwaWVudCBhdXRvbWF0aWNhbGx5IHJlY2VpdmVzIGEgbGljZW5zZSBmcm9tIHRoZSBvcmlnaW5hbCBsaWNlbnNvcnMsIHRvIHJ1biwgbW9kaWZ5IGFuZCBwcm9wYWdhdGUgdGhhdCB3b3JrLCBzdWJqZWN0IHRvIHRoaXMgTGljZW5zZS4gWW91IGFyZSBub3QgcmVzcG9uc2libGUgZm9yIGVuZm9yY2luZyBjb21wbGlhbmNlIGJ5IHRoaXJkIHBhcnRpZXMgd2l0aCB0aGlzIExpY2Vuc2UuCgpBbiDigJxlbnRpdHkgdHJhbnNhY3Rpb27igJ0gaXMgYSB0cmFuc2FjdGlvbiB0cmFuc2ZlcnJpbmcgY29udHJvbCBvZiBhbiBvcmdhbml6YXRpb24sIG9yIHN1YnN0YW50aWFsbHkgYWxsIGFzc2V0cyBvZiBvbmUsIG9yIHN1YmRpdmlkaW5nIGFuIG9yZ2FuaXphdGlvbiwgb3IgbWVyZ2luZyBvcmdhbml6YXRpb25zLiBJZiBwcm9wYWdhdGlvbiBvZiBhIGNvdmVyZWQgd29yayByZXN1bHRzIGZyb20gYW4gZW50aXR5IHRyYW5zYWN0aW9uLCBlYWNoIHBhcnR5IHRvIHRoYXQgdHJhbnNhY3Rpb24gd2hvIHJlY2VpdmVzIGEgY29weSBvZiB0aGUgd29yayBhbHNvIHJlY2VpdmVzIHdoYXRldmVyIGxpY2Vuc2VzIHRvIHRoZSB3b3JrIHRoZSBwYXJ0eSdzIHByZWRlY2Vzc29yIGluIGludGVyZXN0IGhhZCBvciBjb3VsZCBnaXZlIHVuZGVyIHRoZSBwcmV2aW91cyBwYXJhZ3JhcGgsIHBsdXMgYSByaWdodCB0byBwb3NzZXNzaW9uIG9mIHRoZSBDb3JyZXNwb25kaW5nIFNvdXJjZSBvZiB0aGUgd29yayBmcm9tIHRoZSBwcmVkZWNlc3NvciBpbiBpbnRlcmVzdCwgaWYgdGhlIHByZWRlY2Vzc29yIGhhcyBpdCBvciBjYW4gZ2V0IGl0IHdpdGggcmVhc29uYWJsZSBlZmZvcnRzLgoKWW91IG1heSBub3QgaW1wb3NlIGFueSBmdXJ0aGVyIHJlc3RyaWN0aW9ucyBvbiB0aGUgZXhlcmNpc2Ugb2YgdGhlIHJpZ2h0cyBncmFudGVkIG9yIGFmZmlybWVkIHVuZGVyIHRoaXMgTGljZW5zZS4gRm9yIGV4YW1wbGUsIHlvdSBtYXkgbm90IGltcG9zZSBhIGxpY2Vuc2UgZmVlLCByb3lhbHR5LCBvciBvdGhlciBjaGFyZ2UgZm9yIGV4ZXJjaXNlIG9mIHJpZ2h0cyBncmFudGVkIHVuZGVyIHRoaXMgTGljZW5zZSwgYW5kIHlvdSBtYXkgbm90IGluaXRpYXRlIGxpdGlnYXRpb24gKGluY2x1ZGluZyBhIGNyb3NzLWNsYWltIG9yIGNvdW50ZXJjbGFpbSBpbiBhIGxhd3N1aXQpIGFsbGVnaW5nIHRoYXQgYW55IHBhdGVudCBjbGFpbSBpcyBpbmZyaW5nZWQgYnkgbWFraW5nLCB1c2luZywgc2VsbGluZywgb2ZmZXJpbmcgZm9yIHNhbGUsIG9yIGltcG9ydGluZyB0aGUgUHJvZ3JhbSBvciBhbnkgcG9ydGlvbiBvZiBpdC4KCjExLiBQYXRlbnRzLgpBIOKAnGNvbnRyaWJ1dG9y4oCdIGlzIGEgY29weXJpZ2h0IGhvbGRlciB3aG8gYXV0aG9yaXplcyB1c2UgdW5kZXIgdGhpcyBMaWNlbnNlIG9mIHRoZSBQcm9ncmFtIG9yIGEgd29yayBvbiB3aGljaCB0aGUgUHJvZ3JhbSBpcyBiYXNlZC4gVGhlIHdvcmsgdGh1cyBsaWNlbnNlZCBpcyBjYWxsZWQgdGhlIGNvbnRyaWJ1dG9yJ3Mg4oCcY29udHJpYnV0b3IgdmVyc2lvbuKAnS4KCkEgY29udHJpYnV0b3IncyDigJxlc3NlbnRpYWwgcGF0ZW50IGNsYWltc+KAnSBhcmUgYWxsIHBhdGVudCBjbGFpbXMgb3duZWQgb3IgY29udHJvbGxlZCBieSB0aGUgY29udHJpYnV0b3IsIHdoZXRoZXIgYWxyZWFkeSBhY3F1aXJlZCBvciBoZXJlYWZ0ZXIgYWNxdWlyZWQsIHRoYXQgd291bGQgYmUgaW5mcmluZ2VkIGJ5IHNvbWUgbWFubmVyLCBwZXJtaXR0ZWQgYnkgdGhpcyBMaWNlbnNlLCBvZiBtYWtpbmcsIHVzaW5nLCBvciBzZWxsaW5nIGl0cyBjb250cmlidXRvciB2ZXJzaW9uLCBidXQgZG8gbm90IGluY2x1ZGUgY2xhaW1zIHRoYXQgd291bGQgYmUgaW5mcmluZ2VkIG9ubHkgYXMgYSBjb25zZXF1ZW5jZSBvZiBmdXJ0aGVyIG1vZGlmaWNhdGlvbiBvZiB0aGUgY29udHJpYnV0b3IgdmVyc2lvbi4gRm9yIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwg4oCcY29udHJvbOKAnSBpbmNsdWRlcyB0aGUgcmlnaHQgdG8gZ3JhbnQgcGF0ZW50IHN1YmxpY2Vuc2VzIGluIGEgbWFubmVyIGNvbnNpc3RlbnQgd2l0aCB0aGUgcmVxdWlyZW1lbnRzIG9mIHRoaXMgTGljZW5zZS4KCkVhY2ggY29udHJpYnV0b3IgZ3JhbnRzIHlvdSBhIG5vbi1leGNsdXNpdmUsIHdvcmxkd2lkZSwgcm95YWx0eS1mcmVlIHBhdGVudCBsaWNlbnNlIHVuZGVyIHRoZSBjb250cmlidXRvcidzIGVzc2VudGlhbCBwYXRlbnQgY2xhaW1zLCB0byBtYWtlLCB1c2UsIHNlbGwsIG9mZmVyIGZvciBzYWxlLCBpbXBvcnQgYW5kIG90aGVyd2lzZSBydW4sIG1vZGlmeSBhbmQgcHJvcGFnYXRlIHRoZSBjb250ZW50cyBvZiBpdHMgY29udHJpYnV0b3IgdmVyc2lvbi4KCkluIHRoZSBmb2xsb3dpbmcgdGhyZWUgcGFyYWdyYXBocywgYSDigJxwYXRlbnQgbGljZW5zZeKAnSBpcyBhbnkgZXhwcmVzcyBhZ3JlZW1lbnQgb3IgY29tbWl0bWVudCwgaG93ZXZlciBkZW5vbWluYXRlZCwgbm90IHRvIGVuZm9yY2UgYSBwYXRlbnQgKHN1Y2ggYXMgYW4gZXhwcmVzcyBwZXJtaXNzaW9uIHRvIHByYWN0aWNlIGEgcGF0ZW50IG9yIGNvdmVuYW50IG5vdCB0byBzdWUgZm9yIHBhdGVudCBpbmZyaW5nZW1lbnQpLiBUbyDigJxncmFudOKAnSBzdWNoIGEgcGF0ZW50IGxpY2Vuc2UgdG8gYSBwYXJ0eSBtZWFucyB0byBtYWtlIHN1Y2ggYW4gYWdyZWVtZW50IG9yIGNvbW1pdG1lbnQgbm90IHRvIGVuZm9yY2UgYSBwYXRlbnQgYWdhaW5zdCB0aGUgcGFydHkuCgpJZiB5b3UgY29udmV5IGEgY292ZXJlZCB3b3JrLCBrbm93aW5nbHkgcmVseWluZyBvbiBhIHBhdGVudCBsaWNlbnNlLCBhbmQgdGhlIENvcnJlc3BvbmRpbmcgU291cmNlIG9mIHRoZSB3b3JrIGlzIG5vdCBhdmFpbGFibGUgZm9yIGFueW9uZSB0byBjb3B5LCBmcmVlIG9mIGNoYXJnZSBhbmQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoaXMgTGljZW5zZSwgdGhyb3VnaCBhIHB1YmxpY2x5IGF2YWlsYWJsZSBuZXR3b3JrIHNlcnZlciBvciBvdGhlciByZWFkaWx5IGFjY2Vzc2libGUgbWVhbnMsIHRoZW4geW91IG11c3QgZWl0aGVyICgxKSBjYXVzZSB0aGUgQ29ycmVzcG9uZGluZyBTb3VyY2UgdG8gYmUgc28gYXZhaWxhYmxlLCBvciAoMikgYXJyYW5nZSB0byBkZXByaXZlIHlvdXJzZWxmIG9mIHRoZSBiZW5lZml0IG9mIHRoZSBwYXRlbnQgbGljZW5zZSBmb3IgdGhpcyBwYXJ0aWN1bGFyIHdvcmssIG9yICgzKSBhcnJhbmdlLCBpbiBhIG1hbm5lciBjb25zaXN0ZW50IHdpdGggdGhlIHJlcXVpcmVtZW50cyBvZiB0aGlzIExpY2Vuc2UsIHRvIGV4dGVuZCB0aGUgcGF0ZW50IGxpY2Vuc2UgdG8gZG93bnN0cmVhbSByZWNpcGllbnRzLiDigJxLbm93aW5nbHkgcmVseWluZ+KAnSBtZWFucyB5b3UgaGF2ZSBhY3R1YWwga25vd2xlZGdlIHRoYXQsIGJ1dCBmb3IgdGhlIHBhdGVudCBsaWNlbnNlLCB5b3VyIGNvbnZleWluZyB0aGUgY292ZXJlZCB3b3JrIGluIGEgY291bnRyeSwgb3IgeW91ciByZWNpcGllbnQncyB1c2Ugb2YgdGhlIGNvdmVyZWQgd29yayBpbiBhIGNvdW50cnksIHdvdWxkIGluZnJpbmdlIG9uZSBvciBtb3JlIGlkZW50aWZpYWJsZSBwYXRlbnRzIGluIHRoYXQgY291bnRyeSB0aGF0IHlvdSBoYXZlIHJlYXNvbiB0byBiZWxpZXZlIGFyZSB2YWxpZC4KCklmLCBwdXJzdWFudCB0byBvciBpbiBjb25uZWN0aW9uIHdpdGggYSBzaW5nbGUgdHJhbnNhY3Rpb24gb3IgYXJyYW5nZW1lbnQsIHlvdSBjb252ZXksIG9yIHByb3BhZ2F0ZSBieSBwcm9jdXJpbmcgY29udmV5YW5jZSBvZiwgYSBjb3ZlcmVkIHdvcmssIGFuZCBncmFudCBhIHBhdGVudCBsaWNlbnNlIHRvIHNvbWUgb2YgdGhlIHBhcnRpZXMgcmVjZWl2aW5nIHRoZSBjb3ZlcmVkIHdvcmsgYXV0aG9yaXppbmcgdGhlbSB0byB1c2UsIHByb3BhZ2F0ZSwgbW9kaWZ5IG9yIGNvbnZleSBhIHNwZWNpZmljIGNvcHkgb2YgdGhlIGNvdmVyZWQgd29yaywgdGhlbiB0aGUgcGF0ZW50IGxpY2Vuc2UgeW91IGdyYW50IGlzIGF1dG9tYXRpY2FsbHkgZXh0ZW5kZWQgdG8gYWxsIHJlY2lwaWVudHMgb2YgdGhlIGNvdmVyZWQgd29yayBhbmQgd29ya3MgYmFzZWQgb24gaXQuCgpBIHBhdGVudCBsaWNlbnNlIGlzIOKAnGRpc2NyaW1pbmF0b3J54oCdIGlmIGl0IGRvZXMgbm90IGluY2x1ZGUgd2l0aGluIHRoZSBzY29wZSBvZiBpdHMgY292ZXJhZ2UsIHByb2hpYml0cyB0aGUgZXhlcmNpc2Ugb2YsIG9yIGlzIGNvbmRpdGlvbmVkIG9uIHRoZSBub24tZXhlcmNpc2Ugb2Ygb25lIG9yIG1vcmUgb2YgdGhlIHJpZ2h0cyB0aGF0IGFyZSBzcGVjaWZpY2FsbHkgZ3JhbnRlZCB1bmRlciB0aGlzIExpY2Vuc2UuIFlvdSBtYXkgbm90IGNvbnZleSBhIGNvdmVyZWQgd29yayBpZiB5b3UgYXJlIGEgcGFydHkgdG8gYW4gYXJyYW5nZW1lbnQgd2l0aCBhIHRoaXJkIHBhcnR5IHRoYXQgaXMgaW4gdGhlIGJ1c2luZXNzIG9mIGRpc3RyaWJ1dGluZyBzb2Z0d2FyZSwgdW5kZXIgd2hpY2ggeW91IG1ha2UgcGF5bWVudCB0byB0aGUgdGhpcmQgcGFydHkgYmFzZWQgb24gdGhlIGV4dGVudCBvZiB5b3VyIGFjdGl2aXR5IG9mIGNvbnZleWluZyB0aGUgd29yaywgYW5kIHVuZGVyIHdoaWNoIHRoZSB0aGlyZCBwYXJ0eSBncmFudHMsIHRvIGFueSBvZiB0aGUgcGFydGllcyB3aG8gd291bGQgcmVjZWl2ZSB0aGUgY292ZXJlZCB3b3JrIGZyb20geW91LCBhIGRpc2NyaW1pbmF0b3J5IHBhdGVudCBsaWNlbnNlIChhKSBpbiBjb25uZWN0aW9uIHdpdGggY29waWVzIG9mIHRoZSBjb3ZlcmVkIHdvcmsgY29udmV5ZWQgYnkgeW91IChvciBjb3BpZXMgbWFkZSBmcm9tIHRob3NlIGNvcGllcyksIG9yIChiKSBwcmltYXJpbHkgZm9yIGFuZCBpbiBjb25uZWN0aW9uIHdpdGggc3BlY2lmaWMgcHJvZHVjdHMgb3IgY29tcGlsYXRpb25zIHRoYXQgY29udGFpbiB0aGUgY292ZXJlZCB3b3JrLCB1bmxlc3MgeW91IGVudGVyZWQgaW50byB0aGF0IGFycmFuZ2VtZW50LCBvciB0aGF0IHBhdGVudCBsaWNlbnNlIHdhcyBncmFudGVkLCBwcmlvciB0byAyOCBNYXJjaCAyMDA3LgoKTm90aGluZyBpbiB0aGlzIExpY2Vuc2Ugc2hhbGwgYmUgY29uc3RydWVkIGFzIGV4Y2x1ZGluZyBvciBsaW1pdGluZyBhbnkgaW1wbGllZCBsaWNlbnNlIG9yIG90aGVyIGRlZmVuc2VzIHRvIGluZnJpbmdlbWVudCB0aGF0IG1heSBvdGhlcndpc2UgYmUgYXZhaWxhYmxlIHRvIHlvdSB1bmRlciBhcHBsaWNhYmxlIHBhdGVudCBsYXcuCgoxMi4gTm8gU3VycmVuZGVyIG9mIE90aGVycycgRnJlZWRvbS4KSWYgY29uZGl0aW9ucyBhcmUgaW1wb3NlZCBvbiB5b3UgKHdoZXRoZXIgYnkgY291cnQgb3JkZXIsIGFncmVlbWVudCBvciBvdGhlcndpc2UpIHRoYXQgY29udHJhZGljdCB0aGUgY29uZGl0aW9ucyBvZiB0aGlzIExpY2Vuc2UsIHRoZXkgZG8gbm90IGV4Y3VzZSB5b3UgZnJvbSB0aGUgY29uZGl0aW9ucyBvZiB0aGlzIExpY2Vuc2UuIElmIHlvdSBjYW5ub3QgY29udmV5IGEgY292ZXJlZCB3b3JrIHNvIGFzIHRvIHNhdGlzZnkgc2ltdWx0YW5lb3VzbHkgeW91ciBvYmxpZ2F0aW9ucyB1bmRlciB0aGlzIExpY2Vuc2UgYW5kIGFueSBvdGhlciBwZXJ0aW5lbnQgb2JsaWdhdGlvbnMsIHRoZW4gYXMgYSBjb25zZXF1ZW5jZSB5b3UgbWF5IG5vdCBjb252ZXkgaXQgYXQgYWxsLiBGb3IgZXhhbXBsZSwgaWYgeW91IGFncmVlIHRvIHRlcm1zIHRoYXQgb2JsaWdhdGUgeW91IHRvIGNvbGxlY3QgYSByb3lhbHR5IGZvciBmdXJ0aGVyIGNvbnZleWluZyBmcm9tIHRob3NlIHRvIHdob20geW91IGNvbnZleSB0aGUgUHJvZ3JhbSwgdGhlIG9ubHkgd2F5IHlvdSBjb3VsZCBzYXRpc2Z5IGJvdGggdGhvc2UgdGVybXMgYW5kIHRoaXMgTGljZW5zZSB3b3VsZCBiZSB0byByZWZyYWluIGVudGlyZWx5IGZyb20gY29udmV5aW5nIHRoZSBQcm9ncmFtLgoKMTMuIFVzZSB3aXRoIHRoZSBHTlUgQWZmZXJvIEdlbmVyYWwgUHVibGljIExpY2Vuc2UuCk5vdHdpdGhzdGFuZGluZyBhbnkgb3RoZXIgcHJvdmlzaW9uIG9mIHRoaXMgTGljZW5zZSwgeW91IGhhdmUgcGVybWlzc2lvbiB0byBsaW5rIG9yIGNvbWJpbmUgYW55IGNvdmVyZWQgd29yayB3aXRoIGEgd29yayBsaWNlbnNlZCB1bmRlciB2ZXJzaW9uIDMgb2YgdGhlIEdOVSBBZmZlcm8gR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBpbnRvIGEgc2luZ2xlIGNvbWJpbmVkIHdvcmssIGFuZCB0byBjb252ZXkgdGhlIHJlc3VsdGluZyB3b3JrLiBUaGUgdGVybXMgb2YgdGhpcyBMaWNlbnNlIHdpbGwgY29udGludWUgdG8gYXBwbHkgdG8gdGhlIHBhcnQgd2hpY2ggaXMgdGhlIGNvdmVyZWQgd29yaywgYnV0IHRoZSBzcGVjaWFsIHJlcXVpcmVtZW50cyBvZiB0aGUgR05VIEFmZmVybyBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlLCBzZWN0aW9uIDEzLCBjb25jZXJuaW5nIGludGVyYWN0aW9uIHRocm91Z2ggYSBuZXR3b3JrIHdpbGwgYXBwbHkgdG8gdGhlIGNvbWJpbmF0aW9uIGFzIHN1Y2guCgoxNC4gUmV2aXNlZCBWZXJzaW9ucyBvZiB0aGlzIExpY2Vuc2UuClRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24gbWF5IHB1Ymxpc2ggcmV2aXNlZCBhbmQvb3IgbmV3IHZlcnNpb25zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmcm9tIHRpbWUgdG8gdGltZS4gU3VjaCBuZXcgdmVyc2lvbnMgd2lsbCBiZSBzaW1pbGFyIGluIHNwaXJpdCB0byB0aGUgcHJlc2VudCB2ZXJzaW9uLCBidXQgbWF5IGRpZmZlciBpbiBkZXRhaWwgdG8gYWRkcmVzcyBuZXcgcHJvYmxlbXMgb3IgY29uY2VybnMuCgpFYWNoIHZlcnNpb24gaXMgZ2l2ZW4gYSBkaXN0aW5ndWlzaGluZyB2ZXJzaW9uIG51bWJlci4gSWYgdGhlIFByb2dyYW0gc3BlY2lmaWVzIHRoYXQgYSBjZXJ0YWluIG51bWJlcmVkIHZlcnNpb24gb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIOKAnG9yIGFueSBsYXRlciB2ZXJzaW9u4oCdIGFwcGxpZXMgdG8gaXQsIHlvdSBoYXZlIHRoZSBvcHRpb24gb2YgZm9sbG93aW5nIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBlaXRoZXIgb2YgdGhhdCBudW1iZXJlZCB2ZXJzaW9uIG9yIG9mIGFueSBsYXRlciB2ZXJzaW9uIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLiBJZiB0aGUgUHJvZ3JhbSBkb2VzIG5vdCBzcGVjaWZ5IGEgdmVyc2lvbiBudW1iZXIgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlLCB5b3UgbWF5IGNob29zZSBhbnkgdmVyc2lvbiBldmVyIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLgoKSWYgdGhlIFByb2dyYW0gc3BlY2lmaWVzIHRoYXQgYSBwcm94eSBjYW4gZGVjaWRlIHdoaWNoIGZ1dHVyZSB2ZXJzaW9ucyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgY2FuIGJlIHVzZWQsIHRoYXQgcHJveHkncyBwdWJsaWMgc3RhdGVtZW50IG9mIGFjY2VwdGFuY2Ugb2YgYSB2ZXJzaW9uIHBlcm1hbmVudGx5IGF1dGhvcml6ZXMgeW91IHRvIGNob29zZSB0aGF0IHZlcnNpb24gZm9yIHRoZSBQcm9ncmFtLgoKTGF0ZXIgbGljZW5zZSB2ZXJzaW9ucyBtYXkgZ2l2ZSB5b3UgYWRkaXRpb25hbCBvciBkaWZmZXJlbnQgcGVybWlzc2lvbnMuIEhvd2V2ZXIsIG5vIGFkZGl0aW9uYWwgb2JsaWdhdGlvbnMgYXJlIGltcG9zZWQgb24gYW55IGF1dGhvciBvciBjb3B5cmlnaHQgaG9sZGVyIGFzIGEgcmVzdWx0IG9mIHlvdXIgY2hvb3NpbmcgdG8gZm9sbG93IGEgbGF0ZXIgdmVyc2lvbi4KCjE1LiBEaXNjbGFpbWVyIG9mIFdhcnJhbnR5LgpUSEVSRSBJUyBOTyBXQVJSQU5UWSBGT1IgVEhFIFBST0dSQU0sIFRPIFRIRSBFWFRFTlQgUEVSTUlUVEVEIEJZIEFQUExJQ0FCTEUgTEFXLiBFWENFUFQgV0hFTiBPVEhFUldJU0UgU1RBVEVEIElOIFdSSVRJTkcgVEhFIENPUFlSSUdIVCBIT0xERVJTIEFORC9PUiBPVEhFUiBQQVJUSUVTIFBST1ZJREUgVEhFIFBST0dSQU0g4oCcQVMgSVPigJ0gV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRUlUSEVSIEVYUFJFU1NFRCBPUiBJTVBMSUVELCBJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFIElNUExJRUQgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBUSEUgRU5USVJFIFJJU0sgQVMgVE8gVEhFIFFVQUxJVFkgQU5EIFBFUkZPUk1BTkNFIE9GIFRIRSBQUk9HUkFNIElTIFdJVEggWU9VLiBTSE9VTEQgVEhFIFBST0dSQU0gUFJPVkUgREVGRUNUSVZFLCBZT1UgQVNTVU1FIFRIRSBDT1NUIE9GIEFMTCBORUNFU1NBUlkgU0VSVklDSU5HLCBSRVBBSVIgT1IgQ09SUkVDVElPTi4KCjE2LiBMaW1pdGF0aW9uIG9mIExpYWJpbGl0eS4KSU4gTk8gRVZFTlQgVU5MRVNTIFJFUVVJUkVEIEJZIEFQUExJQ0FCTEUgTEFXIE9SIEFHUkVFRCBUTyBJTiBXUklUSU5HIFdJTEwgQU5ZIENPUFlSSUdIVCBIT0xERVIsIE9SIEFOWSBPVEhFUiBQQVJUWSBXSE8gTU9ESUZJRVMgQU5EL09SIENPTlZFWVMgVEhFIFBST0dSQU0gQVMgUEVSTUlUVEVEIEFCT1ZFLCBCRSBMSUFCTEUgVE8gWU9VIEZPUiBEQU1BR0VTLCBJTkNMVURJTkcgQU5ZIEdFTkVSQUwsIFNQRUNJQUwsIElOQ0lERU5UQUwgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTIEFSSVNJTkcgT1VUIE9GIFRIRSBVU0UgT1IgSU5BQklMSVRZIFRPIFVTRSBUSEUgUFJPR1JBTSAoSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBMT1NTIE9GIERBVEEgT1IgREFUQSBCRUlORyBSRU5ERVJFRCBJTkFDQ1VSQVRFIE9SIExPU1NFUyBTVVNUQUlORUQgQlkgWU9VIE9SIFRISVJEIFBBUlRJRVMgT1IgQSBGQUlMVVJFIE9GIFRIRSBQUk9HUkFNIFRPIE9QRVJBVEUgV0lUSCBBTlkgT1RIRVIgUFJPR1JBTVMpLCBFVkVOIElGIFNVQ0ggSE9MREVSIE9SIE9USEVSIFBBUlRZIEhBUyBCRUVOIEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GIFNVQ0ggREFNQUdFUy4KCjE3LiBJbnRlcnByZXRhdGlvbiBvZiBTZWN0aW9ucyAxNSBhbmQgMTYuCklmIHRoZSBkaXNjbGFpbWVyIG9mIHdhcnJhbnR5IGFuZCBsaW1pdGF0aW9uIG9mIGxpYWJpbGl0eSBwcm92aWRlZCBhYm92ZSBjYW5ub3QgYmUgZ2l2ZW4gbG9jYWwgbGVnYWwgZWZmZWN0IGFjY29yZGluZyB0byB0aGVpciB0ZXJtcywgcmV2aWV3aW5nIGNvdXJ0cyBzaGFsbCBhcHBseSBsb2NhbCBsYXcgdGhhdCBtb3N0IGNsb3NlbHkgYXBwcm94aW1hdGVzIGFuIGFic29sdXRlIHdhaXZlciBvZiBhbGwgY2l2aWwgbGlhYmlsaXR5IGluIGNvbm5lY3Rpb24gd2l0aCB0aGUgUHJvZ3JhbSwgdW5sZXNzIGEgd2FycmFudHkgb3IgYXNzdW1wdGlvbiBvZiBsaWFiaWxpdHkgYWNjb21wYW5pZXMgYSBjb3B5IG9mIHRoZSBQcm9ncmFtIGluIHJldHVybiBmb3IgYSBmZWUuCgpFTkQgT0YgVEVSTVMgQU5EIENPTkRJVElPTlMKCkhvdyB0byBBcHBseSBUaGVzZSBUZXJtcyB0byBZb3VyIE5ldyBQcm9ncmFtcwoKSWYgeW91IGRldmVsb3AgYSBuZXcgcHJvZ3JhbSwgYW5kIHlvdSB3YW50IGl0IHRvIGJlIG9mIHRoZSBncmVhdGVzdCBwb3NzaWJsZSB1c2UgdG8gdGhlIHB1YmxpYywgdGhlIGJlc3Qgd2F5IHRvIGFjaGlldmUgdGhpcyBpcyB0byBtYWtlIGl0IGZyZWUgc29mdHdhcmUgd2hpY2ggZXZlcnlvbmUgY2FuIHJlZGlzdHJpYnV0ZSBhbmQgY2hhbmdlIHVuZGVyIHRoZXNlIHRlcm1zLgoKVG8gZG8gc28sIGF0dGFjaCB0aGUgZm9sbG93aW5nIG5vdGljZXMgdG8gdGhlIHByb2dyYW0uIEl0IGlzIHNhZmVzdCB0byBhdHRhY2ggdGhlbSB0byB0aGUgc3RhcnQgb2YgZWFjaCBzb3VyY2UgZmlsZSB0byBtb3N0IGVmZmVjdGl2ZWx5IHN0YXRlIHRoZSBleGNsdXNpb24gb2Ygd2FycmFudHk7IGFuZCBlYWNoIGZpbGUgc2hvdWxkIGhhdmUgYXQgbGVhc3QgdGhlIOKAnGNvcHlyaWdodOKAnSBsaW5lIGFuZCBhIHBvaW50ZXIgdG8gd2hlcmUgdGhlIGZ1bGwgbm90aWNlIGlzIGZvdW5kLgoKICAgICA8b25lIGxpbmUgdG8gZ2l2ZSB0aGUgcHJvZ3JhbSdzIG5hbWUgYW5kIGEgYnJpZWYgaWRlYSBvZiB3aGF0IGl0IGRvZXMuPgogICAgIENvcHlyaWdodCAoQykgPHllYXI+ICA8bmFtZSBvZiBhdXRob3I+CgogICAgIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uCgogICAgIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuCgogICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LgoKQWxzbyBhZGQgaW5mb3JtYXRpb24gb24gaG93IHRvIGNvbnRhY3QgeW91IGJ5IGVsZWN0cm9uaWMgYW5kIHBhcGVyIG1haWwuCgpJZiB0aGUgcHJvZ3JhbSBkb2VzIHRlcm1pbmFsIGludGVyYWN0aW9uLCBtYWtlIGl0IG91dHB1dCBhIHNob3J0IG5vdGljZSBsaWtlIHRoaXMgd2hlbiBpdCBzdGFydHMgaW4gYW4gaW50ZXJhY3RpdmUgbW9kZToKCiAgICAgPHByb2dyYW0+ICBDb3B5cmlnaHQgKEMpIDx5ZWFyPiAgPG5hbWUgb2YgYXV0aG9yPgogICAgIFRoaXMgcHJvZ3JhbSBjb21lcyB3aXRoIEFCU09MVVRFTFkgTk8gV0FSUkFOVFk7IGZvciBkZXRhaWxzIHR5cGUgYHNob3cgdycuCiAgICAgVGhpcyBpcyBmcmVlIHNvZnR3YXJlLCBhbmQgeW91IGFyZSB3ZWxjb21lIHRvIHJlZGlzdHJpYnV0ZSBpdCB1bmRlciBjZXJ0YWluIGNvbmRpdGlvbnM7IHR5cGUgYHNob3cgYycgZm9yIGRldGFpbHMuCgpUaGUgaHlwb3RoZXRpY2FsIGNvbW1hbmRzIGBzaG93IHcnIGFuZCBgc2hvdyBjJyBzaG91bGQgc2hvdyB0aGUgYXBwcm9wcmlhdGUgcGFydHMgb2YgdGhlIEdlbmVyYWwgUHVibGljIExpY2Vuc2UuIE9mIGNvdXJzZSwgeW91ciBwcm9ncmFtJ3MgY29tbWFuZHMgbWlnaHQgYmUgZGlmZmVyZW50OyBmb3IgYSBHVUkgaW50ZXJmYWNlLCB5b3Ugd291bGQgdXNlIGFuIOKAnGFib3V0IGJveOKAnS4KCllvdSBzaG91bGQgYWxzbyBnZXQgeW91ciBlbXBsb3llciAoaWYgeW91IHdvcmsgYXMgYSBwcm9ncmFtbWVyKSBvciBzY2hvb2wsIGlmIGFueSwgdG8gc2lnbiBhIOKAnGNvcHlyaWdodCBkaXNjbGFpbWVy4oCdIGZvciB0aGUgcHJvZ3JhbSwgaWYgbmVjZXNzYXJ5LiBGb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiB0aGlzLCBhbmQgaG93IHRvIGFwcGx5IGFuZCBmb2xsb3cgdGhlIEdOVSBHUEwsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uCgpUaGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZG9lcyBub3QgcGVybWl0IGluY29ycG9yYXRpbmcgeW91ciBwcm9ncmFtIGludG8gcHJvcHJpZXRhcnkgcHJvZ3JhbXMuIElmIHlvdXIgcHJvZ3JhbSBpcyBhIHN1YnJvdXRpbmUgbGlicmFyeSwgeW91IG1heSBjb25zaWRlciBpdCBtb3JlIHVzZWZ1bCB0byBwZXJtaXQgbGlua2luZyBwcm9wcmlldGFyeSBhcHBsaWNhdGlvbnMgd2l0aCB0aGUgbGlicmFyeS4gSWYgdGhpcyBpcyB3aGF0IHlvdSB3YW50IHRvIGRvLCB1c2UgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBpbnN0ZWFkIG9mIHRoaXMgTGljZW5zZS4gQnV0IGZpcnN0LCBwbGVhc2UgcmVhZCA8aHR0cDovL3d3dy5nbnUub3JnL3BoaWxvc29waHkvd2h5LW5vdC1sZ3BsLmh0bWw+Lg=="},"url":"https:\/\/www.gnu.org\/licenses\/gpl-3.0-standalone.html"}}],"version":"tevent-0.9.34","purl":"pkg:github\/samba-team\/samba@0.9.34","supplier":{"name":"samba-team"},"bom-ref":"samba_tevent-0.9.34_9b6248f7-c57d-4abe-bd98-ba98fae7cfc8","description":"","copyright":"","properties":[{"name":"component_id","value":"16"}]},{"name":"libxml2","type":"library","licenses":[{"license":{"id":"MIT","text":{"contentType":"text\/plain","encoding":"base64","content":"TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgPHllYXI+IDxjb3B5cmlnaHQgaG9sZGVycz4KClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUu"},"url":"https:\/\/opensource.org\/licenses\/MIT"}}],"version":"2.9.2-rc1","cpe":"cpe:2.3:a:xmlsoft:libxml2:2.9.2:rc1:*:*:*:*:*:*","purl":"pkg:github\/GNOME\/libxml2@2.9.2-rc1","supplier":{"name":"gnome"},"bom-ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428","description":"","copyright":"","properties":[{"name":"component_id","value":"12"}]},{"name":"blaze-material-ui","type":"library","licenses":[{"license":{"id":"MIT","text":{"contentType":"text\/plain","encoding":"base64","content":"TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgPHllYXI+IDxjb3B5cmlnaHQgaG9sZGVycz4KClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUu"},"url":"https:\/\/opensource.org\/licenses\/MIT"}}],"version":"0.1.9","purl":"pkg:github\/codesignal\/blaze-material-ui@0.1.9","supplier":{"name":"codesignal"},"bom-ref":"blaze-material-ui_0.1.9_685e4cdf-3ec0-40b8-b40a-d46b1ff36d98","description":"","copyright":"","properties":[{"name":"component_id","value":"12140"}]},{"name":"9082892","type":"library","licenses":[{"license":{"id":"CC-BY-SA-3.0","text":{"contentType":"text\/plain","encoding":"base64","content":"Q3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1TaGFyZUFsaWtlIDMuMCBVbnBvcnRlZAoKIENSRUFUSVZFIENPTU1PTlMgQ09SUE9SQVRJT04gSVMgTk9UIEEgTEFXIEZJUk0gQU5EIERPRVMgTk9UIFBST1ZJREUgTEVHQUwgU0VSVklDRVMuIERJU1RSSUJVVElPTiBPRiBUSElTIExJQ0VOU0UgRE9FUyBOT1QgQ1JFQVRFIEFOIEFUVE9STkVZLUNMSUVOVCBSRUxBVElPTlNISVAuIENSRUFUSVZFIENPTU1PTlMgUFJPVklERVMgVEhJUyBJTkZPUk1BVElPTiBPTiBBTiAiQVMtSVMiIEJBU0lTLiBDUkVBVElWRSBDT01NT05TIE1BS0VTIE5PIFdBUlJBTlRJRVMgUkVHQVJESU5HIFRIRSBJTkZPUk1BVElPTiBQUk9WSURFRCwgQU5EIERJU0NMQUlNUyBMSUFCSUxJVFkgRk9SIERBTUFHRVMgUkVTVUxUSU5HIEZST00gSVRTIFVTRS4KCkxpY2Vuc2UKClRIRSBXT1JLIChBUyBERUZJTkVEIEJFTE9XKSBJUyBQUk9WSURFRCBVTkRFUiBUSEUgVEVSTVMgT0YgVEhJUyBDUkVBVElWRSBDT01NT05TIFBVQkxJQyBMSUNFTlNFICgiQ0NQTCIgT1IgIkxJQ0VOU0UiKS4gVEhFIFdPUksgSVMgUFJPVEVDVEVEIEJZIENPUFlSSUdIVCBBTkQvT1IgT1RIRVIgQVBQTElDQUJMRSBMQVcuIEFOWSBVU0UgT0YgVEhFIFdPUksgT1RIRVIgVEhBTiBBUyBBVVRIT1JJWkVEIFVOREVSIFRISVMgTElDRU5TRSBPUiBDT1BZUklHSFQgTEFXIElTIFBST0hJQklURUQuCgpCWSBFWEVSQ0lTSU5HIEFOWSBSSUdIVFMgVE8gVEhFIFdPUksgUFJPVklERUQgSEVSRSwgWU9VIEFDQ0VQVCBBTkQgQUdSRUUgVE8gQkUgQk9VTkQgQlkgVEhFIFRFUk1TIE9GIFRISVMgTElDRU5TRS4gVE8gVEhFIEVYVEVOVCBUSElTIExJQ0VOU0UgTUFZIEJFIENPTlNJREVSRUQgVE8gQkUgQSBDT05UUkFDVCwgVEhFIExJQ0VOU09SIEdSQU5UUyBZT1UgVEhFIFJJR0hUUyBDT05UQUlORUQgSEVSRSBJTiBDT05TSURFUkFUSU9OIE9GIFlPVVIgQUNDRVBUQU5DRSBPRiBTVUNIIFRFUk1TIEFORCBDT05ESVRJT05TLgoKMS4gRGVmaW5pdGlvbnMKCiAgICAgYS4gIkFkYXB0YXRpb24iIG1lYW5zIGEgd29yayBiYXNlZCB1cG9uIHRoZSBXb3JrLCBvciB1cG9uIHRoZSBXb3JrIGFuZCBvdGhlciBwcmUtZXhpc3Rpbmcgd29ya3MsIHN1Y2ggYXMgYSB0cmFuc2xhdGlvbiwgYWRhcHRhdGlvbiwgZGVyaXZhdGl2ZSB3b3JrLCBhcnJhbmdlbWVudCBvZiBtdXNpYyBvciBvdGhlciBhbHRlcmF0aW9ucyBvZiBhIGxpdGVyYXJ5IG9yIGFydGlzdGljIHdvcmssIG9yIHBob25vZ3JhbSBvciBwZXJmb3JtYW5jZSBhbmQgaW5jbHVkZXMgY2luZW1hdG9ncmFwaGljIGFkYXB0YXRpb25zIG9yIGFueSBvdGhlciBmb3JtIGluIHdoaWNoIHRoZSBXb3JrIG1heSBiZSByZWNhc3QsIHRyYW5zZm9ybWVkLCBvciBhZGFwdGVkIGluY2x1ZGluZyBpbiBhbnkgZm9ybSByZWNvZ25pemFibHkgZGVyaXZlZCBmcm9tIHRoZSBvcmlnaW5hbCwgZXhjZXB0IHRoYXQgYSB3b3JrIHRoYXQgY29uc3RpdHV0ZXMgYSBDb2xsZWN0aW9uIHdpbGwgbm90IGJlIGNvbnNpZGVyZWQgYW4gQWRhcHRhdGlvbiBmb3IgdGhlIHB1cnBvc2Ugb2YgdGhpcyBMaWNlbnNlLiBGb3IgdGhlIGF2b2lkYW5jZSBvZiBkb3VidCwgd2hlcmUgdGhlIFdvcmsgaXMgYSBtdXNpY2FsIHdvcmssIHBlcmZvcm1hbmNlIG9yIHBob25vZ3JhbSwgdGhlIHN5bmNocm9uaXphdGlvbiBvZiB0aGUgV29yayBpbiB0aW1lZC1yZWxhdGlvbiB3aXRoIGEgbW92aW5nIGltYWdlICgic3luY2hpbmciKSB3aWxsIGJlIGNvbnNpZGVyZWQgYW4gQWRhcHRhdGlvbiBmb3IgdGhlIHB1cnBvc2Ugb2YgdGhpcyBMaWNlbnNlLgoKICAgICBiLiAiQ29sbGVjdGlvbiIgbWVhbnMgYSBjb2xsZWN0aW9uIG9mIGxpdGVyYXJ5IG9yIGFydGlzdGljIHdvcmtzLCBzdWNoIGFzIGVuY3ljbG9wZWRpYXMgYW5kIGFudGhvbG9naWVzLCBvciBwZXJmb3JtYW5jZXMsIHBob25vZ3JhbXMgb3IgYnJvYWRjYXN0cywgb3Igb3RoZXIgd29ya3Mgb3Igc3ViamVjdCBtYXR0ZXIgb3RoZXIgdGhhbiB3b3JrcyBsaXN0ZWQgaW4gU2VjdGlvbiAxKGYpIGJlbG93LCB3aGljaCwgYnkgcmVhc29uIG9mIHRoZSBzZWxlY3Rpb24gYW5kIGFycmFuZ2VtZW50IG9mIHRoZWlyIGNvbnRlbnRzLCBjb25zdGl0dXRlIGludGVsbGVjdHVhbCBjcmVhdGlvbnMsIGluIHdoaWNoIHRoZSBXb3JrIGlzIGluY2x1ZGVkIGluIGl0cyBlbnRpcmV0eSBpbiB1bm1vZGlmaWVkIGZvcm0gYWxvbmcgd2l0aCBvbmUgb3IgbW9yZSBvdGhlciBjb250cmlidXRpb25zLCBlYWNoIGNvbnN0aXR1dGluZyBzZXBhcmF0ZSBhbmQgaW5kZXBlbmRlbnQgd29ya3MgaW4gdGhlbXNlbHZlcywgd2hpY2ggdG9nZXRoZXIgYXJlIGFzc2VtYmxlZCBpbnRvIGEgY29sbGVjdGl2ZSB3aG9sZS4gQSB3b3JrIHRoYXQgY29uc3RpdHV0ZXMgYSBDb2xsZWN0aW9uIHdpbGwgbm90IGJlIGNvbnNpZGVyZWQgYW4gQWRhcHRhdGlvbiAoYXMgZGVmaW5lZCBiZWxvdykgZm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIExpY2Vuc2UuCgogICAgIGMuICJDcmVhdGl2ZSBDb21tb25zIENvbXBhdGlibGUgTGljZW5zZSIgbWVhbnMgYSBsaWNlbnNlIHRoYXQgaXMgbGlzdGVkIGF0IGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2NvbXBhdGlibGVsaWNlbnNlcyB0aGF0IGhhcyBiZWVuIGFwcHJvdmVkIGJ5IENyZWF0aXZlIENvbW1vbnMgYXMgYmVpbmcgZXNzZW50aWFsbHkgZXF1aXZhbGVudCB0byB0aGlzIExpY2Vuc2UsIGluY2x1ZGluZywgYXQgYSBtaW5pbXVtLCBiZWNhdXNlIHRoYXQgbGljZW5zZTogKGkpIGNvbnRhaW5zIHRlcm1zIHRoYXQgaGF2ZSB0aGUgc2FtZSBwdXJwb3NlLCBtZWFuaW5nIGFuZCBlZmZlY3QgYXMgdGhlIExpY2Vuc2UgRWxlbWVudHMgb2YgdGhpcyBMaWNlbnNlOyBhbmQsIChpaSkgZXhwbGljaXRseSBwZXJtaXRzIHRoZSByZWxpY2Vuc2luZyBvZiBhZGFwdGF0aW9ucyBvZiB3b3JrcyBtYWRlIGF2YWlsYWJsZSB1bmRlciB0aGF0IGxpY2Vuc2UgdW5kZXIgdGhpcyBMaWNlbnNlIG9yIGEgQ3JlYXRpdmUgQ29tbW9ucyBqdXJpc2RpY3Rpb24gbGljZW5zZSB3aXRoIHRoZSBzYW1lIExpY2Vuc2UgRWxlbWVudHMgYXMgdGhpcyBMaWNlbnNlLgoKICAgICBkLiAiRGlzdHJpYnV0ZSIgbWVhbnMgdG8gbWFrZSBhdmFpbGFibGUgdG8gdGhlIHB1YmxpYyB0aGUgb3JpZ2luYWwgYW5kIGNvcGllcyBvZiB0aGUgV29yayBvciBBZGFwdGF0aW9uLCBhcyBhcHByb3ByaWF0ZSwgdGhyb3VnaCBzYWxlIG9yIG90aGVyIHRyYW5zZmVyIG9mIG93bmVyc2hpcC4KCiAgICAgZS4gIkxpY2Vuc2UgRWxlbWVudHMiIG1lYW5zIHRoZSBmb2xsb3dpbmcgaGlnaC1sZXZlbCBsaWNlbnNlIGF0dHJpYnV0ZXMgYXMgc2VsZWN0ZWQgYnkgTGljZW5zb3IgYW5kIGluZGljYXRlZCBpbiB0aGUgdGl0bGUgb2YgdGhpcyBMaWNlbnNlOiBBdHRyaWJ1dGlvbiwgU2hhcmVBbGlrZS4KCiAgICAgZi4gIkxpY2Vuc29yIiBtZWFucyB0aGUgaW5kaXZpZHVhbCwgaW5kaXZpZHVhbHMsIGVudGl0eSBvciBlbnRpdGllcyB0aGF0IG9mZmVyKHMpIHRoZSBXb3JrIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGlzIExpY2Vuc2UuCgogICAgIGcuICJPcmlnaW5hbCBBdXRob3IiIG1lYW5zLCBpbiB0aGUgY2FzZSBvZiBhIGxpdGVyYXJ5IG9yIGFydGlzdGljIHdvcmssIHRoZSBpbmRpdmlkdWFsLCBpbmRpdmlkdWFscywgZW50aXR5IG9yIGVudGl0aWVzIHdobyBjcmVhdGVkIHRoZSBXb3JrIG9yIGlmIG5vIGluZGl2aWR1YWwgb3IgZW50aXR5IGNhbiBiZSBpZGVudGlmaWVkLCB0aGUgcHVibGlzaGVyOyBhbmQgaW4gYWRkaXRpb24gKGkpIGluIHRoZSBjYXNlIG9mIGEgcGVyZm9ybWFuY2UgdGhlIGFjdG9ycywgc2luZ2VycywgbXVzaWNpYW5zLCBkYW5jZXJzLCBhbmQgb3RoZXIgcGVyc29ucyB3aG8gYWN0LCBzaW5nLCBkZWxpdmVyLCBkZWNsYWltLCBwbGF5IGluLCBpbnRlcnByZXQgb3Igb3RoZXJ3aXNlIHBlcmZvcm0gbGl0ZXJhcnkgb3IgYXJ0aXN0aWMgd29ya3Mgb3IgZXhwcmVzc2lvbnMgb2YgZm9sa2xvcmU7IChpaSkgaW4gdGhlIGNhc2Ugb2YgYSBwaG9ub2dyYW0gdGhlIHByb2R1Y2VyIGJlaW5nIHRoZSBwZXJzb24gb3IgbGVnYWwgZW50aXR5IHdobyBmaXJzdCBmaXhlcyB0aGUgc291bmRzIG9mIGEgcGVyZm9ybWFuY2Ugb3Igb3RoZXIgc291bmRzOyBhbmQsIChpaWkpIGluIHRoZSBjYXNlIG9mIGJyb2FkY2FzdHMsIHRoZSBvcmdhbml6YXRpb24gdGhhdCB0cmFuc21pdHMgdGhlIGJyb2FkY2FzdC4KCiAgICAgaC4gIldvcmsiIG1lYW5zIHRoZSBsaXRlcmFyeSBhbmQvb3IgYXJ0aXN0aWMgd29yayBvZmZlcmVkIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGlzIExpY2Vuc2UgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiBhbnkgcHJvZHVjdGlvbiBpbiB0aGUgbGl0ZXJhcnksIHNjaWVudGlmaWMgYW5kIGFydGlzdGljIGRvbWFpbiwgd2hhdGV2ZXIgbWF5IGJlIHRoZSBtb2RlIG9yIGZvcm0gb2YgaXRzIGV4cHJlc3Npb24gaW5jbHVkaW5nIGRpZ2l0YWwgZm9ybSwgc3VjaCBhcyBhIGJvb2ssIHBhbXBobGV0IGFuZCBvdGhlciB3cml0aW5nOyBhIGxlY3R1cmUsIGFkZHJlc3MsIHNlcm1vbiBvciBvdGhlciB3b3JrIG9mIHRoZSBzYW1lIG5hdHVyZTsgYSBkcmFtYXRpYyBvciBkcmFtYXRpY28tbXVzaWNhbCB3b3JrOyBhIGNob3Jlb2dyYXBoaWMgd29yayBvciBlbnRlcnRhaW5tZW50IGluIGR1bWIgc2hvdzsgYSBtdXNpY2FsIGNvbXBvc2l0aW9uIHdpdGggb3Igd2l0aG91dCB3b3JkczsgYSBjaW5lbWF0b2dyYXBoaWMgd29yayB0byB3aGljaCBhcmUgYXNzaW1pbGF0ZWQgd29ya3MgZXhwcmVzc2VkIGJ5IGEgcHJvY2VzcyBhbmFsb2dvdXMgdG8gY2luZW1hdG9ncmFwaHk7IGEgd29yayBvZiBkcmF3aW5nLCBwYWludGluZywgYXJjaGl0ZWN0dXJlLCBzY3VscHR1cmUsIGVuZ3JhdmluZyBvciBsaXRob2dyYXBoeTsgYSBwaG90b2dyYXBoaWMgd29yayB0byB3aGljaCBhcmUgYXNzaW1pbGF0ZWQgd29ya3MgZXhwcmVzc2VkIGJ5IGEgcHJvY2VzcyBhbmFsb2dvdXMgdG8gcGhvdG9ncmFwaHk7IGEgd29yayBvZiBhcHBsaWVkIGFydDsgYW4gaWxsdXN0cmF0aW9uLCBtYXAsIHBsYW4sIHNrZXRjaCBvciB0aHJlZS1kaW1lbnNpb25hbCB3b3JrIHJlbGF0aXZlIHRvIGdlb2dyYXBoeSwgdG9wb2dyYXBoeSwgYXJjaGl0ZWN0dXJlIG9yIHNjaWVuY2U7IGEgcGVyZm9ybWFuY2U7IGEgYnJvYWRjYXN0OyBhIHBob25vZ3JhbTsgYSBjb21waWxhdGlvbiBvZiBkYXRhIHRvIHRoZSBleHRlbnQgaXQgaXMgcHJvdGVjdGVkIGFzIGEgY29weXJpZ2h0YWJsZSB3b3JrOyBvciBhIHdvcmsgcGVyZm9ybWVkIGJ5IGEgdmFyaWV0eSBvciBjaXJjdXMgcGVyZm9ybWVyIHRvIHRoZSBleHRlbnQgaXQgaXMgbm90IG90aGVyd2lzZSBjb25zaWRlcmVkIGEgbGl0ZXJhcnkgb3IgYXJ0aXN0aWMgd29yay4KCiAgICAgaS4gIllvdSIgbWVhbnMgYW4gaW5kaXZpZHVhbCBvciBlbnRpdHkgZXhlcmNpc2luZyByaWdodHMgdW5kZXIgdGhpcyBMaWNlbnNlIHdobyBoYXMgbm90IHByZXZpb3VzbHkgdmlvbGF0ZWQgdGhlIHRlcm1zIG9mIHRoaXMgTGljZW5zZSB3aXRoIHJlc3BlY3QgdG8gdGhlIFdvcmssIG9yIHdobyBoYXMgcmVjZWl2ZWQgZXhwcmVzcyBwZXJtaXNzaW9uIGZyb20gdGhlIExpY2Vuc29yIHRvIGV4ZXJjaXNlIHJpZ2h0cyB1bmRlciB0aGlzIExpY2Vuc2UgZGVzcGl0ZSBhIHByZXZpb3VzIHZpb2xhdGlvbi4KCiAgICAgai4gIlB1YmxpY2x5IFBlcmZvcm0iIG1lYW5zIHRvIHBlcmZvcm0gcHVibGljIHJlY2l0YXRpb25zIG9mIHRoZSBXb3JrIGFuZCB0byBjb21tdW5pY2F0ZSB0byB0aGUgcHVibGljIHRob3NlIHB1YmxpYyByZWNpdGF0aW9ucywgYnkgYW55IG1lYW5zIG9yIHByb2Nlc3MsIGluY2x1ZGluZyBieSB3aXJlIG9yIHdpcmVsZXNzIG1lYW5zIG9yIHB1YmxpYyBkaWdpdGFsIHBlcmZvcm1hbmNlczsgdG8gbWFrZSBhdmFpbGFibGUgdG8gdGhlIHB1YmxpYyBXb3JrcyBpbiBzdWNoIGEgd2F5IHRoYXQgbWVtYmVycyBvZiB0aGUgcHVibGljIG1heSBhY2Nlc3MgdGhlc2UgV29ya3MgZnJvbSBhIHBsYWNlIGFuZCBhdCBhIHBsYWNlIGluZGl2aWR1YWxseSBjaG9zZW4gYnkgdGhlbTsgdG8gcGVyZm9ybSB0aGUgV29yayB0byB0aGUgcHVibGljIGJ5IGFueSBtZWFucyBvciBwcm9jZXNzIGFuZCB0aGUgY29tbXVuaWNhdGlvbiB0byB0aGUgcHVibGljIG9mIHRoZSBwZXJmb3JtYW5jZXMgb2YgdGhlIFdvcmssIGluY2x1ZGluZyBieSBwdWJsaWMgZGlnaXRhbCBwZXJmb3JtYW5jZTsgdG8gYnJvYWRjYXN0IGFuZCByZWJyb2FkY2FzdCB0aGUgV29yayBieSBhbnkgbWVhbnMgaW5jbHVkaW5nIHNpZ25zLCBzb3VuZHMgb3IgaW1hZ2VzLgoKICAgICBrLiAiUmVwcm9kdWNlIiBtZWFucyB0byBtYWtlIGNvcGllcyBvZiB0aGUgV29yayBieSBhbnkgbWVhbnMgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiBieSBzb3VuZCBvciB2aXN1YWwgcmVjb3JkaW5ncyBhbmQgdGhlIHJpZ2h0IG9mIGZpeGF0aW9uIGFuZCByZXByb2R1Y2luZyBmaXhhdGlvbnMgb2YgdGhlIFdvcmssIGluY2x1ZGluZyBzdG9yYWdlIG9mIGEgcHJvdGVjdGVkIHBlcmZvcm1hbmNlIG9yIHBob25vZ3JhbSBpbiBkaWdpdGFsIGZvcm0gb3Igb3RoZXIgZWxlY3Ryb25pYyBtZWRpdW0uCgoyLiBGYWlyIERlYWxpbmcgUmlnaHRzLiBOb3RoaW5nIGluIHRoaXMgTGljZW5zZSBpcyBpbnRlbmRlZCB0byByZWR1Y2UsIGxpbWl0LCBvciByZXN0cmljdCBhbnkgdXNlcyBmcmVlIGZyb20gY29weXJpZ2h0IG9yIHJpZ2h0cyBhcmlzaW5nIGZyb20gbGltaXRhdGlvbnMgb3IgZXhjZXB0aW9ucyB0aGF0IGFyZSBwcm92aWRlZCBmb3IgaW4gY29ubmVjdGlvbiB3aXRoIHRoZSBjb3B5cmlnaHQgcHJvdGVjdGlvbiB1bmRlciBjb3B5cmlnaHQgbGF3IG9yIG90aGVyIGFwcGxpY2FibGUgbGF3cy4KCjMuIExpY2Vuc2UgR3JhbnQuIFN1YmplY3QgdG8gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHRoaXMgTGljZW5zZSwgTGljZW5zb3IgaGVyZWJ5IGdyYW50cyBZb3UgYSB3b3JsZHdpZGUsIHJveWFsdHktZnJlZSwgbm9uLWV4Y2x1c2l2ZSwgcGVycGV0dWFsIChmb3IgdGhlIGR1cmF0aW9uIG9mIHRoZSBhcHBsaWNhYmxlIGNvcHlyaWdodCkgbGljZW5zZSB0byBleGVyY2lzZSB0aGUgcmlnaHRzIGluIHRoZSBXb3JrIGFzIHN0YXRlZCBiZWxvdzoKCiAgICAgYS4gdG8gUmVwcm9kdWNlIHRoZSBXb3JrLCB0byBpbmNvcnBvcmF0ZSB0aGUgV29yayBpbnRvIG9uZSBvciBtb3JlIENvbGxlY3Rpb25zLCBhbmQgdG8gUmVwcm9kdWNlIHRoZSBXb3JrIGFzIGluY29ycG9yYXRlZCBpbiB0aGUgQ29sbGVjdGlvbnM7CgogICAgIGIuIHRvIGNyZWF0ZSBhbmQgUmVwcm9kdWNlIEFkYXB0YXRpb25zIHByb3ZpZGVkIHRoYXQgYW55IHN1Y2ggQWRhcHRhdGlvbiwgaW5jbHVkaW5nIGFueSB0cmFuc2xhdGlvbiBpbiBhbnkgbWVkaXVtLCB0YWtlcyByZWFzb25hYmxlIHN0ZXBzIHRvIGNsZWFybHkgbGFiZWwsIGRlbWFyY2F0ZSBvciBvdGhlcndpc2UgaWRlbnRpZnkgdGhhdCBjaGFuZ2VzIHdlcmUgbWFkZSB0byB0aGUgb3JpZ2luYWwgV29yay4gRm9yIGV4YW1wbGUsIGEgdHJhbnNsYXRpb24gY291bGQgYmUgbWFya2VkICJUaGUgb3JpZ2luYWwgd29yayB3YXMgdHJhbnNsYXRlZCBmcm9tIEVuZ2xpc2ggdG8gU3BhbmlzaCwiIG9yIGEgbW9kaWZpY2F0aW9uIGNvdWxkIGluZGljYXRlICJUaGUgb3JpZ2luYWwgd29yayBoYXMgYmVlbiBtb2RpZmllZC4iOwoKICAgICBjLiB0byBEaXN0cmlidXRlIGFuZCBQdWJsaWNseSBQZXJmb3JtIHRoZSBXb3JrIGluY2x1ZGluZyBhcyBpbmNvcnBvcmF0ZWQgaW4gQ29sbGVjdGlvbnM7IGFuZCwKCiAgICAgZC4gdG8gRGlzdHJpYnV0ZSBhbmQgUHVibGljbHkgUGVyZm9ybSBBZGFwdGF0aW9ucy4KCiAgICAgZS4gRm9yIHRoZSBhdm9pZGFuY2Ugb2YgZG91YnQ6CgogICAgICAgICAgaS4gTm9uLXdhaXZhYmxlIENvbXB1bHNvcnkgTGljZW5zZSBTY2hlbWVzLiBJbiB0aG9zZSBqdXJpc2RpY3Rpb25zIGluIHdoaWNoIHRoZSByaWdodCB0byBjb2xsZWN0IHJveWFsdGllcyB0aHJvdWdoIGFueSBzdGF0dXRvcnkgb3IgY29tcHVsc29yeSBsaWNlbnNpbmcgc2NoZW1lIGNhbm5vdCBiZSB3YWl2ZWQsIHRoZSBMaWNlbnNvciByZXNlcnZlcyB0aGUgZXhjbHVzaXZlIHJpZ2h0IHRvIGNvbGxlY3Qgc3VjaCByb3lhbHRpZXMgZm9yIGFueSBleGVyY2lzZSBieSBZb3Ugb2YgdGhlIHJpZ2h0cyBncmFudGVkIHVuZGVyIHRoaXMgTGljZW5zZTsKCiAgICAgICAgICBpaS4gV2FpdmFibGUgQ29tcHVsc29yeSBMaWNlbnNlIFNjaGVtZXMuIEluIHRob3NlIGp1cmlzZGljdGlvbnMgaW4gd2hpY2ggdGhlIHJpZ2h0IHRvIGNvbGxlY3Qgcm95YWx0aWVzIHRocm91Z2ggYW55IHN0YXR1dG9yeSBvciBjb21wdWxzb3J5IGxpY2Vuc2luZyBzY2hlbWUgY2FuIGJlIHdhaXZlZCwgdGhlIExpY2Vuc29yIHdhaXZlcyB0aGUgZXhjbHVzaXZlIHJpZ2h0IHRvIGNvbGxlY3Qgc3VjaCByb3lhbHRpZXMgZm9yIGFueSBleGVyY2lzZSBieSBZb3Ugb2YgdGhlIHJpZ2h0cyBncmFudGVkIHVuZGVyIHRoaXMgTGljZW5zZTsgYW5kLAoKICAgICAgICAgIGlpaS4gVm9sdW50YXJ5IExpY2Vuc2UgU2NoZW1lcy4gVGhlIExpY2Vuc29yIHdhaXZlcyB0aGUgcmlnaHQgdG8gY29sbGVjdCByb3lhbHRpZXMsIHdoZXRoZXIgaW5kaXZpZHVhbGx5IG9yLCBpbiB0aGUgZXZlbnQgdGhhdCB0aGUgTGljZW5zb3IgaXMgYSBtZW1iZXIgb2YgYSBjb2xsZWN0aW5nIHNvY2lldHkgdGhhdCBhZG1pbmlzdGVycyB2b2x1bnRhcnkgbGljZW5zaW5nIHNjaGVtZXMsIHZpYSB0aGF0IHNvY2lldHksIGZyb20gYW55IGV4ZXJjaXNlIGJ5IFlvdSBvZiB0aGUgcmlnaHRzIGdyYW50ZWQgdW5kZXIgdGhpcyBMaWNlbnNlLgoKVGhlIGFib3ZlIHJpZ2h0cyBtYXkgYmUgZXhlcmNpc2VkIGluIGFsbCBtZWRpYSBhbmQgZm9ybWF0cyB3aGV0aGVyIG5vdyBrbm93biBvciBoZXJlYWZ0ZXIgZGV2aXNlZC4gVGhlIGFib3ZlIHJpZ2h0cyBpbmNsdWRlIHRoZSByaWdodCB0byBtYWtlIHN1Y2ggbW9kaWZpY2F0aW9ucyBhcyBhcmUgdGVjaG5pY2FsbHkgbmVjZXNzYXJ5IHRvIGV4ZXJjaXNlIHRoZSByaWdodHMgaW4gb3RoZXIgbWVkaWEgYW5kIGZvcm1hdHMuIFN1YmplY3QgdG8gU2VjdGlvbiA4KGYpLCBhbGwgcmlnaHRzIG5vdCBleHByZXNzbHkgZ3JhbnRlZCBieSBMaWNlbnNvciBhcmUgaGVyZWJ5IHJlc2VydmVkLgoKNC4gUmVzdHJpY3Rpb25zLiBUaGUgbGljZW5zZSBncmFudGVkIGluIFNlY3Rpb24gMyBhYm92ZSBpcyBleHByZXNzbHkgbWFkZSBzdWJqZWN0IHRvIGFuZCBsaW1pdGVkIGJ5IHRoZSBmb2xsb3dpbmcgcmVzdHJpY3Rpb25zOgoKICAgICBhLiBZb3UgbWF5IERpc3RyaWJ1dGUgb3IgUHVibGljbHkgUGVyZm9ybSB0aGUgV29yayBvbmx5IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGlzIExpY2Vuc2UuIFlvdSBtdXN0IGluY2x1ZGUgYSBjb3B5IG9mLCBvciB0aGUgVW5pZm9ybSBSZXNvdXJjZSBJZGVudGlmaWVyIChVUkkpIGZvciwgdGhpcyBMaWNlbnNlIHdpdGggZXZlcnkgY29weSBvZiB0aGUgV29yayBZb3UgRGlzdHJpYnV0ZSBvciBQdWJsaWNseSBQZXJmb3JtLiBZb3UgbWF5IG5vdCBvZmZlciBvciBpbXBvc2UgYW55IHRlcm1zIG9uIHRoZSBXb3JrIHRoYXQgcmVzdHJpY3QgdGhlIHRlcm1zIG9mIHRoaXMgTGljZW5zZSBvciB0aGUgYWJpbGl0eSBvZiB0aGUgcmVjaXBpZW50IG9mIHRoZSBXb3JrIHRvIGV4ZXJjaXNlIHRoZSByaWdodHMgZ3JhbnRlZCB0byB0aGF0IHJlY2lwaWVudCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIExpY2Vuc2UuIFlvdSBtYXkgbm90IHN1YmxpY2Vuc2UgdGhlIFdvcmsuIFlvdSBtdXN0IGtlZXAgaW50YWN0IGFsbCBub3RpY2VzIHRoYXQgcmVmZXIgdG8gdGhpcyBMaWNlbnNlIGFuZCB0byB0aGUgZGlzY2xhaW1lciBvZiB3YXJyYW50aWVzIHdpdGggZXZlcnkgY29weSBvZiB0aGUgV29yayBZb3UgRGlzdHJpYnV0ZSBvciBQdWJsaWNseSBQZXJmb3JtLiBXaGVuIFlvdSBEaXN0cmlidXRlIG9yIFB1YmxpY2x5IFBlcmZvcm0gdGhlIFdvcmssIFlvdSBtYXkgbm90IGltcG9zZSBhbnkgZWZmZWN0aXZlIHRlY2hub2xvZ2ljYWwgbWVhc3VyZXMgb24gdGhlIFdvcmsgdGhhdCByZXN0cmljdCB0aGUgYWJpbGl0eSBvZiBhIHJlY2lwaWVudCBvZiB0aGUgV29yayBmcm9tIFlvdSB0byBleGVyY2lzZSB0aGUgcmlnaHRzIGdyYW50ZWQgdG8gdGhhdCByZWNpcGllbnQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBMaWNlbnNlLiBUaGlzIFNlY3Rpb24gNChhKSBhcHBsaWVzIHRvIHRoZSBXb3JrIGFzIGluY29ycG9yYXRlZCBpbiBhIENvbGxlY3Rpb24sIGJ1dCB0aGlzIGRvZXMgbm90IHJlcXVpcmUgdGhlIENvbGxlY3Rpb24gYXBhcnQgZnJvbSB0aGUgV29yayBpdHNlbGYgdG8gYmUgbWFkZSBzdWJqZWN0IHRvIHRoZSB0ZXJtcyBvZiB0aGlzIExpY2Vuc2UuIElmIFlvdSBjcmVhdGUgYSBDb2xsZWN0aW9uLCB1cG9uIG5vdGljZSBmcm9tIGFueSBMaWNlbnNvciBZb3UgbXVzdCwgdG8gdGhlIGV4dGVudCBwcmFjdGljYWJsZSwgcmVtb3ZlIGZyb20gdGhlIENvbGxlY3Rpb24gYW55IGNyZWRpdCBhcyByZXF1aXJlZCBieSBTZWN0aW9uIDQoYyksIGFzIHJlcXVlc3RlZC4gSWYgWW91IGNyZWF0ZSBhbiBBZGFwdGF0aW9uLCB1cG9uIG5vdGljZSBmcm9tIGFueSBMaWNlbnNvciBZb3UgbXVzdCwgdG8gdGhlIGV4dGVudCBwcmFjdGljYWJsZSwgcmVtb3ZlIGZyb20gdGhlIEFkYXB0YXRpb24gYW55IGNyZWRpdCBhcyByZXF1aXJlZCBieSBTZWN0aW9uIDQoYyksIGFzIHJlcXVlc3RlZC4KCiAgICAgYi4gWW91IG1heSBEaXN0cmlidXRlIG9yIFB1YmxpY2x5IFBlcmZvcm0gYW4gQWRhcHRhdGlvbiBvbmx5IHVuZGVyIHRoZSB0ZXJtcyBvZjogKGkpIHRoaXMgTGljZW5zZTsgKGlpKSBhIGxhdGVyIHZlcnNpb24gb2YgdGhpcyBMaWNlbnNlIHdpdGggdGhlIHNhbWUgTGljZW5zZSBFbGVtZW50cyBhcyB0aGlzIExpY2Vuc2U7IChpaWkpIGEgQ3JlYXRpdmUgQ29tbW9ucyBqdXJpc2RpY3Rpb24gbGljZW5zZSAoZWl0aGVyIHRoaXMgb3IgYSBsYXRlciBsaWNlbnNlIHZlcnNpb24pIHRoYXQgY29udGFpbnMgdGhlIHNhbWUgTGljZW5zZSBFbGVtZW50cyBhcyB0aGlzIExpY2Vuc2UgKGUuZy4sIEF0dHJpYnV0aW9uLVNoYXJlQWxpa2UgMy4wIFVTKSk7IChpdikgYSBDcmVhdGl2ZSBDb21tb25zIENvbXBhdGlibGUgTGljZW5zZS4gSWYgeW91IGxpY2Vuc2UgdGhlIEFkYXB0YXRpb24gdW5kZXIgb25lIG9mIHRoZSBsaWNlbnNlcyBtZW50aW9uZWQgaW4gKGl2KSwgeW91IG11c3QgY29tcGx5IHdpdGggdGhlIHRlcm1zIG9mIHRoYXQgbGljZW5zZS4gSWYgeW91IGxpY2Vuc2UgdGhlIEFkYXB0YXRpb24gdW5kZXIgdGhlIHRlcm1zIG9mIGFueSBvZiB0aGUgbGljZW5zZXMgbWVudGlvbmVkIGluIChpKSwgKGlpKSBvciAoaWlpKSAodGhlICJBcHBsaWNhYmxlIExpY2Vuc2UiKSwgeW91IG11c3QgY29tcGx5IHdpdGggdGhlIHRlcm1zIG9mIHRoZSBBcHBsaWNhYmxlIExpY2Vuc2UgZ2VuZXJhbGx5IGFuZCB0aGUgZm9sbG93aW5nIHByb3Zpc2lvbnM6IChJKSBZb3UgbXVzdCBpbmNsdWRlIGEgY29weSBvZiwgb3IgdGhlIFVSSSBmb3IsIHRoZSBBcHBsaWNhYmxlIExpY2Vuc2Ugd2l0aCBldmVyeSBjb3B5IG9mIGVhY2ggQWRhcHRhdGlvbiBZb3UgRGlzdHJpYnV0ZSBvciBQdWJsaWNseSBQZXJmb3JtOyAoSUkpIFlvdSBtYXkgbm90IG9mZmVyIG9yIGltcG9zZSBhbnkgdGVybXMgb24gdGhlIEFkYXB0YXRpb24gdGhhdCByZXN0cmljdCB0aGUgdGVybXMgb2YgdGhlIEFwcGxpY2FibGUgTGljZW5zZSBvciB0aGUgYWJpbGl0eSBvZiB0aGUgcmVjaXBpZW50IG9mIHRoZSBBZGFwdGF0aW9uIHRvIGV4ZXJjaXNlIHRoZSByaWdodHMgZ3JhbnRlZCB0byB0aGF0IHJlY2lwaWVudCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEFwcGxpY2FibGUgTGljZW5zZTsgKElJSSkgWW91IG11c3Qga2VlcCBpbnRhY3QgYWxsIG5vdGljZXMgdGhhdCByZWZlciB0byB0aGUgQXBwbGljYWJsZSBMaWNlbnNlIGFuZCB0byB0aGUgZGlzY2xhaW1lciBvZiB3YXJyYW50aWVzIHdpdGggZXZlcnkgY29weSBvZiB0aGUgV29yayBhcyBpbmNsdWRlZCBpbiB0aGUgQWRhcHRhdGlvbiBZb3UgRGlzdHJpYnV0ZSBvciBQdWJsaWNseSBQZXJmb3JtOyAoSVYpIHdoZW4gWW91IERpc3RyaWJ1dGUgb3IgUHVibGljbHkgUGVyZm9ybSB0aGUgQWRhcHRhdGlvbiwgWW91IG1heSBub3QgaW1wb3NlIGFueSBlZmZlY3RpdmUgdGVjaG5vbG9naWNhbCBtZWFzdXJlcyBvbiB0aGUgQWRhcHRhdGlvbiB0aGF0IHJlc3RyaWN0IHRoZSBhYmlsaXR5IG9mIGEgcmVjaXBpZW50IG9mIHRoZSBBZGFwdGF0aW9uIGZyb20gWW91IHRvIGV4ZXJjaXNlIHRoZSByaWdodHMgZ3JhbnRlZCB0byB0aGF0IHJlY2lwaWVudCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEFwcGxpY2FibGUgTGljZW5zZS4gVGhpcyBTZWN0aW9uIDQoYikgYXBwbGllcyB0byB0aGUgQWRhcHRhdGlvbiBhcyBpbmNvcnBvcmF0ZWQgaW4gYSBDb2xsZWN0aW9uLCBidXQgdGhpcyBkb2VzIG5vdCByZXF1aXJlIHRoZSBDb2xsZWN0aW9uIGFwYXJ0IGZyb20gdGhlIEFkYXB0YXRpb24gaXRzZWxmIHRvIGJlIG1hZGUgc3ViamVjdCB0byB0aGUgdGVybXMgb2YgdGhlIEFwcGxpY2FibGUgTGljZW5zZS4KCiAgICAgYy4gSWYgWW91IERpc3RyaWJ1dGUsIG9yIFB1YmxpY2x5IFBlcmZvcm0gdGhlIFdvcmsgb3IgYW55IEFkYXB0YXRpb25zIG9yIENvbGxlY3Rpb25zLCBZb3UgbXVzdCwgdW5sZXNzIGEgcmVxdWVzdCBoYXMgYmVlbiBtYWRlIHB1cnN1YW50IHRvIFNlY3Rpb24gNChhKSwga2VlcCBpbnRhY3QgYWxsIGNvcHlyaWdodCBub3RpY2VzIGZvciB0aGUgV29yayBhbmQgcHJvdmlkZSwgcmVhc29uYWJsZSB0byB0aGUgbWVkaXVtIG9yIG1lYW5zIFlvdSBhcmUgdXRpbGl6aW5nOiAoaSkgdGhlIG5hbWUgb2YgdGhlIE9yaWdpbmFsIEF1dGhvciAob3IgcHNldWRvbnltLCBpZiBhcHBsaWNhYmxlKSBpZiBzdXBwbGllZCwgYW5kL29yIGlmIHRoZSBPcmlnaW5hbCBBdXRob3IgYW5kL29yIExpY2Vuc29yIGRlc2lnbmF0ZSBhbm90aGVyIHBhcnR5IG9yIHBhcnRpZXMgKGUuZy4sIGEgc3BvbnNvciBpbnN0aXR1dGUsIHB1Ymxpc2hpbmcgZW50aXR5LCBqb3VybmFsKSBmb3IgYXR0cmlidXRpb24gKCJBdHRyaWJ1dGlvbiBQYXJ0aWVzIikgaW4gTGljZW5zb3IncyBjb3B5cmlnaHQgbm90aWNlLCB0ZXJtcyBvZiBzZXJ2aWNlIG9yIGJ5IG90aGVyIHJlYXNvbmFibGUgbWVhbnMsIHRoZSBuYW1lIG9mIHN1Y2ggcGFydHkgb3IgcGFydGllczsgKGlpKSB0aGUgdGl0bGUgb2YgdGhlIFdvcmsgaWYgc3VwcGxpZWQ7IChpaWkpIHRvIHRoZSBleHRlbnQgcmVhc29uYWJseSBwcmFjdGljYWJsZSwgdGhlIFVSSSwgaWYgYW55LCB0aGF0IExpY2Vuc29yIHNwZWNpZmllcyB0byBiZSBhc3NvY2lhdGVkIHdpdGggdGhlIFdvcmssIHVubGVzcyBzdWNoIFVSSSBkb2VzIG5vdCByZWZlciB0byB0aGUgY29weXJpZ2h0IG5vdGljZSBvciBsaWNlbnNpbmcgaW5mb3JtYXRpb24gZm9yIHRoZSBXb3JrOyBhbmQgKGl2KSAsIGNvbnNpc3RlbnQgd2l0aCBTc2VjdGlvbiAzKGIpLCBpbiB0aGUgY2FzZSBvZiBhbiBBZGFwdGF0aW9uLCBhIGNyZWRpdCBpZGVudGlmeWluZyB0aGUgdXNlIG9mIHRoZSBXb3JrIGluIHRoZSBBZGFwdGF0aW9uIChlLmcuLCAiRnJlbmNoIHRyYW5zbGF0aW9uIG9mIHRoZSBXb3JrIGJ5IE9yaWdpbmFsIEF1dGhvciwiIG9yICJTY3JlZW5wbGF5IGJhc2VkIG9uIG9yaWdpbmFsIFdvcmsgYnkgT3JpZ2luYWwgQXV0aG9yIikuIFRoZSBjcmVkaXQgcmVxdWlyZWQgYnkgdGhpcyBTZWN0aW9uIDQoYykgbWF5IGJlIGltcGxlbWVudGVkIGluIGFueSByZWFzb25hYmxlIG1hbm5lcjsgcHJvdmlkZWQsIGhvd2V2ZXIsIHRoYXQgaW4gdGhlIGNhc2Ugb2YgYSBBZGFwdGF0aW9uIG9yIENvbGxlY3Rpb24sIGF0IGEgbWluaW11bSBzdWNoIGNyZWRpdCB3aWxsIGFwcGVhciwgaWYgYSBjcmVkaXQgZm9yIGFsbCBjb250cmlidXRpbmcgYXV0aG9ycyBvZiB0aGUgQWRhcHRhdGlvbiBvciBDb2xsZWN0aW9uIGFwcGVhcnMsIHRoZW4gYXMgcGFydCBvZiB0aGVzZSBjcmVkaXRzIGFuZCBpbiBhIG1hbm5lciBhdCBsZWFzdCBhcyBwcm9taW5lbnQgYXMgdGhlIGNyZWRpdHMgZm9yIHRoZSBvdGhlciBjb250cmlidXRpbmcgYXV0aG9ycy4gRm9yIHRoZSBhdm9pZGFuY2Ugb2YgZG91YnQsIFlvdSBtYXkgb25seSB1c2UgdGhlIGNyZWRpdCByZXF1aXJlZCBieSB0aGlzIFNlY3Rpb24gZm9yIHRoZSBwdXJwb3NlIG9mIGF0dHJpYnV0aW9uIGluIHRoZSBtYW5uZXIgc2V0IG91dCBhYm92ZSBhbmQsIGJ5IGV4ZXJjaXNpbmcgWW91ciByaWdodHMgdW5kZXIgdGhpcyBMaWNlbnNlLCBZb3UgbWF5IG5vdCBpbXBsaWNpdGx5IG9yIGV4cGxpY2l0bHkgYXNzZXJ0IG9yIGltcGx5IGFueSBjb25uZWN0aW9uIHdpdGgsIHNwb25zb3JzaGlwIG9yIGVuZG9yc2VtZW50IGJ5IHRoZSBPcmlnaW5hbCBBdXRob3IsIExpY2Vuc29yIGFuZC9vciBBdHRyaWJ1dGlvbiBQYXJ0aWVzLCBhcyBhcHByb3ByaWF0ZSwgb2YgWW91IG9yIFlvdXIgdXNlIG9mIHRoZSBXb3JrLCB3aXRob3V0IHRoZSBzZXBhcmF0ZSwgZXhwcmVzcyBwcmlvciB3cml0dGVuIHBlcm1pc3Npb24gb2YgdGhlIE9yaWdpbmFsIEF1dGhvciwgTGljZW5zb3IgYW5kL29yIEF0dHJpYnV0aW9uIFBhcnRpZXMuCgogICAgIGQuIEV4Y2VwdCBhcyBvdGhlcndpc2UgYWdyZWVkIGluIHdyaXRpbmcgYnkgdGhlIExpY2Vuc29yIG9yIGFzIG1heSBiZSBvdGhlcndpc2UgcGVybWl0dGVkIGJ5IGFwcGxpY2FibGUgbGF3LCBpZiBZb3UgUmVwcm9kdWNlLCBEaXN0cmlidXRlIG9yIFB1YmxpY2x5IFBlcmZvcm0gdGhlIFdvcmsgZWl0aGVyIGJ5IGl0c2VsZiBvciBhcyBwYXJ0IG9mIGFueSBBZGFwdGF0aW9ucyBvciBDb2xsZWN0aW9ucywgWW91IG11c3Qgbm90IGRpc3RvcnQsIG11dGlsYXRlLCBtb2RpZnkgb3IgdGFrZSBvdGhlciBkZXJvZ2F0b3J5IGFjdGlvbiBpbiByZWxhdGlvbiB0byB0aGUgV29yayB3aGljaCB3b3VsZCBiZSBwcmVqdWRpY2lhbCB0byB0aGUgT3JpZ2luYWwgQXV0aG9yJ3MgaG9ub3Igb3IgcmVwdXRhdGlvbi4gTGljZW5zb3IgYWdyZWVzIHRoYXQgaW4gdGhvc2UganVyaXNkaWN0aW9ucyAoZS5nLiBKYXBhbiksIGluIHdoaWNoIGFueSBleGVyY2lzZSBvZiB0aGUgcmlnaHQgZ3JhbnRlZCBpbiBTZWN0aW9uIDMoYikgb2YgdGhpcyBMaWNlbnNlICh0aGUgcmlnaHQgdG8gbWFrZSBBZGFwdGF0aW9ucykgd291bGQgYmUgZGVlbWVkIHRvIGJlIGEgZGlzdG9ydGlvbiwgbXV0aWxhdGlvbiwgbW9kaWZpY2F0aW9uIG9yIG90aGVyIGRlcm9nYXRvcnkgYWN0aW9uIHByZWp1ZGljaWFsIHRvIHRoZSBPcmlnaW5hbCBBdXRob3IncyBob25vciBhbmQgcmVwdXRhdGlvbiwgdGhlIExpY2Vuc29yIHdpbGwgd2FpdmUgb3Igbm90IGFzc2VydCwgYXMgYXBwcm9wcmlhdGUsIHRoaXMgU2VjdGlvbiwgdG8gdGhlIGZ1bGxlc3QgZXh0ZW50IHBlcm1pdHRlZCBieSB0aGUgYXBwbGljYWJsZSBuYXRpb25hbCBsYXcsIHRvIGVuYWJsZSBZb3UgdG8gcmVhc29uYWJseSBleGVyY2lzZSBZb3VyIHJpZ2h0IHVuZGVyIFNlY3Rpb24gMyhiKSBvZiB0aGlzIExpY2Vuc2UgKHJpZ2h0IHRvIG1ha2UgQWRhcHRhdGlvbnMpIGJ1dCBub3Qgb3RoZXJ3aXNlLgoKNS4gUmVwcmVzZW50YXRpb25zLCBXYXJyYW50aWVzIGFuZCBEaXNjbGFpbWVyCgpVTkxFU1MgT1RIRVJXSVNFIE1VVFVBTExZIEFHUkVFRCBUTyBCWSBUSEUgUEFSVElFUyBJTiBXUklUSU5HLCBMSUNFTlNPUiBPRkZFUlMgVEhFIFdPUksgQVMtSVMgQU5EIE1BS0VTIE5PIFJFUFJFU0VOVEFUSU9OUyBPUiBXQVJSQU5USUVTIE9GIEFOWSBLSU5EIENPTkNFUk5JTkcgVEhFIFdPUkssIEVYUFJFU1MsIElNUExJRUQsIFNUQVRVVE9SWSBPUiBPVEhFUldJU0UsIElOQ0xVRElORywgV0lUSE9VVCBMSU1JVEFUSU9OLCBXQVJSQU5USUVTIE9GIFRJVExFLCBNRVJDSEFOVElCSUxJVFksIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLCBOT05JTkZSSU5HRU1FTlQsIE9SIFRIRSBBQlNFTkNFIE9GIExBVEVOVCBPUiBPVEhFUiBERUZFQ1RTLCBBQ0NVUkFDWSwgT1IgVEhFIFBSRVNFTkNFIE9GIEFCU0VOQ0UgT0YgRVJST1JTLCBXSEVUSEVSIE9SIE5PVCBESVNDT1ZFUkFCTEUuIFNPTUUgSlVSSVNESUNUSU9OUyBETyBOT1QgQUxMT1cgVEhFIEVYQ0xVU0lPTiBPRiBJTVBMSUVEIFdBUlJBTlRJRVMsIFNPIFNVQ0ggRVhDTFVTSU9OIE1BWSBOT1QgQVBQTFkgVE8gWU9VLgoKNi4gTGltaXRhdGlvbiBvbiBMaWFiaWxpdHkuIEVYQ0VQVCBUTyBUSEUgRVhURU5UIFJFUVVJUkVEIEJZIEFQUExJQ0FCTEUgTEFXLCBJTiBOTyBFVkVOVCBXSUxMIExJQ0VOU09SIEJFIExJQUJMRSBUTyBZT1UgT04gQU5ZIExFR0FMIFRIRU9SWSBGT1IgQU5ZIFNQRUNJQUwsIElOQ0lERU5UQUwsIENPTlNFUVVFTlRJQUwsIFBVTklUSVZFIE9SIEVYRU1QTEFSWSBEQU1BR0VTIEFSSVNJTkcgT1VUIE9GIFRISVMgTElDRU5TRSBPUiBUSEUgVVNFIE9GIFRIRSBXT1JLLCBFVkVOIElGIExJQ0VOU09SIEhBUyBCRUVOIEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GIFNVQ0ggREFNQUdFUy4KCjcuIFRlcm1pbmF0aW9uCgogICAgIGEuIFRoaXMgTGljZW5zZSBhbmQgdGhlIHJpZ2h0cyBncmFudGVkIGhlcmV1bmRlciB3aWxsIHRlcm1pbmF0ZSBhdXRvbWF0aWNhbGx5IHVwb24gYW55IGJyZWFjaCBieSBZb3Ugb2YgdGhlIHRlcm1zIG9mIHRoaXMgTGljZW5zZS4gSW5kaXZpZHVhbHMgb3IgZW50aXRpZXMgd2hvIGhhdmUgcmVjZWl2ZWQgQWRhcHRhdGlvbnMgb3IgQ29sbGVjdGlvbnMgZnJvbSBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlLCBob3dldmVyLCB3aWxsIG5vdCBoYXZlIHRoZWlyIGxpY2Vuc2VzIHRlcm1pbmF0ZWQgcHJvdmlkZWQgc3VjaCBpbmRpdmlkdWFscyBvciBlbnRpdGllcyByZW1haW4gaW4gZnVsbCBjb21wbGlhbmNlIHdpdGggdGhvc2UgbGljZW5zZXMuIFNlY3Rpb25zIDEsIDIsIDUsIDYsIDcsIGFuZCA4IHdpbGwgc3Vydml2ZSBhbnkgdGVybWluYXRpb24gb2YgdGhpcyBMaWNlbnNlLgoKICAgICBiLiBTdWJqZWN0IHRvIHRoZSBhYm92ZSB0ZXJtcyBhbmQgY29uZGl0aW9ucywgdGhlIGxpY2Vuc2UgZ3JhbnRlZCBoZXJlIGlzIHBlcnBldHVhbCAoZm9yIHRoZSBkdXJhdGlvbiBvZiB0aGUgYXBwbGljYWJsZSBjb3B5cmlnaHQgaW4gdGhlIFdvcmspLiBOb3R3aXRoc3RhbmRpbmcgdGhlIGFib3ZlLCBMaWNlbnNvciByZXNlcnZlcyB0aGUgcmlnaHQgdG8gcmVsZWFzZSB0aGUgV29yayB1bmRlciBkaWZmZXJlbnQgbGljZW5zZSB0ZXJtcyBvciB0byBzdG9wIGRpc3RyaWJ1dGluZyB0aGUgV29yayBhdCBhbnkgdGltZTsgcHJvdmlkZWQsIGhvd2V2ZXIgdGhhdCBhbnkgc3VjaCBlbGVjdGlvbiB3aWxsIG5vdCBzZXJ2ZSB0byB3aXRoZHJhdyB0aGlzIExpY2Vuc2UgKG9yIGFueSBvdGhlciBsaWNlbnNlIHRoYXQgaGFzIGJlZW4sIG9yIGlzIHJlcXVpcmVkIHRvIGJlLCBncmFudGVkIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGlzIExpY2Vuc2UpLCBhbmQgdGhpcyBMaWNlbnNlIHdpbGwgY29udGludWUgaW4gZnVsbCBmb3JjZSBhbmQgZWZmZWN0IHVubGVzcyB0ZXJtaW5hdGVkIGFzIHN0YXRlZCBhYm92ZS4KCjguIE1pc2NlbGxhbmVvdXMKCiAgICAgYS4gRWFjaCB0aW1lIFlvdSBEaXN0cmlidXRlIG9yIFB1YmxpY2x5IFBlcmZvcm0gdGhlIFdvcmsgb3IgYSBDb2xsZWN0aW9uLCB0aGUgTGljZW5zb3Igb2ZmZXJzIHRvIHRoZSByZWNpcGllbnQgYSBsaWNlbnNlIHRvIHRoZSBXb3JrIG9uIHRoZSBzYW1lIHRlcm1zIGFuZCBjb25kaXRpb25zIGFzIHRoZSBsaWNlbnNlIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgICAgYi4gRWFjaCB0aW1lIFlvdSBEaXN0cmlidXRlIG9yIFB1YmxpY2x5IFBlcmZvcm0gYW4gQWRhcHRhdGlvbiwgTGljZW5zb3Igb2ZmZXJzIHRvIHRoZSByZWNpcGllbnQgYSBsaWNlbnNlIHRvIHRoZSBvcmlnaW5hbCBXb3JrIG9uIHRoZSBzYW1lIHRlcm1zIGFuZCBjb25kaXRpb25zIGFzIHRoZSBsaWNlbnNlIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZS4KCiAgICAgYy4gSWYgYW55IHByb3Zpc2lvbiBvZiB0aGlzIExpY2Vuc2UgaXMgaW52YWxpZCBvciB1bmVuZm9yY2VhYmxlIHVuZGVyIGFwcGxpY2FibGUgbGF3LCBpdCBzaGFsbCBub3QgYWZmZWN0IHRoZSB2YWxpZGl0eSBvciBlbmZvcmNlYWJpbGl0eSBvZiB0aGUgcmVtYWluZGVyIG9mIHRoZSB0ZXJtcyBvZiB0aGlzIExpY2Vuc2UsIGFuZCB3aXRob3V0IGZ1cnRoZXIgYWN0aW9uIGJ5IHRoZSBwYXJ0aWVzIHRvIHRoaXMgYWdyZWVtZW50LCBzdWNoIHByb3Zpc2lvbiBzaGFsbCBiZSByZWZvcm1lZCB0byB0aGUgbWluaW11bSBleHRlbnQgbmVjZXNzYXJ5IHRvIG1ha2Ugc3VjaCBwcm92aXNpb24gdmFsaWQgYW5kIGVuZm9yY2VhYmxlLgoKICAgICBkLiBObyB0ZXJtIG9yIHByb3Zpc2lvbiBvZiB0aGlzIExpY2Vuc2Ugc2hhbGwgYmUgZGVlbWVkIHdhaXZlZCBhbmQgbm8gYnJlYWNoIGNvbnNlbnRlZCB0byB1bmxlc3Mgc3VjaCB3YWl2ZXIgb3IgY29uc2VudCBzaGFsbCBiZSBpbiB3cml0aW5nIGFuZCBzaWduZWQgYnkgdGhlIHBhcnR5IHRvIGJlIGNoYXJnZWQgd2l0aCBzdWNoIHdhaXZlciBvciBjb25zZW50LgoKICAgICBlLiBUaGlzIExpY2Vuc2UgY29uc3RpdHV0ZXMgdGhlIGVudGlyZSBhZ3JlZW1lbnQgYmV0d2VlbiB0aGUgcGFydGllcyB3aXRoIHJlc3BlY3QgdG8gdGhlIFdvcmsgbGljZW5zZWQgaGVyZS4gVGhlcmUgYXJlIG5vIHVuZGVyc3RhbmRpbmdzLCBhZ3JlZW1lbnRzIG9yIHJlcHJlc2VudGF0aW9ucyB3aXRoIHJlc3BlY3QgdG8gdGhlIFdvcmsgbm90IHNwZWNpZmllZCBoZXJlLiBMaWNlbnNvciBzaGFsbCBub3QgYmUgYm91bmQgYnkgYW55IGFkZGl0aW9uYWwgcHJvdmlzaW9ucyB0aGF0IG1heSBhcHBlYXIgaW4gYW55IGNvbW11bmljYXRpb24gZnJvbSBZb3UuIFRoaXMgTGljZW5zZSBtYXkgbm90IGJlIG1vZGlmaWVkIHdpdGhvdXQgdGhlIG11dHVhbCB3cml0dGVuIGFncmVlbWVudCBvZiB0aGUgTGljZW5zb3IgYW5kIFlvdS4KCiAgICAgZi4gVGhlIHJpZ2h0cyBncmFudGVkIHVuZGVyLCBhbmQgdGhlIHN1YmplY3QgbWF0dGVyIHJlZmVyZW5jZWQsIGluIHRoaXMgTGljZW5zZSB3ZXJlIGRyYWZ0ZWQgdXRpbGl6aW5nIHRoZSB0ZXJtaW5vbG9neSBvZiB0aGUgQmVybmUgQ29udmVudGlvbiBmb3IgdGhlIFByb3RlY3Rpb24gb2YgTGl0ZXJhcnkgYW5kIEFydGlzdGljIFdvcmtzIChhcyBhbWVuZGVkIG9uIFNlcHRlbWJlciAyOCwgMTk3OSksIHRoZSBSb21lIENvbnZlbnRpb24gb2YgMTk2MSwgdGhlIFdJUE8gQ29weXJpZ2h0IFRyZWF0eSBvZiAxOTk2LCB0aGUgV0lQTyBQZXJmb3JtYW5jZXMgYW5kIFBob25vZ3JhbXMgVHJlYXR5IG9mIDE5OTYgYW5kIHRoZSBVbml2ZXJzYWwgQ29weXJpZ2h0IENvbnZlbnRpb24gKGFzIHJldmlzZWQgb24gSnVseSAyNCwgMTk3MSkuIFRoZXNlIHJpZ2h0cyBhbmQgc3ViamVjdCBtYXR0ZXIgdGFrZSBlZmZlY3QgaW4gdGhlIHJlbGV2YW50IGp1cmlzZGljdGlvbiBpbiB3aGljaCB0aGUgTGljZW5zZSB0ZXJtcyBhcmUgc291Z2h0IHRvIGJlIGVuZm9yY2VkIGFjY29yZGluZyB0byB0aGUgY29ycmVzcG9uZGluZyBwcm92aXNpb25zIG9mIHRoZSBpbXBsZW1lbnRhdGlvbiBvZiB0aG9zZSB0cmVhdHkgcHJvdmlzaW9ucyBpbiB0aGUgYXBwbGljYWJsZSBuYXRpb25hbCBsYXcuIElmIHRoZSBzdGFuZGFyZCBzdWl0ZSBvZiByaWdodHMgZ3JhbnRlZCB1bmRlciBhcHBsaWNhYmxlIGNvcHlyaWdodCBsYXcgaW5jbHVkZXMgYWRkaXRpb25hbCByaWdodHMgbm90IGdyYW50ZWQgdW5kZXIgdGhpcyBMaWNlbnNlLCBzdWNoIGFkZGl0aW9uYWwgcmlnaHRzIGFyZSBkZWVtZWQgdG8gYmUgaW5jbHVkZWQgaW4gdGhlIExpY2Vuc2U7IHRoaXMgTGljZW5zZSBpcyBub3QgaW50ZW5kZWQgdG8gcmVzdHJpY3QgdGhlIGxpY2Vuc2Ugb2YgYW55IHJpZ2h0cyB1bmRlciBhcHBsaWNhYmxlIGxhdy4KCkNyZWF0aXZlIENvbW1vbnMgTm90aWNlCgpDcmVhdGl2ZSBDb21tb25zIGlzIG5vdCBhIHBhcnR5IHRvIHRoaXMgTGljZW5zZSwgYW5kIG1ha2VzIG5vIHdhcnJhbnR5IHdoYXRzb2V2ZXIgaW4gY29ubmVjdGlvbiB3aXRoIHRoZSBXb3JrLiBDcmVhdGl2ZSBDb21tb25zIHdpbGwgbm90IGJlIGxpYWJsZSB0byBZb3Ugb3IgYW55IHBhcnR5IG9uIGFueSBsZWdhbCB0aGVvcnkgZm9yIGFueSBkYW1hZ2VzIHdoYXRzb2V2ZXIsIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gYW55IGdlbmVyYWwsIHNwZWNpYWwsIGluY2lkZW50YWwgb3IgY29uc2VxdWVudGlhbCBkYW1hZ2VzIGFyaXNpbmcgaW4gY29ubmVjdGlvbiB0byB0aGlzIGxpY2Vuc2UuIE5vdHdpdGhzdGFuZGluZyB0aGUgZm9yZWdvaW5nIHR3byAoMikgc2VudGVuY2VzLCBpZiBDcmVhdGl2ZSBDb21tb25zIGhhcyBleHByZXNzbHkgaWRlbnRpZmllZCBpdHNlbGYgYXMgdGhlIExpY2Vuc29yIGhlcmV1bmRlciwgaXQgc2hhbGwgaGF2ZSBhbGwgcmlnaHRzIGFuZCBvYmxpZ2F0aW9ucyBvZiBMaWNlbnNvci4KCkV4Y2VwdCBmb3IgdGhlIGxpbWl0ZWQgcHVycG9zZSBvZiBpbmRpY2F0aW5nIHRvIHRoZSBwdWJsaWMgdGhhdCB0aGUgV29yayBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQ0NQTCwgQ3JlYXRpdmUgQ29tbW9ucyBkb2VzIG5vdCBhdXRob3JpemUgdGhlIHVzZSBieSBlaXRoZXIgcGFydHkgb2YgdGhlIHRyYWRlbWFyayAiQ3JlYXRpdmUgQ29tbW9ucyIgb3IgYW55IHJlbGF0ZWQgdHJhZGVtYXJrIG9yIGxvZ28gb2YgQ3JlYXRpdmUgQ29tbW9ucyB3aXRob3V0IHRoZSBwcmlvciB3cml0dGVuIGNvbnNlbnQgb2YgQ3JlYXRpdmUgQ29tbW9ucy4gQW55IHBlcm1pdHRlZCB1c2Ugd2lsbCBiZSBpbiBjb21wbGlhbmNlIHdpdGggQ3JlYXRpdmUgQ29tbW9ucycgdGhlbi1jdXJyZW50IHRyYWRlbWFyayB1c2FnZSBndWlkZWxpbmVzLCBhcyBtYXkgYmUgcHVibGlzaGVkIG9uIGl0cyB3ZWJzaXRlIG9yIG90aGVyd2lzZSBtYWRlIGF2YWlsYWJsZSB1cG9uIHJlcXVlc3QgZnJvbSB0aW1lIHRvIHRpbWUuIEZvciB0aGUgYXZvaWRhbmNlIG9mIGRvdWJ0LCB0aGlzIHRyYWRlbWFyayByZXN0cmljdGlvbiBkb2VzIG5vdCBmb3JtIHBhcnQgb2YgdGhlIExpY2Vuc2UuCgpDcmVhdGl2ZSBDb21tb25zIG1heSBiZSBjb250YWN0ZWQgYXQgaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvLg=="},"url":"https:\/\/creativecommons.org\/licenses\/by-sa\/3.0\/legalcode"}}],"version":"1","purl":"pkg:\/Milan Mendpara\/9082892@1","supplier":{"name":"Milan Mendpara"},"bom-ref":"9082892_1_fb74e921-0ec9-4d54-9926-ee739f847fd0","description":"","copyright":"","properties":[{"name":"component_id","value":"968"}]},{"name":"jszip","type":"library","licenses":[{"license":{"id":"MIT","text":{"contentType":"text\/plain","encoding":"base64","content":"TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgPHllYXI+IDxjb3B5cmlnaHQgaG9sZGVycz4KClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUu"},"url":"https:\/\/opensource.org\/licenses\/MIT"}}],"version":"2.6.0","cpe":"cpe:2.3:a:jszip_project:jszip:2.6.0:*:*:*:*:node.js:*:*","purl":"pkg:github\/Stuk\/jszip@2.6.0","supplier":{"name":"stuk"},"bom-ref":"jszip_2.6.0_37f396b4-dd84-4a70-999c-20fb01d3f0b5","description":"","copyright":"","properties":[{"name":"component_id","value":"6"}]},{"name":"node-forge","type":"library","licenses":[{"license":{"id":"GPL-2.0-only","text":{"contentType":"text\/plain","encoding":"base64","content":"R05VIEdFTkVSQUwgUFVCTElDIExJQ0VOU0UKVmVyc2lvbiAyLCBKdW5lIDE5OTEKCkNvcHlyaWdodCAoQykgMTk4OSwgMTk5MSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIEluYy4KNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSwgVVNBCgpFdmVyeW9uZSBpcyBwZXJtaXR0ZWQgdG8gY29weSBhbmQgZGlzdHJpYnV0ZSB2ZXJiYXRpbSBjb3BpZXMgb2YgdGhpcyBsaWNlbnNlIGRvY3VtZW50LCBidXQgY2hhbmdpbmcgaXQgaXMgbm90IGFsbG93ZWQuCgpQcmVhbWJsZQoKVGhlIGxpY2Vuc2VzIGZvciBtb3N0IHNvZnR3YXJlIGFyZSBkZXNpZ25lZCB0byB0YWtlIGF3YXkgeW91ciBmcmVlZG9tIHRvIHNoYXJlIGFuZCBjaGFuZ2UgaXQuIEJ5IGNvbnRyYXN0LCB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgaXMgaW50ZW5kZWQgdG8gZ3VhcmFudGVlIHlvdXIgZnJlZWRvbSB0byBzaGFyZSBhbmQgY2hhbmdlIGZyZWUgc29mdHdhcmUtLXRvIG1ha2Ugc3VyZSB0aGUgc29mdHdhcmUgaXMgZnJlZSBmb3IgYWxsIGl0cyB1c2Vycy4gVGhpcyBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFwcGxpZXMgdG8gbW9zdCBvZiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uJ3Mgc29mdHdhcmUgYW5kIHRvIGFueSBvdGhlciBwcm9ncmFtIHdob3NlIGF1dGhvcnMgY29tbWl0IHRvIHVzaW5nIGl0LiAoU29tZSBvdGhlciBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24gc29mdHdhcmUgaXMgY292ZXJlZCBieSB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGluc3RlYWQuKSBZb3UgY2FuIGFwcGx5IGl0IHRvIHlvdXIgcHJvZ3JhbXMsIHRvby4KCldoZW4gd2Ugc3BlYWsgb2YgZnJlZSBzb2Z0d2FyZSwgd2UgYXJlIHJlZmVycmluZyB0byBmcmVlZG9tLCBub3QgcHJpY2UuIE91ciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlcyBhcmUgZGVzaWduZWQgdG8gbWFrZSBzdXJlIHRoYXQgeW91IGhhdmUgdGhlIGZyZWVkb20gdG8gZGlzdHJpYnV0ZSBjb3BpZXMgb2YgZnJlZSBzb2Z0d2FyZSAoYW5kIGNoYXJnZSBmb3IgdGhpcyBzZXJ2aWNlIGlmIHlvdSB3aXNoKSwgdGhhdCB5b3UgcmVjZWl2ZSBzb3VyY2UgY29kZSBvciBjYW4gZ2V0IGl0IGlmIHlvdSB3YW50IGl0LCB0aGF0IHlvdSBjYW4gY2hhbmdlIHRoZSBzb2Z0d2FyZSBvciB1c2UgcGllY2VzIG9mIGl0IGluIG5ldyBmcmVlIHByb2dyYW1zOyBhbmQgdGhhdCB5b3Uga25vdyB5b3UgY2FuIGRvIHRoZXNlIHRoaW5ncy4KClRvIHByb3RlY3QgeW91ciByaWdodHMsIHdlIG5lZWQgdG8gbWFrZSByZXN0cmljdGlvbnMgdGhhdCBmb3JiaWQgYW55b25lIHRvIGRlbnkgeW91IHRoZXNlIHJpZ2h0cyBvciB0byBhc2sgeW91IHRvIHN1cnJlbmRlciB0aGUgcmlnaHRzLiBUaGVzZSByZXN0cmljdGlvbnMgdHJhbnNsYXRlIHRvIGNlcnRhaW4gcmVzcG9uc2liaWxpdGllcyBmb3IgeW91IGlmIHlvdSBkaXN0cmlidXRlIGNvcGllcyBvZiB0aGUgc29mdHdhcmUsIG9yIGlmIHlvdSBtb2RpZnkgaXQuCgpGb3IgZXhhbXBsZSwgaWYgeW91IGRpc3RyaWJ1dGUgY29waWVzIG9mIHN1Y2ggYSBwcm9ncmFtLCB3aGV0aGVyIGdyYXRpcyBvciBmb3IgYSBmZWUsIHlvdSBtdXN0IGdpdmUgdGhlIHJlY2lwaWVudHMgYWxsIHRoZSByaWdodHMgdGhhdCB5b3UgaGF2ZS4gWW91IG11c3QgbWFrZSBzdXJlIHRoYXQgdGhleSwgdG9vLCByZWNlaXZlIG9yIGNhbiBnZXQgdGhlIHNvdXJjZSBjb2RlLiBBbmQgeW91IG11c3Qgc2hvdyB0aGVtIHRoZXNlIHRlcm1zIHNvIHRoZXkga25vdyB0aGVpciByaWdodHMuCgpXZSBwcm90ZWN0IHlvdXIgcmlnaHRzIHdpdGggdHdvIHN0ZXBzOiAoMSkgY29weXJpZ2h0IHRoZSBzb2Z0d2FyZSwgYW5kICgyKSBvZmZlciB5b3UgdGhpcyBsaWNlbnNlIHdoaWNoIGdpdmVzIHlvdSBsZWdhbCBwZXJtaXNzaW9uIHRvIGNvcHksIGRpc3RyaWJ1dGUgYW5kL29yIG1vZGlmeSB0aGUgc29mdHdhcmUuCgpBbHNvLCBmb3IgZWFjaCBhdXRob3IncyBwcm90ZWN0aW9uIGFuZCBvdXJzLCB3ZSB3YW50IHRvIG1ha2UgY2VydGFpbiB0aGF0IGV2ZXJ5b25lIHVuZGVyc3RhbmRzIHRoYXQgdGhlcmUgaXMgbm8gd2FycmFudHkgZm9yIHRoaXMgZnJlZSBzb2Z0d2FyZS4gSWYgdGhlIHNvZnR3YXJlIGlzIG1vZGlmaWVkIGJ5IHNvbWVvbmUgZWxzZSBhbmQgcGFzc2VkIG9uLCB3ZSB3YW50IGl0cyByZWNpcGllbnRzIHRvIGtub3cgdGhhdCB3aGF0IHRoZXkgaGF2ZSBpcyBub3QgdGhlIG9yaWdpbmFsLCBzbyB0aGF0IGFueSBwcm9ibGVtcyBpbnRyb2R1Y2VkIGJ5IG90aGVycyB3aWxsIG5vdCByZWZsZWN0IG9uIHRoZSBvcmlnaW5hbCBhdXRob3JzJyByZXB1dGF0aW9ucy4KCkZpbmFsbHksIGFueSBmcmVlIHByb2dyYW0gaXMgdGhyZWF0ZW5lZCBjb25zdGFudGx5IGJ5IHNvZnR3YXJlIHBhdGVudHMuIFdlIHdpc2ggdG8gYXZvaWQgdGhlIGRhbmdlciB0aGF0IHJlZGlzdHJpYnV0b3JzIG9mIGEgZnJlZSBwcm9ncmFtIHdpbGwgaW5kaXZpZHVhbGx5IG9idGFpbiBwYXRlbnQgbGljZW5zZXMsIGluIGVmZmVjdCBtYWtpbmcgdGhlIHByb2dyYW0gcHJvcHJpZXRhcnkuIFRvIHByZXZlbnQgdGhpcywgd2UgaGF2ZSBtYWRlIGl0IGNsZWFyIHRoYXQgYW55IHBhdGVudCBtdXN0IGJlIGxpY2Vuc2VkIGZvciBldmVyeW9uZSdzIGZyZWUgdXNlIG9yIG5vdCBsaWNlbnNlZCBhdCBhbGwuCgpUaGUgcHJlY2lzZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgY29weWluZywgZGlzdHJpYnV0aW9uIGFuZCBtb2RpZmljYXRpb24gZm9sbG93LgoKVEVSTVMgQU5EIENPTkRJVElPTlMgRk9SIENPUFlJTkcsIERJU1RSSUJVVElPTiBBTkQgTU9ESUZJQ0FUSU9OCgowLiBUaGlzIExpY2Vuc2UgYXBwbGllcyB0byBhbnkgcHJvZ3JhbSBvciBvdGhlciB3b3JrIHdoaWNoIGNvbnRhaW5zIGEgbm90aWNlIHBsYWNlZCBieSB0aGUgY29weXJpZ2h0IGhvbGRlciBzYXlpbmcgaXQgbWF5IGJlIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGlzIEdlbmVyYWwgUHVibGljIExpY2Vuc2UuIFRoZSAiUHJvZ3JhbSIsIGJlbG93LCByZWZlcnMgdG8gYW55IHN1Y2ggcHJvZ3JhbSBvciB3b3JrLCBhbmQgYSAid29yayBiYXNlZCBvbiB0aGUgUHJvZ3JhbSIgbWVhbnMgZWl0aGVyIHRoZSBQcm9ncmFtIG9yIGFueSBkZXJpdmF0aXZlIHdvcmsgdW5kZXIgY29weXJpZ2h0IGxhdzogdGhhdCBpcyB0byBzYXksIGEgd29yayBjb250YWluaW5nIHRoZSBQcm9ncmFtIG9yIGEgcG9ydGlvbiBvZiBpdCwgZWl0aGVyIHZlcmJhdGltIG9yIHdpdGggbW9kaWZpY2F0aW9ucyBhbmQvb3IgdHJhbnNsYXRlZCBpbnRvIGFub3RoZXIgbGFuZ3VhZ2UuIChIZXJlaW5hZnRlciwgdHJhbnNsYXRpb24gaXMgaW5jbHVkZWQgd2l0aG91dCBsaW1pdGF0aW9uIGluIHRoZSB0ZXJtICJtb2RpZmljYXRpb24iLikgRWFjaCBsaWNlbnNlZSBpcyBhZGRyZXNzZWQgYXMgInlvdSIuCgpBY3Rpdml0aWVzIG90aGVyIHRoYW4gY29weWluZywgZGlzdHJpYnV0aW9uIGFuZCBtb2RpZmljYXRpb24gYXJlIG5vdCBjb3ZlcmVkIGJ5IHRoaXMgTGljZW5zZTsgdGhleSBhcmUgb3V0c2lkZSBpdHMgc2NvcGUuIFRoZSBhY3Qgb2YgcnVubmluZyB0aGUgUHJvZ3JhbSBpcyBub3QgcmVzdHJpY3RlZCwgYW5kIHRoZSBvdXRwdXQgZnJvbSB0aGUgUHJvZ3JhbSBpcyBjb3ZlcmVkIG9ubHkgaWYgaXRzIGNvbnRlbnRzIGNvbnN0aXR1dGUgYSB3b3JrIGJhc2VkIG9uIHRoZSBQcm9ncmFtIChpbmRlcGVuZGVudCBvZiBoYXZpbmcgYmVlbiBtYWRlIGJ5IHJ1bm5pbmcgdGhlIFByb2dyYW0pLiBXaGV0aGVyIHRoYXQgaXMgdHJ1ZSBkZXBlbmRzIG9uIHdoYXQgdGhlIFByb2dyYW0gZG9lcy4KCjEuIFlvdSBtYXkgY29weSBhbmQgZGlzdHJpYnV0ZSB2ZXJiYXRpbSBjb3BpZXMgb2YgdGhlIFByb2dyYW0ncyBzb3VyY2UgY29kZSBhcyB5b3UgcmVjZWl2ZSBpdCwgaW4gYW55IG1lZGl1bSwgcHJvdmlkZWQgdGhhdCB5b3UgY29uc3BpY3VvdXNseSBhbmQgYXBwcm9wcmlhdGVseSBwdWJsaXNoIG9uIGVhY2ggY29weSBhbiBhcHByb3ByaWF0ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCBkaXNjbGFpbWVyIG9mIHdhcnJhbnR5OyBrZWVwIGludGFjdCBhbGwgdGhlIG5vdGljZXMgdGhhdCByZWZlciB0byB0aGlzIExpY2Vuc2UgYW5kIHRvIHRoZSBhYnNlbmNlIG9mIGFueSB3YXJyYW50eTsgYW5kIGdpdmUgYW55IG90aGVyIHJlY2lwaWVudHMgb2YgdGhlIFByb2dyYW0gYSBjb3B5IG9mIHRoaXMgTGljZW5zZSBhbG9uZyB3aXRoIHRoZSBQcm9ncmFtLgoKWW91IG1heSBjaGFyZ2UgYSBmZWUgZm9yIHRoZSBwaHlzaWNhbCBhY3Qgb2YgdHJhbnNmZXJyaW5nIGEgY29weSwgYW5kIHlvdSBtYXkgYXQgeW91ciBvcHRpb24gb2ZmZXIgd2FycmFudHkgcHJvdGVjdGlvbiBpbiBleGNoYW5nZSBmb3IgYSBmZWUuCgoyLiBZb3UgbWF5IG1vZGlmeSB5b3VyIGNvcHkgb3IgY29waWVzIG9mIHRoZSBQcm9ncmFtIG9yIGFueSBwb3J0aW9uIG9mIGl0LCB0aHVzIGZvcm1pbmcgYSB3b3JrIGJhc2VkIG9uIHRoZSBQcm9ncmFtLCBhbmQgY29weSBhbmQgZGlzdHJpYnV0ZSBzdWNoIG1vZGlmaWNhdGlvbnMgb3Igd29yayB1bmRlciB0aGUgdGVybXMgb2YgU2VjdGlvbiAxIGFib3ZlLCBwcm92aWRlZCB0aGF0IHlvdSBhbHNvIG1lZXQgYWxsIG9mIHRoZXNlIGNvbmRpdGlvbnM6CgogICAgIGEpIFlvdSBtdXN0IGNhdXNlIHRoZSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBwcm9taW5lbnQgbm90aWNlcyBzdGF0aW5nIHRoYXQgeW91IGNoYW5nZWQgdGhlIGZpbGVzIGFuZCB0aGUgZGF0ZSBvZiBhbnkgY2hhbmdlLgoKICAgICBiKSBZb3UgbXVzdCBjYXVzZSBhbnkgd29yayB0aGF0IHlvdSBkaXN0cmlidXRlIG9yIHB1Ymxpc2gsIHRoYXQgaW4gd2hvbGUgb3IgaW4gcGFydCBjb250YWlucyBvciBpcyBkZXJpdmVkIGZyb20gdGhlIFByb2dyYW0gb3IgYW55IHBhcnQgdGhlcmVvZiwgdG8gYmUgbGljZW5zZWQgYXMgYSB3aG9sZSBhdCBubyBjaGFyZ2UgdG8gYWxsIHRoaXJkIHBhcnRpZXMgdW5kZXIgdGhlIHRlcm1zIG9mIHRoaXMgTGljZW5zZS4KCiAgICAgYykgSWYgdGhlIG1vZGlmaWVkIHByb2dyYW0gbm9ybWFsbHkgcmVhZHMgY29tbWFuZHMgaW50ZXJhY3RpdmVseSB3aGVuIHJ1biwgeW91IG11c3QgY2F1c2UgaXQsIHdoZW4gc3RhcnRlZCBydW5uaW5nIGZvciBzdWNoIGludGVyYWN0aXZlIHVzZSBpbiB0aGUgbW9zdCBvcmRpbmFyeSB3YXksIHRvIHByaW50IG9yIGRpc3BsYXkgYW4gYW5ub3VuY2VtZW50IGluY2x1ZGluZyBhbiBhcHByb3ByaWF0ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCBhIG5vdGljZSB0aGF0IHRoZXJlIGlzIG5vIHdhcnJhbnR5IChvciBlbHNlLCBzYXlpbmcgdGhhdCB5b3UgcHJvdmlkZSBhIHdhcnJhbnR5KSBhbmQgdGhhdCB1c2VycyBtYXkgcmVkaXN0cmlidXRlIHRoZSBwcm9ncmFtIHVuZGVyIHRoZXNlIGNvbmRpdGlvbnMsIGFuZCB0ZWxsaW5nIHRoZSB1c2VyIGhvdyB0byB2aWV3IGEgY29weSBvZiB0aGlzIExpY2Vuc2UuIChFeGNlcHRpb246IGlmIHRoZSBQcm9ncmFtIGl0c2VsZiBpcyBpbnRlcmFjdGl2ZSBidXQgZG9lcyBub3Qgbm9ybWFsbHkgcHJpbnQgc3VjaCBhbiBhbm5vdW5jZW1lbnQsIHlvdXIgd29yayBiYXNlZCBvbiB0aGUgUHJvZ3JhbSBpcyBub3QgcmVxdWlyZWQgdG8gcHJpbnQgYW4gYW5ub3VuY2VtZW50LikKClRoZXNlIHJlcXVpcmVtZW50cyBhcHBseSB0byB0aGUgbW9kaWZpZWQgd29yayBhcyBhIHdob2xlLiBJZiBpZGVudGlmaWFibGUgc2VjdGlvbnMgb2YgdGhhdCB3b3JrIGFyZSBub3QgZGVyaXZlZCBmcm9tIHRoZSBQcm9ncmFtLCBhbmQgY2FuIGJlIHJlYXNvbmFibHkgY29uc2lkZXJlZCBpbmRlcGVuZGVudCBhbmQgc2VwYXJhdGUgd29ya3MgaW4gdGhlbXNlbHZlcywgdGhlbiB0aGlzIExpY2Vuc2UsIGFuZCBpdHMgdGVybXMsIGRvIG5vdCBhcHBseSB0byB0aG9zZSBzZWN0aW9ucyB3aGVuIHlvdSBkaXN0cmlidXRlIHRoZW0gYXMgc2VwYXJhdGUgd29ya3MuIEJ1dCB3aGVuIHlvdSBkaXN0cmlidXRlIHRoZSBzYW1lIHNlY3Rpb25zIGFzIHBhcnQgb2YgYSB3aG9sZSB3aGljaCBpcyBhIHdvcmsgYmFzZWQgb24gdGhlIFByb2dyYW0sIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHdob2xlIG11c3QgYmUgb24gdGhlIHRlcm1zIG9mIHRoaXMgTGljZW5zZSwgd2hvc2UgcGVybWlzc2lvbnMgZm9yIG90aGVyIGxpY2Vuc2VlcyBleHRlbmQgdG8gdGhlIGVudGlyZSB3aG9sZSwgYW5kIHRodXMgdG8gZWFjaCBhbmQgZXZlcnkgcGFydCByZWdhcmRsZXNzIG9mIHdobyB3cm90ZSBpdC4KClRodXMsIGl0IGlzIG5vdCB0aGUgaW50ZW50IG9mIHRoaXMgc2VjdGlvbiB0byBjbGFpbSByaWdodHMgb3IgY29udGVzdCB5b3VyIHJpZ2h0cyB0byB3b3JrIHdyaXR0ZW4gZW50aXJlbHkgYnkgeW91OyByYXRoZXIsIHRoZSBpbnRlbnQgaXMgdG8gZXhlcmNpc2UgdGhlIHJpZ2h0IHRvIGNvbnRyb2wgdGhlIGRpc3RyaWJ1dGlvbiBvZiBkZXJpdmF0aXZlIG9yIGNvbGxlY3RpdmUgd29ya3MgYmFzZWQgb24gdGhlIFByb2dyYW0uCgpJbiBhZGRpdGlvbiwgbWVyZSBhZ2dyZWdhdGlvbiBvZiBhbm90aGVyIHdvcmsgbm90IGJhc2VkIG9uIHRoZSBQcm9ncmFtIHdpdGggdGhlIFByb2dyYW0gKG9yIHdpdGggYSB3b3JrIGJhc2VkIG9uIHRoZSBQcm9ncmFtKSBvbiBhIHZvbHVtZSBvZiBhIHN0b3JhZ2Ugb3IgZGlzdHJpYnV0aW9uIG1lZGl1bSBkb2VzIG5vdCBicmluZyB0aGUgb3RoZXIgd29yayB1bmRlciB0aGUgc2NvcGUgb2YgdGhpcyBMaWNlbnNlLgoKMy4gWW91IG1heSBjb3B5IGFuZCBkaXN0cmlidXRlIHRoZSBQcm9ncmFtIChvciBhIHdvcmsgYmFzZWQgb24gaXQsIHVuZGVyIFNlY3Rpb24gMikgaW4gb2JqZWN0IGNvZGUgb3IgZXhlY3V0YWJsZSBmb3JtIHVuZGVyIHRoZSB0ZXJtcyBvZiBTZWN0aW9ucyAxIGFuZCAyIGFib3ZlIHByb3ZpZGVkIHRoYXQgeW91IGFsc28gZG8gb25lIG9mIHRoZSBmb2xsb3dpbmc6CgogICAgIGEpIEFjY29tcGFueSBpdCB3aXRoIHRoZSBjb21wbGV0ZSBjb3JyZXNwb25kaW5nIG1hY2hpbmUtcmVhZGFibGUgc291cmNlIGNvZGUsIHdoaWNoIG11c3QgYmUgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIHRlcm1zIG9mIFNlY3Rpb25zIDEgYW5kIDIgYWJvdmUgb24gYSBtZWRpdW0gY3VzdG9tYXJpbHkgdXNlZCBmb3Igc29mdHdhcmUgaW50ZXJjaGFuZ2U7IG9yLAoKICAgICBiKSBBY2NvbXBhbnkgaXQgd2l0aCBhIHdyaXR0ZW4gb2ZmZXIsIHZhbGlkIGZvciBhdCBsZWFzdCB0aHJlZSB5ZWFycywgdG8gZ2l2ZSBhbnkgdGhpcmQgcGFydHksIGZvciBhIGNoYXJnZSBubyBtb3JlIHRoYW4geW91ciBjb3N0IG9mIHBoeXNpY2FsbHkgcGVyZm9ybWluZyBzb3VyY2UgZGlzdHJpYnV0aW9uLCBhIGNvbXBsZXRlIG1hY2hpbmUtcmVhZGFibGUgY29weSBvZiB0aGUgY29ycmVzcG9uZGluZyBzb3VyY2UgY29kZSwgdG8gYmUgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIHRlcm1zIG9mIFNlY3Rpb25zIDEgYW5kIDIgYWJvdmUgb24gYSBtZWRpdW0gY3VzdG9tYXJpbHkgdXNlZCBmb3Igc29mdHdhcmUgaW50ZXJjaGFuZ2U7IG9yLAoKICAgICBjKSBBY2NvbXBhbnkgaXQgd2l0aCB0aGUgaW5mb3JtYXRpb24geW91IHJlY2VpdmVkIGFzIHRvIHRoZSBvZmZlciB0byBkaXN0cmlidXRlIGNvcnJlc3BvbmRpbmcgc291cmNlIGNvZGUuIChUaGlzIGFsdGVybmF0aXZlIGlzIGFsbG93ZWQgb25seSBmb3Igbm9uY29tbWVyY2lhbCBkaXN0cmlidXRpb24gYW5kIG9ubHkgaWYgeW91IHJlY2VpdmVkIHRoZSBwcm9ncmFtIGluIG9iamVjdCBjb2RlIG9yIGV4ZWN1dGFibGUgZm9ybSB3aXRoIHN1Y2ggYW4gb2ZmZXIsIGluIGFjY29yZCB3aXRoIFN1YnNlY3Rpb24gYiBhYm92ZS4pCgpUaGUgc291cmNlIGNvZGUgZm9yIGEgd29yayBtZWFucyB0aGUgcHJlZmVycmVkIGZvcm0gb2YgdGhlIHdvcmsgZm9yIG1ha2luZyBtb2RpZmljYXRpb25zIHRvIGl0LiBGb3IgYW4gZXhlY3V0YWJsZSB3b3JrLCBjb21wbGV0ZSBzb3VyY2UgY29kZSBtZWFucyBhbGwgdGhlIHNvdXJjZSBjb2RlIGZvciBhbGwgbW9kdWxlcyBpdCBjb250YWlucywgcGx1cyBhbnkgYXNzb2NpYXRlZCBpbnRlcmZhY2UgZGVmaW5pdGlvbiBmaWxlcywgcGx1cyB0aGUgc2NyaXB0cyB1c2VkIHRvIGNvbnRyb2wgY29tcGlsYXRpb24gYW5kIGluc3RhbGxhdGlvbiBvZiB0aGUgZXhlY3V0YWJsZS4gSG93ZXZlciwgYXMgYSBzcGVjaWFsIGV4Y2VwdGlvbiwgdGhlIHNvdXJjZSBjb2RlIGRpc3RyaWJ1dGVkIG5lZWQgbm90IGluY2x1ZGUgYW55dGhpbmcgdGhhdCBpcyBub3JtYWxseSBkaXN0cmlidXRlZCAoaW4gZWl0aGVyIHNvdXJjZSBvciBiaW5hcnkgZm9ybSkgd2l0aCB0aGUgbWFqb3IgY29tcG9uZW50cyAoY29tcGlsZXIsIGtlcm5lbCwgYW5kIHNvIG9uKSBvZiB0aGUgb3BlcmF0aW5nIHN5c3RlbSBvbiB3aGljaCB0aGUgZXhlY3V0YWJsZSBydW5zLCB1bmxlc3MgdGhhdCBjb21wb25lbnQgaXRzZWxmIGFjY29tcGFuaWVzIHRoZSBleGVjdXRhYmxlLgoKSWYgZGlzdHJpYnV0aW9uIG9mIGV4ZWN1dGFibGUgb3Igb2JqZWN0IGNvZGUgaXMgbWFkZSBieSBvZmZlcmluZyBhY2Nlc3MgdG8gY29weSBmcm9tIGEgZGVzaWduYXRlZCBwbGFjZSwgdGhlbiBvZmZlcmluZyBlcXVpdmFsZW50IGFjY2VzcyB0byBjb3B5IHRoZSBzb3VyY2UgY29kZSBmcm9tIHRoZSBzYW1lIHBsYWNlIGNvdW50cyBhcyBkaXN0cmlidXRpb24gb2YgdGhlIHNvdXJjZSBjb2RlLCBldmVuIHRob3VnaCB0aGlyZCBwYXJ0aWVzIGFyZSBub3QgY29tcGVsbGVkIHRvIGNvcHkgdGhlIHNvdXJjZSBhbG9uZyB3aXRoIHRoZSBvYmplY3QgY29kZS4KCjQuIFlvdSBtYXkgbm90IGNvcHksIG1vZGlmeSwgc3VibGljZW5zZSwgb3IgZGlzdHJpYnV0ZSB0aGUgUHJvZ3JhbSBleGNlcHQgYXMgZXhwcmVzc2x5IHByb3ZpZGVkIHVuZGVyIHRoaXMgTGljZW5zZS4gQW55IGF0dGVtcHQgb3RoZXJ3aXNlIHRvIGNvcHksIG1vZGlmeSwgc3VibGljZW5zZSBvciBkaXN0cmlidXRlIHRoZSBQcm9ncmFtIGlzIHZvaWQsIGFuZCB3aWxsIGF1dG9tYXRpY2FsbHkgdGVybWluYXRlIHlvdXIgcmlnaHRzIHVuZGVyIHRoaXMgTGljZW5zZS4gSG93ZXZlciwgcGFydGllcyB3aG8gaGF2ZSByZWNlaXZlZCBjb3BpZXMsIG9yIHJpZ2h0cywgZnJvbSB5b3UgdW5kZXIgdGhpcyBMaWNlbnNlIHdpbGwgbm90IGhhdmUgdGhlaXIgbGljZW5zZXMgdGVybWluYXRlZCBzbyBsb25nIGFzIHN1Y2ggcGFydGllcyByZW1haW4gaW4gZnVsbCBjb21wbGlhbmNlLgoKNS4gWW91IGFyZSBub3QgcmVxdWlyZWQgdG8gYWNjZXB0IHRoaXMgTGljZW5zZSwgc2luY2UgeW91IGhhdmUgbm90IHNpZ25lZCBpdC4gSG93ZXZlciwgbm90aGluZyBlbHNlIGdyYW50cyB5b3UgcGVybWlzc2lvbiB0byBtb2RpZnkgb3IgZGlzdHJpYnV0ZSB0aGUgUHJvZ3JhbSBvciBpdHMgZGVyaXZhdGl2ZSB3b3Jrcy4gVGhlc2UgYWN0aW9ucyBhcmUgcHJvaGliaXRlZCBieSBsYXcgaWYgeW91IGRvIG5vdCBhY2NlcHQgdGhpcyBMaWNlbnNlLiBUaGVyZWZvcmUsIGJ5IG1vZGlmeWluZyBvciBkaXN0cmlidXRpbmcgdGhlIFByb2dyYW0gKG9yIGFueSB3b3JrIGJhc2VkIG9uIHRoZSBQcm9ncmFtKSwgeW91IGluZGljYXRlIHlvdXIgYWNjZXB0YW5jZSBvZiB0aGlzIExpY2Vuc2UgdG8gZG8gc28sIGFuZCBhbGwgaXRzIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciBjb3B5aW5nLCBkaXN0cmlidXRpbmcgb3IgbW9kaWZ5aW5nIHRoZSBQcm9ncmFtIG9yIHdvcmtzIGJhc2VkIG9uIGl0LgoKNi4gRWFjaCB0aW1lIHlvdSByZWRpc3RyaWJ1dGUgdGhlIFByb2dyYW0gKG9yIGFueSB3b3JrIGJhc2VkIG9uIHRoZSBQcm9ncmFtKSwgdGhlIHJlY2lwaWVudCBhdXRvbWF0aWNhbGx5IHJlY2VpdmVzIGEgbGljZW5zZSBmcm9tIHRoZSBvcmlnaW5hbCBsaWNlbnNvciB0byBjb3B5LCBkaXN0cmlidXRlIG9yIG1vZGlmeSB0aGUgUHJvZ3JhbSBzdWJqZWN0IHRvIHRoZXNlIHRlcm1zIGFuZCBjb25kaXRpb25zLiBZb3UgbWF5IG5vdCBpbXBvc2UgYW55IGZ1cnRoZXIgcmVzdHJpY3Rpb25zIG9uIHRoZSByZWNpcGllbnRzJyBleGVyY2lzZSBvZiB0aGUgcmlnaHRzIGdyYW50ZWQgaGVyZWluLiBZb3UgYXJlIG5vdCByZXNwb25zaWJsZSBmb3IgZW5mb3JjaW5nIGNvbXBsaWFuY2UgYnkgdGhpcmQgcGFydGllcyB0byB0aGlzIExpY2Vuc2UuCgo3LiBJZiwgYXMgYSBjb25zZXF1ZW5jZSBvZiBhIGNvdXJ0IGp1ZGdtZW50IG9yIGFsbGVnYXRpb24gb2YgcGF0ZW50IGluZnJpbmdlbWVudCBvciBmb3IgYW55IG90aGVyIHJlYXNvbiAobm90IGxpbWl0ZWQgdG8gcGF0ZW50IGlzc3VlcyksIGNvbmRpdGlvbnMgYXJlIGltcG9zZWQgb24geW91ICh3aGV0aGVyIGJ5IGNvdXJ0IG9yZGVyLCBhZ3JlZW1lbnQgb3Igb3RoZXJ3aXNlKSB0aGF0IGNvbnRyYWRpY3QgdGhlIGNvbmRpdGlvbnMgb2YgdGhpcyBMaWNlbnNlLCB0aGV5IGRvIG5vdCBleGN1c2UgeW91IGZyb20gdGhlIGNvbmRpdGlvbnMgb2YgdGhpcyBMaWNlbnNlLiBJZiB5b3UgY2Fubm90IGRpc3RyaWJ1dGUgc28gYXMgdG8gc2F0aXNmeSBzaW11bHRhbmVvdXNseSB5b3VyIG9ibGlnYXRpb25zIHVuZGVyIHRoaXMgTGljZW5zZSBhbmQgYW55IG90aGVyIHBlcnRpbmVudCBvYmxpZ2F0aW9ucywgdGhlbiBhcyBhIGNvbnNlcXVlbmNlIHlvdSBtYXkgbm90IGRpc3RyaWJ1dGUgdGhlIFByb2dyYW0gYXQgYWxsLiBGb3IgZXhhbXBsZSwgaWYgYSBwYXRlbnQgbGljZW5zZSB3b3VsZCBub3QgcGVybWl0IHJveWFsdHktZnJlZSByZWRpc3RyaWJ1dGlvbiBvZiB0aGUgUHJvZ3JhbSBieSBhbGwgdGhvc2Ugd2hvIHJlY2VpdmUgY29waWVzIGRpcmVjdGx5IG9yIGluZGlyZWN0bHkgdGhyb3VnaCB5b3UsIHRoZW4gdGhlIG9ubHkgd2F5IHlvdSBjb3VsZCBzYXRpc2Z5IGJvdGggaXQgYW5kIHRoaXMgTGljZW5zZSB3b3VsZCBiZSB0byByZWZyYWluIGVudGlyZWx5IGZyb20gZGlzdHJpYnV0aW9uIG9mIHRoZSBQcm9ncmFtLgoKSWYgYW55IHBvcnRpb24gb2YgdGhpcyBzZWN0aW9uIGlzIGhlbGQgaW52YWxpZCBvciB1bmVuZm9yY2VhYmxlIHVuZGVyIGFueSBwYXJ0aWN1bGFyIGNpcmN1bXN0YW5jZSwgdGhlIGJhbGFuY2Ugb2YgdGhlIHNlY3Rpb24gaXMgaW50ZW5kZWQgdG8gYXBwbHkgYW5kIHRoZSBzZWN0aW9uIGFzIGEgd2hvbGUgaXMgaW50ZW5kZWQgdG8gYXBwbHkgaW4gb3RoZXIgY2lyY3Vtc3RhbmNlcy4KCkl0IGlzIG5vdCB0aGUgcHVycG9zZSBvZiB0aGlzIHNlY3Rpb24gdG8gaW5kdWNlIHlvdSB0byBpbmZyaW5nZSBhbnkgcGF0ZW50cyBvciBvdGhlciBwcm9wZXJ0eSByaWdodCBjbGFpbXMgb3IgdG8gY29udGVzdCB2YWxpZGl0eSBvZiBhbnkgc3VjaCBjbGFpbXM7IHRoaXMgc2VjdGlvbiBoYXMgdGhlIHNvbGUgcHVycG9zZSBvZiBwcm90ZWN0aW5nIHRoZSBpbnRlZ3JpdHkgb2YgdGhlIGZyZWUgc29mdHdhcmUgZGlzdHJpYnV0aW9uIHN5c3RlbSwgd2hpY2ggaXMgaW1wbGVtZW50ZWQgYnkgcHVibGljIGxpY2Vuc2UgcHJhY3RpY2VzLiBNYW55IHBlb3BsZSBoYXZlIG1hZGUgZ2VuZXJvdXMgY29udHJpYnV0aW9ucyB0byB0aGUgd2lkZSByYW5nZSBvZiBzb2Z0d2FyZSBkaXN0cmlidXRlZCB0aHJvdWdoIHRoYXQgc3lzdGVtIGluIHJlbGlhbmNlIG9uIGNvbnNpc3RlbnQgYXBwbGljYXRpb24gb2YgdGhhdCBzeXN0ZW07IGl0IGlzIHVwIHRvIHRoZSBhdXRob3IvZG9ub3IgdG8gZGVjaWRlIGlmIGhlIG9yIHNoZSBpcyB3aWxsaW5nIHRvIGRpc3RyaWJ1dGUgc29mdHdhcmUgdGhyb3VnaCBhbnkgb3RoZXIgc3lzdGVtIGFuZCBhIGxpY2Vuc2VlIGNhbm5vdCBpbXBvc2UgdGhhdCBjaG9pY2UuCgpUaGlzIHNlY3Rpb24gaXMgaW50ZW5kZWQgdG8gbWFrZSB0aG9yb3VnaGx5IGNsZWFyIHdoYXQgaXMgYmVsaWV2ZWQgdG8gYmUgYSBjb25zZXF1ZW5jZSBvZiB0aGUgcmVzdCBvZiB0aGlzIExpY2Vuc2UuCgo4LiBJZiB0aGUgZGlzdHJpYnV0aW9uIGFuZC9vciB1c2Ugb2YgdGhlIFByb2dyYW0gaXMgcmVzdHJpY3RlZCBpbiBjZXJ0YWluIGNvdW50cmllcyBlaXRoZXIgYnkgcGF0ZW50cyBvciBieSBjb3B5cmlnaHRlZCBpbnRlcmZhY2VzLCB0aGUgb3JpZ2luYWwgY29weXJpZ2h0IGhvbGRlciB3aG8gcGxhY2VzIHRoZSBQcm9ncmFtIHVuZGVyIHRoaXMgTGljZW5zZSBtYXkgYWRkIGFuIGV4cGxpY2l0IGdlb2dyYXBoaWNhbCBkaXN0cmlidXRpb24gbGltaXRhdGlvbiBleGNsdWRpbmcgdGhvc2UgY291bnRyaWVzLCBzbyB0aGF0IGRpc3RyaWJ1dGlvbiBpcyBwZXJtaXR0ZWQgb25seSBpbiBvciBhbW9uZyBjb3VudHJpZXMgbm90IHRodXMgZXhjbHVkZWQuIEluIHN1Y2ggY2FzZSwgdGhpcyBMaWNlbnNlIGluY29ycG9yYXRlcyB0aGUgbGltaXRhdGlvbiBhcyBpZiB3cml0dGVuIGluIHRoZSBib2R5IG9mIHRoaXMgTGljZW5zZS4KCjkuIFRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24gbWF5IHB1Ymxpc2ggcmV2aXNlZCBhbmQvb3IgbmV3IHZlcnNpb25zIG9mIHRoZSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZyb20gdGltZSB0byB0aW1lLiBTdWNoIG5ldyB2ZXJzaW9ucyB3aWxsIGJlIHNpbWlsYXIgaW4gc3Bpcml0IHRvIHRoZSBwcmVzZW50IHZlcnNpb24sIGJ1dCBtYXkgZGlmZmVyIGluIGRldGFpbCB0byBhZGRyZXNzIG5ldyBwcm9ibGVtcyBvciBjb25jZXJucy4KCkVhY2ggdmVyc2lvbiBpcyBnaXZlbiBhIGRpc3Rpbmd1aXNoaW5nIHZlcnNpb24gbnVtYmVyLiBJZiB0aGUgUHJvZ3JhbSBzcGVjaWZpZXMgYSB2ZXJzaW9uIG51bWJlciBvZiB0aGlzIExpY2Vuc2Ugd2hpY2ggYXBwbGllcyB0byBpdCBhbmQgImFueSBsYXRlciB2ZXJzaW9uIiwgeW91IGhhdmUgdGhlIG9wdGlvbiBvZiBmb2xsb3dpbmcgdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIGVpdGhlciBvZiB0aGF0IHZlcnNpb24gb3Igb2YgYW55IGxhdGVyIHZlcnNpb24gcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24uIElmIHRoZSBQcm9ncmFtIGRvZXMgbm90IHNwZWNpZnkgYSB2ZXJzaW9uIG51bWJlciBvZiB0aGlzIExpY2Vuc2UsIHlvdSBtYXkgY2hvb3NlIGFueSB2ZXJzaW9uIGV2ZXIgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24uCgoxMC4gSWYgeW91IHdpc2ggdG8gaW5jb3Jwb3JhdGUgcGFydHMgb2YgdGhlIFByb2dyYW0gaW50byBvdGhlciBmcmVlIHByb2dyYW1zIHdob3NlIGRpc3RyaWJ1dGlvbiBjb25kaXRpb25zIGFyZSBkaWZmZXJlbnQsIHdyaXRlIHRvIHRoZSBhdXRob3IgdG8gYXNrIGZvciBwZXJtaXNzaW9uLiBGb3Igc29mdHdhcmUgd2hpY2ggaXMgY29weXJpZ2h0ZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgd2Ugc29tZXRpbWVzIG1ha2UgZXhjZXB0aW9ucyBmb3IgdGhpcy4gT3VyIGRlY2lzaW9uIHdpbGwgYmUgZ3VpZGVkIGJ5IHRoZSB0d28gZ29hbHMgb2YgcHJlc2VydmluZyB0aGUgZnJlZSBzdGF0dXMgb2YgYWxsIGRlcml2YXRpdmVzIG9mIG91ciBmcmVlIHNvZnR3YXJlIGFuZCBvZiBwcm9tb3RpbmcgdGhlIHNoYXJpbmcgYW5kIHJldXNlIG9mIHNvZnR3YXJlIGdlbmVyYWxseS4KCk5PIFdBUlJBTlRZCgoxMS4gQkVDQVVTRSBUSEUgUFJPR1JBTSBJUyBMSUNFTlNFRCBGUkVFIE9GIENIQVJHRSwgVEhFUkUgSVMgTk8gV0FSUkFOVFkgRk9SIFRIRSBQUk9HUkFNLCBUTyBUSEUgRVhURU5UIFBFUk1JVFRFRCBCWSBBUFBMSUNBQkxFIExBVy4gRVhDRVBUIFdIRU4gT1RIRVJXSVNFIFNUQVRFRCBJTiBXUklUSU5HIFRIRSBDT1BZUklHSFQgSE9MREVSUyBBTkQvT1IgT1RIRVIgUEFSVElFUyBQUk9WSURFIFRIRSBQUk9HUkFNICJBUyBJUyIgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRUlUSEVSIEVYUFJFU1NFRCBPUiBJTVBMSUVELCBJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFIElNUExJRUQgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBUSEUgRU5USVJFIFJJU0sgQVMgVE8gVEhFIFFVQUxJVFkgQU5EIFBFUkZPUk1BTkNFIE9GIFRIRSBQUk9HUkFNIElTIFdJVEggWU9VLiBTSE9VTEQgVEhFIFBST0dSQU0gUFJPVkUgREVGRUNUSVZFLCBZT1UgQVNTVU1FIFRIRSBDT1NUIE9GIEFMTCBORUNFU1NBUlkgU0VSVklDSU5HLCBSRVBBSVIgT1IgQ09SUkVDVElPTi4KCjEyLiBJTiBOTyBFVkVOVCBVTkxFU1MgUkVRVUlSRUQgQlkgQVBQTElDQUJMRSBMQVcgT1IgQUdSRUVEIFRPIElOIFdSSVRJTkcgV0lMTCBBTlkgQ09QWVJJR0hUIEhPTERFUiwgT1IgQU5ZIE9USEVSIFBBUlRZIFdITyBNQVkgTU9ESUZZIEFORC9PUiBSRURJU1RSSUJVVEUgVEhFIFBST0dSQU0gQVMgUEVSTUlUVEVEIEFCT1ZFLCBCRSBMSUFCTEUgVE8gWU9VIEZPUiBEQU1BR0VTLCBJTkNMVURJTkcgQU5ZIEdFTkVSQUwsIFNQRUNJQUwsIElOQ0lERU5UQUwgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTIEFSSVNJTkcgT1VUIE9GIFRIRSBVU0UgT1IgSU5BQklMSVRZIFRPIFVTRSBUSEUgUFJPR1JBTSAoSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBMT1NTIE9GIERBVEEgT1IgREFUQSBCRUlORyBSRU5ERVJFRCBJTkFDQ1VSQVRFIE9SIExPU1NFUyBTVVNUQUlORUQgQlkgWU9VIE9SIFRISVJEIFBBUlRJRVMgT1IgQSBGQUlMVVJFIE9GIFRIRSBQUk9HUkFNIFRPIE9QRVJBVEUgV0lUSCBBTlkgT1RIRVIgUFJPR1JBTVMpLCBFVkVOIElGIFNVQ0ggSE9MREVSIE9SIE9USEVSIFBBUlRZIEhBUyBCRUVOIEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GIFNVQ0ggREFNQUdFUy4KCkVORCBPRiBURVJNUyBBTkQgQ09ORElUSU9OUwoKSG93IHRvIEFwcGx5IFRoZXNlIFRlcm1zIHRvIFlvdXIgTmV3IFByb2dyYW1zCgpJZiB5b3UgZGV2ZWxvcCBhIG5ldyBwcm9ncmFtLCBhbmQgeW91IHdhbnQgaXQgdG8gYmUgb2YgdGhlIGdyZWF0ZXN0IHBvc3NpYmxlIHVzZSB0byB0aGUgcHVibGljLCB0aGUgYmVzdCB3YXkgdG8gYWNoaWV2ZSB0aGlzIGlzIHRvIG1ha2UgaXQgZnJlZSBzb2Z0d2FyZSB3aGljaCBldmVyeW9uZSBjYW4gcmVkaXN0cmlidXRlIGFuZCBjaGFuZ2UgdW5kZXIgdGhlc2UgdGVybXMuCgpUbyBkbyBzbywgYXR0YWNoIHRoZSBmb2xsb3dpbmcgbm90aWNlcyB0byB0aGUgcHJvZ3JhbS4gSXQgaXMgc2FmZXN0IHRvIGF0dGFjaCB0aGVtIHRvIHRoZSBzdGFydCBvZiBlYWNoIHNvdXJjZSBmaWxlIHRvIG1vc3QgZWZmZWN0aXZlbHkgY29udmV5IHRoZSBleGNsdXNpb24gb2Ygd2FycmFudHk7IGFuZCBlYWNoIGZpbGUgc2hvdWxkIGhhdmUgYXQgbGVhc3QgdGhlICJjb3B5cmlnaHQiIGxpbmUgYW5kIGEgcG9pbnRlciB0byB3aGVyZSB0aGUgZnVsbCBub3RpY2UgaXMgZm91bmQuCgogICAgIG9uZSBsaW5lIHRvIGdpdmUgdGhlIHByb2dyYW0ncyBuYW1lIGFuZCBhbiBpZGVhIG9mIHdoYXQgaXQgZG9lcy4gQ29weXJpZ2h0IChDKSB5eXl5IG5hbWUgb2YgYXV0aG9yCgogICAgIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDIgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uCgogICAgIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4KCiAgICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIHByb2dyYW07IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAwMjExMC0xMzAxLCBVU0EuIEFsc28gYWRkIGluZm9ybWF0aW9uIG9uIGhvdyB0byBjb250YWN0IHlvdSBieSBlbGVjdHJvbmljIGFuZCBwYXBlciBtYWlsLgoKSWYgdGhlIHByb2dyYW0gaXMgaW50ZXJhY3RpdmUsIG1ha2UgaXQgb3V0cHV0IGEgc2hvcnQgbm90aWNlIGxpa2UgdGhpcyB3aGVuIGl0IHN0YXJ0cyBpbiBhbiBpbnRlcmFjdGl2ZSBtb2RlOgoKICAgICBHbm9tb3Zpc2lvbiB2ZXJzaW9uIDY5LCBDb3B5cmlnaHQgKEMpIHllYXIgbmFtZSBvZiBhdXRob3IgR25vbW92aXNpb24gY29tZXMgd2l0aCBBQlNPTFVURUxZIE5PIFdBUlJBTlRZOyBmb3IgZGV0YWlscyB0eXBlIGBzaG93IHcnLiBUaGlzIGlzIGZyZWUgc29mdHdhcmUsIGFuZCB5b3UgYXJlIHdlbGNvbWUgdG8gcmVkaXN0cmlidXRlIGl0IHVuZGVyIGNlcnRhaW4gY29uZGl0aW9uczsgdHlwZSBgc2hvdyBjJyBmb3IgZGV0YWlscy4KClRoZSBoeXBvdGhldGljYWwgY29tbWFuZHMgYHNob3cgdycgYW5kIGBzaG93IGMnIHNob3VsZCBzaG93IHRoZSBhcHByb3ByaWF0ZSBwYXJ0cyBvZiB0aGUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZS4gT2YgY291cnNlLCB0aGUgY29tbWFuZHMgeW91IHVzZSBtYXkgYmUgY2FsbGVkIHNvbWV0aGluZyBvdGhlciB0aGFuIGBzaG93IHcnIGFuZCBgc2hvdyBjJzsgdGhleSBjb3VsZCBldmVuIGJlIG1vdXNlLWNsaWNrcyBvciBtZW51IGl0ZW1zLS13aGF0ZXZlciBzdWl0cyB5b3VyIHByb2dyYW0uCgpZb3Ugc2hvdWxkIGFsc28gZ2V0IHlvdXIgZW1wbG95ZXIgKGlmIHlvdSB3b3JrIGFzIGEgcHJvZ3JhbW1lcikgb3IgeW91ciBzY2hvb2wsIGlmIGFueSwgdG8gc2lnbiBhICJjb3B5cmlnaHQgZGlzY2xhaW1lciIgZm9yIHRoZSBwcm9ncmFtLCBpZiBuZWNlc3NhcnkuIEhlcmUgaXMgYSBzYW1wbGU7IGFsdGVyIHRoZSBuYW1lczoKCiAgICAgWW95b2R5bmUsIEluYy4sIGhlcmVieSBkaXNjbGFpbXMgYWxsIGNvcHlyaWdodCBpbnRlcmVzdCBpbiB0aGUgcHJvZ3JhbSBgR25vbW92aXNpb24nICh3aGljaCBtYWtlcyBwYXNzZXMgYXQgY29tcGlsZXJzKSB3cml0dGVuIGJ5IEphbWVzIEhhY2tlci4KCnNpZ25hdHVyZSBvZiBUeSBDb29uLCAxIEFwcmlsIDE5ODkgVHkgQ29vbiwgUHJlc2lkZW50IG9mIFZpY2U="},"url":"https:\/\/www.gnu.org\/licenses\/old-licenses\/gpl-2.0-standalone.html"}}],"version":"1.0.0","cpe":"cpe:2.3:a:digitalbazaar:forge:1.0.0:*:*:*:*:node.js:*:*","purl":"pkg:npm\/npmjs\/node-forge@1.0.0","supplier":{"name":"npmjs"},"bom-ref":"node-forge_1.0.0_2cf1f98f-bef7-49e2-a410-4f8fcc4640ff","description":"","copyright":"","properties":[{"name":"component_id","value":"7"}]},{"name":"13781114","type":"library","licenses":[{"license":{"id":"CC-BY-SA-4.0","text":{"contentType":"text\/plain","encoding":"base64","content":"Q3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1TaGFyZUFsaWtlIDQuMCBJbnRlcm5hdGlvbmFsCgogQ3JlYXRpdmUgQ29tbW9ucyBDb3Jwb3JhdGlvbiAo4oCcQ3JlYXRpdmUgQ29tbW9uc+KAnSkgaXMgbm90IGEgbGF3IGZpcm0gYW5kIGRvZXMgbm90IHByb3ZpZGUgbGVnYWwgc2VydmljZXMgb3IgbGVnYWwgYWR2aWNlLiBEaXN0cmlidXRpb24gb2YgQ3JlYXRpdmUgQ29tbW9ucyBwdWJsaWMgbGljZW5zZXMgZG9lcyBub3QgY3JlYXRlIGEgbGF3eWVyLWNsaWVudCBvciBvdGhlciByZWxhdGlvbnNoaXAuIENyZWF0aXZlIENvbW1vbnMgbWFrZXMgaXRzIGxpY2Vuc2VzIGFuZCByZWxhdGVkIGluZm9ybWF0aW9uIGF2YWlsYWJsZSBvbiBhbiDigJxhcy1pc+KAnSBiYXNpcy4gQ3JlYXRpdmUgQ29tbW9ucyBnaXZlcyBubyB3YXJyYW50aWVzIHJlZ2FyZGluZyBpdHMgbGljZW5zZXMsIGFueSBtYXRlcmlhbCBsaWNlbnNlZCB1bmRlciB0aGVpciB0ZXJtcyBhbmQgY29uZGl0aW9ucywgb3IgYW55IHJlbGF0ZWQgaW5mb3JtYXRpb24uIENyZWF0aXZlIENvbW1vbnMgZGlzY2xhaW1zIGFsbCBsaWFiaWxpdHkgZm9yIGRhbWFnZXMgcmVzdWx0aW5nIGZyb20gdGhlaXIgdXNlIHRvIHRoZSBmdWxsZXN0IGV4dGVudCBwb3NzaWJsZS4KClVzaW5nIENyZWF0aXZlIENvbW1vbnMgUHVibGljIExpY2Vuc2VzCgpDcmVhdGl2ZSBDb21tb25zIHB1YmxpYyBsaWNlbnNlcyBwcm92aWRlIGEgc3RhbmRhcmQgc2V0IG9mIHRlcm1zIGFuZCBjb25kaXRpb25zIHRoYXQgY3JlYXRvcnMgYW5kIG90aGVyIHJpZ2h0cyBob2xkZXJzIG1heSB1c2UgdG8gc2hhcmUgb3JpZ2luYWwgd29ya3Mgb2YgYXV0aG9yc2hpcCBhbmQgb3RoZXIgbWF0ZXJpYWwgc3ViamVjdCB0byBjb3B5cmlnaHQgYW5kIGNlcnRhaW4gb3RoZXIgcmlnaHRzIHNwZWNpZmllZCBpbiB0aGUgcHVibGljIGxpY2Vuc2UgYmVsb3cuIFRoZSBmb2xsb3dpbmcgY29uc2lkZXJhdGlvbnMgYXJlIGZvciBpbmZvcm1hdGlvbmFsIHB1cnBvc2VzIG9ubHksIGFyZSBub3QgZXhoYXVzdGl2ZSwgYW5kIGRvIG5vdCBmb3JtIHBhcnQgb2Ygb3VyIGxpY2Vuc2VzLgoKQ29uc2lkZXJhdGlvbnMgZm9yIGxpY2Vuc29yczogT3VyIHB1YmxpYyBsaWNlbnNlcyBhcmUgaW50ZW5kZWQgZm9yIHVzZSBieSB0aG9zZSBhdXRob3JpemVkIHRvIGdpdmUgdGhlIHB1YmxpYyBwZXJtaXNzaW9uIHRvIHVzZSBtYXRlcmlhbCBpbiB3YXlzIG90aGVyd2lzZSByZXN0cmljdGVkIGJ5IGNvcHlyaWdodCBhbmQgY2VydGFpbiBvdGhlciByaWdodHMuIE91ciBsaWNlbnNlcyBhcmUgaXJyZXZvY2FibGUuIExpY2Vuc29ycyBzaG91bGQgcmVhZCBhbmQgdW5kZXJzdGFuZCB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YgdGhlIGxpY2Vuc2UgdGhleSBjaG9vc2UgYmVmb3JlIGFwcGx5aW5nIGl0LiBMaWNlbnNvcnMgc2hvdWxkIGFsc28gc2VjdXJlIGFsbCByaWdodHMgbmVjZXNzYXJ5IGJlZm9yZSBhcHBseWluZyBvdXIgbGljZW5zZXMgc28gdGhhdCB0aGUgcHVibGljIGNhbiByZXVzZSB0aGUgbWF0ZXJpYWwgYXMgZXhwZWN0ZWQuIExpY2Vuc29ycyBzaG91bGQgY2xlYXJseSBtYXJrIGFueSBtYXRlcmlhbCBub3Qgc3ViamVjdCB0byB0aGUgbGljZW5zZS4gVGhpcyBpbmNsdWRlcyBvdGhlciBDQy1saWNlbnNlZCBtYXRlcmlhbCwgb3IgbWF0ZXJpYWwgdXNlZCB1bmRlciBhbiBleGNlcHRpb24gb3IgbGltaXRhdGlvbiB0byBjb3B5cmlnaHQuIE1vcmUgY29uc2lkZXJhdGlvbnMgZm9yIGxpY2Vuc29ycy4KCkNvbnNpZGVyYXRpb25zIGZvciB0aGUgcHVibGljOiBCeSB1c2luZyBvbmUgb2Ygb3VyIHB1YmxpYyBsaWNlbnNlcywgYSBsaWNlbnNvciBncmFudHMgdGhlIHB1YmxpYyBwZXJtaXNzaW9uIHRvIHVzZSB0aGUgbGljZW5zZWQgbWF0ZXJpYWwgdW5kZXIgc3BlY2lmaWVkIHRlcm1zIGFuZCBjb25kaXRpb25zLiBJZiB0aGUgbGljZW5zb3LigJlzIHBlcm1pc3Npb24gaXMgbm90IG5lY2Vzc2FyeSBmb3IgYW55IHJlYXNvbuKAk2ZvciBleGFtcGxlLCBiZWNhdXNlIG9mIGFueSBhcHBsaWNhYmxlIGV4Y2VwdGlvbiBvciBsaW1pdGF0aW9uIHRvIGNvcHlyaWdodOKAk3RoZW4gdGhhdCB1c2UgaXMgbm90IHJlZ3VsYXRlZCBieSB0aGUgbGljZW5zZS4gT3VyIGxpY2Vuc2VzIGdyYW50IG9ubHkgcGVybWlzc2lvbnMgdW5kZXIgY29weXJpZ2h0IGFuZCBjZXJ0YWluIG90aGVyIHJpZ2h0cyB0aGF0IGEgbGljZW5zb3IgaGFzIGF1dGhvcml0eSB0byBncmFudC4gVXNlIG9mIHRoZSBsaWNlbnNlZCBtYXRlcmlhbCBtYXkgc3RpbGwgYmUgcmVzdHJpY3RlZCBmb3Igb3RoZXIgcmVhc29ucywgaW5jbHVkaW5nIGJlY2F1c2Ugb3RoZXJzIGhhdmUgY29weXJpZ2h0IG9yIG90aGVyIHJpZ2h0cyBpbiB0aGUgbWF0ZXJpYWwuIEEgbGljZW5zb3IgbWF5IG1ha2Ugc3BlY2lhbCByZXF1ZXN0cywgc3VjaCBhcyBhc2tpbmcgdGhhdCBhbGwgY2hhbmdlcyBiZSBtYXJrZWQgb3IgZGVzY3JpYmVkLgoKQWx0aG91Z2ggbm90IHJlcXVpcmVkIGJ5IG91ciBsaWNlbnNlcywgeW91IGFyZSBlbmNvdXJhZ2VkIHRvIHJlc3BlY3QgdGhvc2UgcmVxdWVzdHMgd2hlcmUgcmVhc29uYWJsZS4gTW9yZSBjb25zaWRlcmF0aW9ucyBmb3IgdGhlIHB1YmxpYy4KCkNyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tU2hhcmVBbGlrZSA0LjAgSW50ZXJuYXRpb25hbCBQdWJsaWMgTGljZW5zZQoKQnkgZXhlcmNpc2luZyB0aGUgTGljZW5zZWQgUmlnaHRzIChkZWZpbmVkIGJlbG93KSwgWW91IGFjY2VwdCBhbmQgYWdyZWUgdG8gYmUgYm91bmQgYnkgdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHRoaXMgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1TaGFyZUFsaWtlIDQuMCBJbnRlcm5hdGlvbmFsIFB1YmxpYyBMaWNlbnNlICgiUHVibGljIExpY2Vuc2UiKS4gVG8gdGhlIGV4dGVudCB0aGlzIFB1YmxpYyBMaWNlbnNlIG1heSBiZSBpbnRlcnByZXRlZCBhcyBhIGNvbnRyYWN0LCBZb3UgYXJlIGdyYW50ZWQgdGhlIExpY2Vuc2VkIFJpZ2h0cyBpbiBjb25zaWRlcmF0aW9uIG9mIFlvdXIgYWNjZXB0YW5jZSBvZiB0aGVzZSB0ZXJtcyBhbmQgY29uZGl0aW9ucywgYW5kIHRoZSBMaWNlbnNvciBncmFudHMgWW91IHN1Y2ggcmlnaHRzIGluIGNvbnNpZGVyYXRpb24gb2YgYmVuZWZpdHMgdGhlIExpY2Vuc29yIHJlY2VpdmVzIGZyb20gbWFraW5nIHRoZSBMaWNlbnNlZCBNYXRlcmlhbCBhdmFpbGFibGUgdW5kZXIgdGhlc2UgdGVybXMgYW5kIGNvbmRpdGlvbnMuCgpTZWN0aW9uIDEg4oCTIERlZmluaXRpb25zLgoKICAgICBhLglBZGFwdGVkIE1hdGVyaWFsIG1lYW5zIG1hdGVyaWFsIHN1YmplY3QgdG8gQ29weXJpZ2h0IGFuZCBTaW1pbGFyIFJpZ2h0cyB0aGF0IGlzIGRlcml2ZWQgZnJvbSBvciBiYXNlZCB1cG9uIHRoZSBMaWNlbnNlZCBNYXRlcmlhbCBhbmQgaW4gd2hpY2ggdGhlIExpY2Vuc2VkIE1hdGVyaWFsIGlzIHRyYW5zbGF0ZWQsIGFsdGVyZWQsIGFycmFuZ2VkLCB0cmFuc2Zvcm1lZCwgb3Igb3RoZXJ3aXNlIG1vZGlmaWVkIGluIGEgbWFubmVyIHJlcXVpcmluZyBwZXJtaXNzaW9uIHVuZGVyIHRoZSBDb3B5cmlnaHQgYW5kIFNpbWlsYXIgUmlnaHRzIGhlbGQgYnkgdGhlIExpY2Vuc29yLiBGb3IgcHVycG9zZXMgb2YgdGhpcyBQdWJsaWMgTGljZW5zZSwgd2hlcmUgdGhlIExpY2Vuc2VkIE1hdGVyaWFsIGlzIGEgbXVzaWNhbCB3b3JrLCBwZXJmb3JtYW5jZSwgb3Igc291bmQgcmVjb3JkaW5nLCBBZGFwdGVkIE1hdGVyaWFsIGlzIGFsd2F5cyBwcm9kdWNlZCB3aGVyZSB0aGUgTGljZW5zZWQgTWF0ZXJpYWwgaXMgc3luY2hlZCBpbiB0aW1lZCByZWxhdGlvbiB3aXRoIGEgbW92aW5nIGltYWdlLgoKICAgICBiLglBZGFwdGVyJ3MgTGljZW5zZSBtZWFucyB0aGUgbGljZW5zZSBZb3UgYXBwbHkgdG8gWW91ciBDb3B5cmlnaHQgYW5kIFNpbWlsYXIgUmlnaHRzIGluIFlvdXIgY29udHJpYnV0aW9ucyB0byBBZGFwdGVkIE1hdGVyaWFsIGluIGFjY29yZGFuY2Ugd2l0aCB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YgdGhpcyBQdWJsaWMgTGljZW5zZS4KCiAgICAgYy4JQlktU0EgQ29tcGF0aWJsZSBMaWNlbnNlIG1lYW5zIGEgbGljZW5zZSBsaXN0ZWQgYXQgY3JlYXRpdmVjb21tb25zLm9yZy9jb21wYXRpYmxlbGljZW5zZXMsIGFwcHJvdmVkIGJ5IENyZWF0aXZlIENvbW1vbnMgYXMgZXNzZW50aWFsbHkgdGhlIGVxdWl2YWxlbnQgb2YgdGhpcyBQdWJsaWMgTGljZW5zZS4KCiAgICAgZC4JQ29weXJpZ2h0IGFuZCBTaW1pbGFyIFJpZ2h0cyBtZWFucyBjb3B5cmlnaHQgYW5kL29yIHNpbWlsYXIgcmlnaHRzIGNsb3NlbHkgcmVsYXRlZCB0byBjb3B5cmlnaHQgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIHBlcmZvcm1hbmNlLCBicm9hZGNhc3QsIHNvdW5kIHJlY29yZGluZywgYW5kIFN1aSBHZW5lcmlzIERhdGFiYXNlIFJpZ2h0cywgd2l0aG91dCByZWdhcmQgdG8gaG93IHRoZSByaWdodHMgYXJlIGxhYmVsZWQgb3IgY2F0ZWdvcml6ZWQuIEZvciBwdXJwb3NlcyBvZiB0aGlzIFB1YmxpYyBMaWNlbnNlLCB0aGUgcmlnaHRzIHNwZWNpZmllZCBpbiBTZWN0aW9uIDIoYikoMSktKDIpIGFyZSBub3QgQ29weXJpZ2h0IGFuZCBTaW1pbGFyIFJpZ2h0cy4KCiAgICAgZS4JRWZmZWN0aXZlIFRlY2hub2xvZ2ljYWwgTWVhc3VyZXMgbWVhbnMgdGhvc2UgbWVhc3VyZXMgdGhhdCwgaW4gdGhlIGFic2VuY2Ugb2YgcHJvcGVyIGF1dGhvcml0eSwgbWF5IG5vdCBiZSBjaXJjdW12ZW50ZWQgdW5kZXIgbGF3cyBmdWxmaWxsaW5nIG9ibGlnYXRpb25zIHVuZGVyIEFydGljbGUgMTEgb2YgdGhlIFdJUE8gQ29weXJpZ2h0IFRyZWF0eSBhZG9wdGVkIG9uIERlY2VtYmVyIDIwLCAxOTk2LCBhbmQvb3Igc2ltaWxhciBpbnRlcm5hdGlvbmFsIGFncmVlbWVudHMuCgogICAgIGYuCUV4Y2VwdGlvbnMgYW5kIExpbWl0YXRpb25zIG1lYW5zIGZhaXIgdXNlLCBmYWlyIGRlYWxpbmcsIGFuZC9vciBhbnkgb3RoZXIgZXhjZXB0aW9uIG9yIGxpbWl0YXRpb24gdG8gQ29weXJpZ2h0IGFuZCBTaW1pbGFyIFJpZ2h0cyB0aGF0IGFwcGxpZXMgdG8gWW91ciB1c2Ugb2YgdGhlIExpY2Vuc2VkIE1hdGVyaWFsLgoKICAgICBnLglMaWNlbnNlIEVsZW1lbnRzIG1lYW5zIHRoZSBsaWNlbnNlIGF0dHJpYnV0ZXMgbGlzdGVkIGluIHRoZSBuYW1lIG9mIGEgQ3JlYXRpdmUgQ29tbW9ucyBQdWJsaWMgTGljZW5zZS4gVGhlIExpY2Vuc2UgRWxlbWVudHMgb2YgdGhpcyBQdWJsaWMgTGljZW5zZSBhcmUgQXR0cmlidXRpb24gYW5kIFNoYXJlQWxpa2UuCgogICAgIGguCUxpY2Vuc2VkIE1hdGVyaWFsIG1lYW5zIHRoZSBhcnRpc3RpYyBvciBsaXRlcmFyeSB3b3JrLCBkYXRhYmFzZSwgb3Igb3RoZXIgbWF0ZXJpYWwgdG8gd2hpY2ggdGhlIExpY2Vuc29yIGFwcGxpZWQgdGhpcyBQdWJsaWMgTGljZW5zZS4KCiAgICAgaS4JTGljZW5zZWQgUmlnaHRzIG1lYW5zIHRoZSByaWdodHMgZ3JhbnRlZCB0byBZb3Ugc3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YgdGhpcyBQdWJsaWMgTGljZW5zZSwgd2hpY2ggYXJlIGxpbWl0ZWQgdG8gYWxsIENvcHlyaWdodCBhbmQgU2ltaWxhciBSaWdodHMgdGhhdCBhcHBseSB0byBZb3VyIHVzZSBvZiB0aGUgTGljZW5zZWQgTWF0ZXJpYWwgYW5kIHRoYXQgdGhlIExpY2Vuc29yIGhhcyBhdXRob3JpdHkgdG8gbGljZW5zZS4KCiAgICAgai4JTGljZW5zb3IgbWVhbnMgdGhlIGluZGl2aWR1YWwocykgb3IgZW50aXR5KGllcykgZ3JhbnRpbmcgcmlnaHRzIHVuZGVyIHRoaXMgUHVibGljIExpY2Vuc2UuCgogICAgIGsuCVNoYXJlIG1lYW5zIHRvIHByb3ZpZGUgbWF0ZXJpYWwgdG8gdGhlIHB1YmxpYyBieSBhbnkgbWVhbnMgb3IgcHJvY2VzcyB0aGF0IHJlcXVpcmVzIHBlcm1pc3Npb24gdW5kZXIgdGhlIExpY2Vuc2VkIFJpZ2h0cywgc3VjaCBhcyByZXByb2R1Y3Rpb24sIHB1YmxpYyBkaXNwbGF5LCBwdWJsaWMgcGVyZm9ybWFuY2UsIGRpc3RyaWJ1dGlvbiwgZGlzc2VtaW5hdGlvbiwgY29tbXVuaWNhdGlvbiwgb3IgaW1wb3J0YXRpb24sIGFuZCB0byBtYWtlIG1hdGVyaWFsIGF2YWlsYWJsZSB0byB0aGUgcHVibGljIGluY2x1ZGluZyBpbiB3YXlzIHRoYXQgbWVtYmVycyBvZiB0aGUgcHVibGljIG1heSBhY2Nlc3MgdGhlIG1hdGVyaWFsIGZyb20gYSBwbGFjZSBhbmQgYXQgYSB0aW1lIGluZGl2aWR1YWxseSBjaG9zZW4gYnkgdGhlbS4KCiAgICAgbC4JU3VpIEdlbmVyaXMgRGF0YWJhc2UgUmlnaHRzIG1lYW5zIHJpZ2h0cyBvdGhlciB0aGFuIGNvcHlyaWdodCByZXN1bHRpbmcgZnJvbSBEaXJlY3RpdmUgOTYvOS9FQyBvZiB0aGUgRXVyb3BlYW4gUGFybGlhbWVudCBhbmQgb2YgdGhlIENvdW5jaWwgb2YgMTEgTWFyY2ggMTk5NiBvbiB0aGUgbGVnYWwgcHJvdGVjdGlvbiBvZiBkYXRhYmFzZXMsIGFzIGFtZW5kZWQgYW5kL29yIHN1Y2NlZWRlZCwgYXMgd2VsbCBhcyBvdGhlciBlc3NlbnRpYWxseSBlcXVpdmFsZW50IHJpZ2h0cyBhbnl3aGVyZSBpbiB0aGUgd29ybGQuCgogICAgIG0uCVlvdSBtZWFucyB0aGUgaW5kaXZpZHVhbCBvciBlbnRpdHkgZXhlcmNpc2luZyB0aGUgTGljZW5zZWQgUmlnaHRzIHVuZGVyIHRoaXMgUHVibGljIExpY2Vuc2UuIFlvdXIgaGFzIGEgY29ycmVzcG9uZGluZyBtZWFuaW5nLgoKU2VjdGlvbiAyIOKAkyBTY29wZS4KCiAgICAgYS4JTGljZW5zZSBncmFudC4KCiAgICAgICAgICAxLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB0aGlzIFB1YmxpYyBMaWNlbnNlLCB0aGUgTGljZW5zb3IgaGVyZWJ5IGdyYW50cyBZb3UgYSB3b3JsZHdpZGUsIHJveWFsdHktZnJlZSwgbm9uLXN1YmxpY2Vuc2FibGUsIG5vbi1leGNsdXNpdmUsIGlycmV2b2NhYmxlIGxpY2Vuc2UgdG8gZXhlcmNpc2UgdGhlIExpY2Vuc2VkIFJpZ2h0cyBpbiB0aGUgTGljZW5zZWQgTWF0ZXJpYWwgdG86CgogICAgICAgICAgICAgICBBLiByZXByb2R1Y2UgYW5kIFNoYXJlIHRoZSBMaWNlbnNlZCBNYXRlcmlhbCwgaW4gd2hvbGUgb3IgaW4gcGFydDsgYW5kCgogICAgICAgICAgICAgICBCLiBwcm9kdWNlLCByZXByb2R1Y2UsIGFuZCBTaGFyZSBBZGFwdGVkIE1hdGVyaWFsLgoKICAgICAgICAgIDIuIEV4Y2VwdGlvbnMgYW5kIExpbWl0YXRpb25zLiBGb3IgdGhlIGF2b2lkYW5jZSBvZiBkb3VidCwgd2hlcmUgRXhjZXB0aW9ucyBhbmQgTGltaXRhdGlvbnMgYXBwbHkgdG8gWW91ciB1c2UsIHRoaXMgUHVibGljIExpY2Vuc2UgZG9lcyBub3QgYXBwbHksIGFuZCBZb3UgZG8gbm90IG5lZWQgdG8gY29tcGx5IHdpdGggaXRzIHRlcm1zIGFuZCBjb25kaXRpb25zLgoKICAgICAgICAgIDMuIFRlcm0uIFRoZSB0ZXJtIG9mIHRoaXMgUHVibGljIExpY2Vuc2UgaXMgc3BlY2lmaWVkIGluIFNlY3Rpb24gNihhKS4KCiAgICAgICAgICA0LiBNZWRpYSBhbmQgZm9ybWF0czsgdGVjaG5pY2FsIG1vZGlmaWNhdGlvbnMgYWxsb3dlZC4gVGhlIExpY2Vuc29yIGF1dGhvcml6ZXMgWW91IHRvIGV4ZXJjaXNlIHRoZSBMaWNlbnNlZCBSaWdodHMgaW4gYWxsIG1lZGlhIGFuZCBmb3JtYXRzIHdoZXRoZXIgbm93IGtub3duIG9yIGhlcmVhZnRlciBjcmVhdGVkLCBhbmQgdG8gbWFrZSB0ZWNobmljYWwgbW9kaWZpY2F0aW9ucyBuZWNlc3NhcnkgdG8gZG8gc28uIFRoZSBMaWNlbnNvciB3YWl2ZXMgYW5kL29yIGFncmVlcyBub3QgdG8gYXNzZXJ0IGFueSByaWdodCBvciBhdXRob3JpdHkgdG8gZm9yYmlkIFlvdSBmcm9tIG1ha2luZyB0ZWNobmljYWwgbW9kaWZpY2F0aW9ucyBuZWNlc3NhcnkgdG8gZXhlcmNpc2UgdGhlIExpY2Vuc2VkIFJpZ2h0cywgaW5jbHVkaW5nIHRlY2huaWNhbCBtb2RpZmljYXRpb25zIG5lY2Vzc2FyeSB0byBjaXJjdW12ZW50IEVmZmVjdGl2ZSBUZWNobm9sb2dpY2FsIE1lYXN1cmVzLiBGb3IgcHVycG9zZXMgb2YgdGhpcyBQdWJsaWMgTGljZW5zZSwgc2ltcGx5IG1ha2luZyBtb2RpZmljYXRpb25zIGF1dGhvcml6ZWQgYnkgdGhpcyBTZWN0aW9uIDIoYSkoNCkgbmV2ZXIgcHJvZHVjZXMgQWRhcHRlZCBNYXRlcmlhbC4KCiAgICAgICAgICA1LiBEb3duc3RyZWFtIHJlY2lwaWVudHMuCgogICAgICAgICAgICAgICBBLiBPZmZlciBmcm9tIHRoZSBMaWNlbnNvciDigJMgTGljZW5zZWQgTWF0ZXJpYWwuIEV2ZXJ5IHJlY2lwaWVudCBvZiB0aGUgTGljZW5zZWQgTWF0ZXJpYWwgYXV0b21hdGljYWxseSByZWNlaXZlcyBhbiBvZmZlciBmcm9tIHRoZSBMaWNlbnNvciB0byBleGVyY2lzZSB0aGUgTGljZW5zZWQgUmlnaHRzIHVuZGVyIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB0aGlzIFB1YmxpYyBMaWNlbnNlLgoKICAgICAgICAgICAgICAgQi4gQWRkaXRpb25hbCBvZmZlciBmcm9tIHRoZSBMaWNlbnNvciDigJMgQWRhcHRlZCBNYXRlcmlhbC4gRXZlcnkgcmVjaXBpZW50IG9mIEFkYXB0ZWQgTWF0ZXJpYWwgZnJvbSBZb3UgYXV0b21hdGljYWxseSByZWNlaXZlcyBhbiBvZmZlciBmcm9tIHRoZSBMaWNlbnNvciB0byBleGVyY2lzZSB0aGUgTGljZW5zZWQgUmlnaHRzIGluIHRoZSBBZGFwdGVkIE1hdGVyaWFsIHVuZGVyIHRoZSBjb25kaXRpb25zIG9mIHRoZSBBZGFwdGVy4oCZcyBMaWNlbnNlIFlvdSBhcHBseS4KCiAgICAgICAgICAgICAgIEMuIE5vIGRvd25zdHJlYW0gcmVzdHJpY3Rpb25zLiBZb3UgbWF5IG5vdCBvZmZlciBvciBpbXBvc2UgYW55IGFkZGl0aW9uYWwgb3IgZGlmZmVyZW50IHRlcm1zIG9yIGNvbmRpdGlvbnMgb24sIG9yIGFwcGx5IGFueSBFZmZlY3RpdmUgVGVjaG5vbG9naWNhbCBNZWFzdXJlcyB0bywgdGhlIExpY2Vuc2VkIE1hdGVyaWFsIGlmIGRvaW5nIHNvIHJlc3RyaWN0cyBleGVyY2lzZSBvZiB0aGUgTGljZW5zZWQgUmlnaHRzIGJ5IGFueSByZWNpcGllbnQgb2YgdGhlIExpY2Vuc2VkIE1hdGVyaWFsLgoKICAgICAgICAgIDYuIE5vIGVuZG9yc2VtZW50LiBOb3RoaW5nIGluIHRoaXMgUHVibGljIExpY2Vuc2UgY29uc3RpdHV0ZXMgb3IgbWF5IGJlIGNvbnN0cnVlZCBhcyBwZXJtaXNzaW9uIHRvIGFzc2VydCBvciBpbXBseSB0aGF0IFlvdSBhcmUsIG9yIHRoYXQgWW91ciB1c2Ugb2YgdGhlIExpY2Vuc2VkIE1hdGVyaWFsIGlzLCBjb25uZWN0ZWQgd2l0aCwgb3Igc3BvbnNvcmVkLCBlbmRvcnNlZCwgb3IgZ3JhbnRlZCBvZmZpY2lhbCBzdGF0dXMgYnksIHRoZSBMaWNlbnNvciBvciBvdGhlcnMgZGVzaWduYXRlZCB0byByZWNlaXZlIGF0dHJpYnV0aW9uIGFzIHByb3ZpZGVkIGluIFNlY3Rpb24gMyhhKSgxKShBKShpKS4KCiAgICAgYi4JT3RoZXIgcmlnaHRzLgoKICAgICAgICAgIDEuIE1vcmFsIHJpZ2h0cywgc3VjaCBhcyB0aGUgcmlnaHQgb2YgaW50ZWdyaXR5LCBhcmUgbm90IGxpY2Vuc2VkIHVuZGVyIHRoaXMgUHVibGljIExpY2Vuc2UsIG5vciBhcmUgcHVibGljaXR5LCBwcml2YWN5LCBhbmQvb3Igb3RoZXIgc2ltaWxhciBwZXJzb25hbGl0eSByaWdodHM7IGhvd2V2ZXIsIHRvIHRoZSBleHRlbnQgcG9zc2libGUsIHRoZSBMaWNlbnNvciB3YWl2ZXMgYW5kL29yIGFncmVlcyBub3QgdG8gYXNzZXJ0IGFueSBzdWNoIHJpZ2h0cyBoZWxkIGJ5IHRoZSBMaWNlbnNvciB0byB0aGUgbGltaXRlZCBleHRlbnQgbmVjZXNzYXJ5IHRvIGFsbG93IFlvdSB0byBleGVyY2lzZSB0aGUgTGljZW5zZWQgUmlnaHRzLCBidXQgbm90IG90aGVyd2lzZS4KCiAgICAgICAgICAyLiBQYXRlbnQgYW5kIHRyYWRlbWFyayByaWdodHMgYXJlIG5vdCBsaWNlbnNlZCB1bmRlciB0aGlzIFB1YmxpYyBMaWNlbnNlLgoKICAgICAgICAgIDMuIFRvIHRoZSBleHRlbnQgcG9zc2libGUsIHRoZSBMaWNlbnNvciB3YWl2ZXMgYW55IHJpZ2h0IHRvIGNvbGxlY3Qgcm95YWx0aWVzIGZyb20gWW91IGZvciB0aGUgZXhlcmNpc2Ugb2YgdGhlIExpY2Vuc2VkIFJpZ2h0cywgd2hldGhlciBkaXJlY3RseSBvciB0aHJvdWdoIGEgY29sbGVjdGluZyBzb2NpZXR5IHVuZGVyIGFueSB2b2x1bnRhcnkgb3Igd2FpdmFibGUgc3RhdHV0b3J5IG9yIGNvbXB1bHNvcnkgbGljZW5zaW5nIHNjaGVtZS4gSW4gYWxsIG90aGVyIGNhc2VzIHRoZSBMaWNlbnNvciBleHByZXNzbHkgcmVzZXJ2ZXMgYW55IHJpZ2h0IHRvIGNvbGxlY3Qgc3VjaCByb3lhbHRpZXMuCgpTZWN0aW9uIDMg4oCTIExpY2Vuc2UgQ29uZGl0aW9ucy4KCllvdXIgZXhlcmNpc2Ugb2YgdGhlIExpY2Vuc2VkIFJpZ2h0cyBpcyBleHByZXNzbHkgbWFkZSBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9ucy4KCiAgICAgYS4JQXR0cmlidXRpb24uCgogICAgICAgICAgMS4gSWYgWW91IFNoYXJlIHRoZSBMaWNlbnNlZCBNYXRlcmlhbCAoaW5jbHVkaW5nIGluIG1vZGlmaWVkIGZvcm0pLCBZb3UgbXVzdDoKCiAgICAgICAgICAgICAgIEEuIHJldGFpbiB0aGUgZm9sbG93aW5nIGlmIGl0IGlzIHN1cHBsaWVkIGJ5IHRoZSBMaWNlbnNvciB3aXRoIHRoZSBMaWNlbnNlZCBNYXRlcmlhbDoKCiAgICAgICAgICAgICAgICAgICAgaS4JaWRlbnRpZmljYXRpb24gb2YgdGhlIGNyZWF0b3Iocykgb2YgdGhlIExpY2Vuc2VkIE1hdGVyaWFsIGFuZCBhbnkgb3RoZXJzIGRlc2lnbmF0ZWQgdG8gcmVjZWl2ZSBhdHRyaWJ1dGlvbiwgaW4gYW55IHJlYXNvbmFibGUgbWFubmVyIHJlcXVlc3RlZCBieSB0aGUgTGljZW5zb3IgKGluY2x1ZGluZyBieSBwc2V1ZG9ueW0gaWYgZGVzaWduYXRlZCk7CgogICAgICAgICAgICAgICAgICAgIGlpLglhIGNvcHlyaWdodCBub3RpY2U7CgogICAgICAgICAgICAgICAgICAgIGlpaS4gYSBub3RpY2UgdGhhdCByZWZlcnMgdG8gdGhpcyBQdWJsaWMgTGljZW5zZTsKCiAgICAgICAgICAgICAgICAgICAgaXYuCWEgbm90aWNlIHRoYXQgcmVmZXJzIHRvIHRoZSBkaXNjbGFpbWVyIG9mIHdhcnJhbnRpZXM7CgogICAgICAgICAgICAgICAgICAgIHYuCWEgVVJJIG9yIGh5cGVybGluayB0byB0aGUgTGljZW5zZWQgTWF0ZXJpYWwgdG8gdGhlIGV4dGVudCByZWFzb25hYmx5IHByYWN0aWNhYmxlOwoKICAgICAgICAgICAgICAgQi4gaW5kaWNhdGUgaWYgWW91IG1vZGlmaWVkIHRoZSBMaWNlbnNlZCBNYXRlcmlhbCBhbmQgcmV0YWluIGFuIGluZGljYXRpb24gb2YgYW55IHByZXZpb3VzIG1vZGlmaWNhdGlvbnM7IGFuZAoKICAgICAgICAgICAgICAgQy4gaW5kaWNhdGUgdGhlIExpY2Vuc2VkIE1hdGVyaWFsIGlzIGxpY2Vuc2VkIHVuZGVyIHRoaXMgUHVibGljIExpY2Vuc2UsIGFuZCBpbmNsdWRlIHRoZSB0ZXh0IG9mLCBvciB0aGUgVVJJIG9yIGh5cGVybGluayB0bywgdGhpcyBQdWJsaWMgTGljZW5zZS4KCiAgICAgICAgICAyLiBZb3UgbWF5IHNhdGlzZnkgdGhlIGNvbmRpdGlvbnMgaW4gU2VjdGlvbiAzKGEpKDEpIGluIGFueSByZWFzb25hYmxlIG1hbm5lciBiYXNlZCBvbiB0aGUgbWVkaXVtLCBtZWFucywgYW5kIGNvbnRleHQgaW4gd2hpY2ggWW91IFNoYXJlIHRoZSBMaWNlbnNlZCBNYXRlcmlhbC4gRm9yIGV4YW1wbGUsIGl0IG1heSBiZSByZWFzb25hYmxlIHRvIHNhdGlzZnkgdGhlIGNvbmRpdGlvbnMgYnkgcHJvdmlkaW5nIGEgVVJJIG9yIGh5cGVybGluayB0byBhIHJlc291cmNlIHRoYXQgaW5jbHVkZXMgdGhlIHJlcXVpcmVkIGluZm9ybWF0aW9uLgoKICAgICAgICAgIDMuIElmIHJlcXVlc3RlZCBieSB0aGUgTGljZW5zb3IsIFlvdSBtdXN0IHJlbW92ZSBhbnkgb2YgdGhlIGluZm9ybWF0aW9uIHJlcXVpcmVkIGJ5IFNlY3Rpb24gMyhhKSgxKShBKSB0byB0aGUgZXh0ZW50IHJlYXNvbmFibHkgcHJhY3RpY2FibGUuCgogICAgIGIuCVNoYXJlQWxpa2UuSW4gYWRkaXRpb24gdG8gdGhlIGNvbmRpdGlvbnMgaW4gU2VjdGlvbiAzKGEpLCBpZiBZb3UgU2hhcmUgQWRhcHRlZCBNYXRlcmlhbCBZb3UgcHJvZHVjZSwgdGhlIGZvbGxvd2luZyBjb25kaXRpb25zIGFsc28gYXBwbHkuCgogICAgICAgICAgMS4gVGhlIEFkYXB0ZXLigJlzIExpY2Vuc2UgWW91IGFwcGx5IG11c3QgYmUgYSBDcmVhdGl2ZSBDb21tb25zIGxpY2Vuc2Ugd2l0aCB0aGUgc2FtZSBMaWNlbnNlIEVsZW1lbnRzLCB0aGlzIHZlcnNpb24gb3IgbGF0ZXIsIG9yIGEgQlktU0EgQ29tcGF0aWJsZSBMaWNlbnNlLgoKICAgICAgICAgIDIuIFlvdSBtdXN0IGluY2x1ZGUgdGhlIHRleHQgb2YsIG9yIHRoZSBVUkkgb3IgaHlwZXJsaW5rIHRvLCB0aGUgQWRhcHRlcidzIExpY2Vuc2UgWW91IGFwcGx5LiBZb3UgbWF5IHNhdGlzZnkgdGhpcyBjb25kaXRpb24gaW4gYW55IHJlYXNvbmFibGUgbWFubmVyIGJhc2VkIG9uIHRoZSBtZWRpdW0sIG1lYW5zLCBhbmQgY29udGV4dCBpbiB3aGljaCBZb3UgU2hhcmUgQWRhcHRlZCBNYXRlcmlhbC4KCiAgICAgICAgICAzLiBZb3UgbWF5IG5vdCBvZmZlciBvciBpbXBvc2UgYW55IGFkZGl0aW9uYWwgb3IgZGlmZmVyZW50IHRlcm1zIG9yIGNvbmRpdGlvbnMgb24sIG9yIGFwcGx5IGFueSBFZmZlY3RpdmUgVGVjaG5vbG9naWNhbCBNZWFzdXJlcyB0bywgQWRhcHRlZCBNYXRlcmlhbCB0aGF0IHJlc3RyaWN0IGV4ZXJjaXNlIG9mIHRoZSByaWdodHMgZ3JhbnRlZCB1bmRlciB0aGUgQWRhcHRlcidzIExpY2Vuc2UgWW91IGFwcGx5LgoKU2VjdGlvbiA0IOKAkyBTdWkgR2VuZXJpcyBEYXRhYmFzZSBSaWdodHMuCgpXaGVyZSB0aGUgTGljZW5zZWQgUmlnaHRzIGluY2x1ZGUgU3VpIEdlbmVyaXMgRGF0YWJhc2UgUmlnaHRzIHRoYXQgYXBwbHkgdG8gWW91ciB1c2Ugb2YgdGhlIExpY2Vuc2VkIE1hdGVyaWFsOgoKICAgICBhLglmb3IgdGhlIGF2b2lkYW5jZSBvZiBkb3VidCwgU2VjdGlvbiAyKGEpKDEpIGdyYW50cyBZb3UgdGhlIHJpZ2h0IHRvIGV4dHJhY3QsIHJldXNlLCByZXByb2R1Y2UsIGFuZCBTaGFyZSBhbGwgb3IgYSBzdWJzdGFudGlhbCBwb3J0aW9uIG9mIHRoZSBjb250ZW50cyBvZiB0aGUgZGF0YWJhc2U7CgogICAgIGIuCWlmIFlvdSBpbmNsdWRlIGFsbCBvciBhIHN1YnN0YW50aWFsIHBvcnRpb24gb2YgdGhlIGRhdGFiYXNlIGNvbnRlbnRzIGluIGEgZGF0YWJhc2UgaW4gd2hpY2ggWW91IGhhdmUgU3VpIEdlbmVyaXMgRGF0YWJhc2UgUmlnaHRzLCB0aGVuIHRoZSBkYXRhYmFzZSBpbiB3aGljaCBZb3UgaGF2ZSBTdWkgR2VuZXJpcyBEYXRhYmFzZSBSaWdodHMgKGJ1dCBub3QgaXRzIGluZGl2aWR1YWwgY29udGVudHMpIGlzIEFkYXB0ZWQgTWF0ZXJpYWwsIGluY2x1ZGluZyBmb3IgcHVycG9zZXMgb2YgU2VjdGlvbiAzKGIpOyBhbmQKCiAgICAgYy4JWW91IG11c3QgY29tcGx5IHdpdGggdGhlIGNvbmRpdGlvbnMgaW4gU2VjdGlvbiAzKGEpIGlmIFlvdSBTaGFyZSBhbGwgb3IgYSBzdWJzdGFudGlhbCBwb3J0aW9uIG9mIHRoZSBjb250ZW50cyBvZiB0aGUgZGF0YWJhc2UuCkZvciB0aGUgYXZvaWRhbmNlIG9mIGRvdWJ0LCB0aGlzIFNlY3Rpb24gNCBzdXBwbGVtZW50cyBhbmQgZG9lcyBub3QgcmVwbGFjZSBZb3VyIG9ibGlnYXRpb25zIHVuZGVyIHRoaXMgUHVibGljIExpY2Vuc2Ugd2hlcmUgdGhlIExpY2Vuc2VkIFJpZ2h0cyBpbmNsdWRlIG90aGVyIENvcHlyaWdodCBhbmQgU2ltaWxhciBSaWdodHMuCgpTZWN0aW9uIDUg4oCTIERpc2NsYWltZXIgb2YgV2FycmFudGllcyBhbmQgTGltaXRhdGlvbiBvZiBMaWFiaWxpdHkuCgogICAgIGEuCVVubGVzcyBvdGhlcndpc2Ugc2VwYXJhdGVseSB1bmRlcnRha2VuIGJ5IHRoZSBMaWNlbnNvciwgdG8gdGhlIGV4dGVudCBwb3NzaWJsZSwgdGhlIExpY2Vuc29yIG9mZmVycyB0aGUgTGljZW5zZWQgTWF0ZXJpYWwgYXMtaXMgYW5kIGFzLWF2YWlsYWJsZSwgYW5kIG1ha2VzIG5vIHJlcHJlc2VudGF0aW9ucyBvciB3YXJyYW50aWVzIG9mIGFueSBraW5kIGNvbmNlcm5pbmcgdGhlIExpY2Vuc2VkIE1hdGVyaWFsLCB3aGV0aGVyIGV4cHJlc3MsIGltcGxpZWQsIHN0YXR1dG9yeSwgb3Igb3RoZXIuIFRoaXMgaW5jbHVkZXMsIHdpdGhvdXQgbGltaXRhdGlvbiwgd2FycmFudGllcyBvZiB0aXRsZSwgbWVyY2hhbnRhYmlsaXR5LCBmaXRuZXNzIGZvciBhIHBhcnRpY3VsYXIgcHVycG9zZSwgbm9uLWluZnJpbmdlbWVudCwgYWJzZW5jZSBvZiBsYXRlbnQgb3Igb3RoZXIgZGVmZWN0cywgYWNjdXJhY3ksIG9yIHRoZSBwcmVzZW5jZSBvciBhYnNlbmNlIG9mIGVycm9ycywgd2hldGhlciBvciBub3Qga25vd24gb3IgZGlzY292ZXJhYmxlLiBXaGVyZSBkaXNjbGFpbWVycyBvZiB3YXJyYW50aWVzIGFyZSBub3QgYWxsb3dlZCBpbiBmdWxsIG9yIGluIHBhcnQsIHRoaXMgZGlzY2xhaW1lciBtYXkgbm90IGFwcGx5IHRvIFlvdS4KCiAgICAgYi4JVG8gdGhlIGV4dGVudCBwb3NzaWJsZSwgaW4gbm8gZXZlbnQgd2lsbCB0aGUgTGljZW5zb3IgYmUgbGlhYmxlIHRvIFlvdSBvbiBhbnkgbGVnYWwgdGhlb3J5IChpbmNsdWRpbmcsIHdpdGhvdXQgbGltaXRhdGlvbiwgbmVnbGlnZW5jZSkgb3Igb3RoZXJ3aXNlIGZvciBhbnkgZGlyZWN0LCBzcGVjaWFsLCBpbmRpcmVjdCwgaW5jaWRlbnRhbCwgY29uc2VxdWVudGlhbCwgcHVuaXRpdmUsIGV4ZW1wbGFyeSwgb3Igb3RoZXIgbG9zc2VzLCBjb3N0cywgZXhwZW5zZXMsIG9yIGRhbWFnZXMgYXJpc2luZyBvdXQgb2YgdGhpcyBQdWJsaWMgTGljZW5zZSBvciB1c2Ugb2YgdGhlIExpY2Vuc2VkIE1hdGVyaWFsLCBldmVuIGlmIHRoZSBMaWNlbnNvciBoYXMgYmVlbiBhZHZpc2VkIG9mIHRoZSBwb3NzaWJpbGl0eSBvZiBzdWNoIGxvc3NlcywgY29zdHMsIGV4cGVuc2VzLCBvciBkYW1hZ2VzLiBXaGVyZSBhIGxpbWl0YXRpb24gb2YgbGlhYmlsaXR5IGlzIG5vdCBhbGxvd2VkIGluIGZ1bGwgb3IgaW4gcGFydCwgdGhpcyBsaW1pdGF0aW9uIG1heSBub3QgYXBwbHkgdG8gWW91LgoKICAgICBjLglUaGUgZGlzY2xhaW1lciBvZiB3YXJyYW50aWVzIGFuZCBsaW1pdGF0aW9uIG9mIGxpYWJpbGl0eSBwcm92aWRlZCBhYm92ZSBzaGFsbCBiZSBpbnRlcnByZXRlZCBpbiBhIG1hbm5lciB0aGF0LCB0byB0aGUgZXh0ZW50IHBvc3NpYmxlLCBtb3N0IGNsb3NlbHkgYXBwcm94aW1hdGVzIGFuIGFic29sdXRlIGRpc2NsYWltZXIgYW5kIHdhaXZlciBvZiBhbGwgbGlhYmlsaXR5LgoKU2VjdGlvbiA2IOKAkyBUZXJtIGFuZCBUZXJtaW5hdGlvbi4KCiAgICAgYS4JVGhpcyBQdWJsaWMgTGljZW5zZSBhcHBsaWVzIGZvciB0aGUgdGVybSBvZiB0aGUgQ29weXJpZ2h0IGFuZCBTaW1pbGFyIFJpZ2h0cyBsaWNlbnNlZCBoZXJlLiBIb3dldmVyLCBpZiBZb3UgZmFpbCB0byBjb21wbHkgd2l0aCB0aGlzIFB1YmxpYyBMaWNlbnNlLCB0aGVuIFlvdXIgcmlnaHRzIHVuZGVyIHRoaXMgUHVibGljIExpY2Vuc2UgdGVybWluYXRlIGF1dG9tYXRpY2FsbHkuCgogICAgIGIuCVdoZXJlIFlvdXIgcmlnaHQgdG8gdXNlIHRoZSBMaWNlbnNlZCBNYXRlcmlhbCBoYXMgdGVybWluYXRlZCB1bmRlciBTZWN0aW9uIDYoYSksIGl0IHJlaW5zdGF0ZXM6CgogICAgICAgICAgMS4gYXV0b21hdGljYWxseSBhcyBvZiB0aGUgZGF0ZSB0aGUgdmlvbGF0aW9uIGlzIGN1cmVkLCBwcm92aWRlZCBpdCBpcyBjdXJlZCB3aXRoaW4gMzAgZGF5cyBvZiBZb3VyIGRpc2NvdmVyeSBvZiB0aGUgdmlvbGF0aW9uOyBvcgoKICAgICAgICAgIDIuIHVwb24gZXhwcmVzcyByZWluc3RhdGVtZW50IGJ5IHRoZSBMaWNlbnNvci4KCiAgICAgYy4JRm9yIHRoZSBhdm9pZGFuY2Ugb2YgZG91YnQsIHRoaXMgU2VjdGlvbiA2KGIpIGRvZXMgbm90IGFmZmVjdCBhbnkgcmlnaHQgdGhlIExpY2Vuc29yIG1heSBoYXZlIHRvIHNlZWsgcmVtZWRpZXMgZm9yIFlvdXIgdmlvbGF0aW9ucyBvZiB0aGlzIFB1YmxpYyBMaWNlbnNlLgoKICAgICBkLglGb3IgdGhlIGF2b2lkYW5jZSBvZiBkb3VidCwgdGhlIExpY2Vuc29yIG1heSBhbHNvIG9mZmVyIHRoZSBMaWNlbnNlZCBNYXRlcmlhbCB1bmRlciBzZXBhcmF0ZSB0ZXJtcyBvciBjb25kaXRpb25zIG9yIHN0b3AgZGlzdHJpYnV0aW5nIHRoZSBMaWNlbnNlZCBNYXRlcmlhbCBhdCBhbnkgdGltZTsgaG93ZXZlciwgZG9pbmcgc28gd2lsbCBub3QgdGVybWluYXRlIHRoaXMgUHVibGljIExpY2Vuc2UuCgogICAgIGUuCVNlY3Rpb25zIDEsIDUsIDYsIDcsIGFuZCA4IHN1cnZpdmUgdGVybWluYXRpb24gb2YgdGhpcyBQdWJsaWMgTGljZW5zZS4KClNlY3Rpb24gNyDigJMgT3RoZXIgVGVybXMgYW5kIENvbmRpdGlvbnMuCgogICAgIGEuCVRoZSBMaWNlbnNvciBzaGFsbCBub3QgYmUgYm91bmQgYnkgYW55IGFkZGl0aW9uYWwgb3IgZGlmZmVyZW50IHRlcm1zIG9yIGNvbmRpdGlvbnMgY29tbXVuaWNhdGVkIGJ5IFlvdSB1bmxlc3MgZXhwcmVzc2x5IGFncmVlZC4KCiAgICAgYi4JQW55IGFycmFuZ2VtZW50cywgdW5kZXJzdGFuZGluZ3MsIG9yIGFncmVlbWVudHMgcmVnYXJkaW5nIHRoZSBMaWNlbnNlZCBNYXRlcmlhbCBub3Qgc3RhdGVkIGhlcmVpbiBhcmUgc2VwYXJhdGUgZnJvbSBhbmQgaW5kZXBlbmRlbnQgb2YgdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHRoaXMgUHVibGljIExpY2Vuc2UuCgpTZWN0aW9uIDgg4oCTIEludGVycHJldGF0aW9uLgoKICAgICBhLglGb3IgdGhlIGF2b2lkYW5jZSBvZiBkb3VidCwgdGhpcyBQdWJsaWMgTGljZW5zZSBkb2VzIG5vdCwgYW5kIHNoYWxsIG5vdCBiZSBpbnRlcnByZXRlZCB0bywgcmVkdWNlLCBsaW1pdCwgcmVzdHJpY3QsIG9yIGltcG9zZSBjb25kaXRpb25zIG9uIGFueSB1c2Ugb2YgdGhlIExpY2Vuc2VkIE1hdGVyaWFsIHRoYXQgY291bGQgbGF3ZnVsbHkgYmUgbWFkZSB3aXRob3V0IHBlcm1pc3Npb24gdW5kZXIgdGhpcyBQdWJsaWMgTGljZW5zZS4KCiAgICAgYi4JVG8gdGhlIGV4dGVudCBwb3NzaWJsZSwgaWYgYW55IHByb3Zpc2lvbiBvZiB0aGlzIFB1YmxpYyBMaWNlbnNlIGlzIGRlZW1lZCB1bmVuZm9yY2VhYmxlLCBpdCBzaGFsbCBiZSBhdXRvbWF0aWNhbGx5IHJlZm9ybWVkIHRvIHRoZSBtaW5pbXVtIGV4dGVudCBuZWNlc3NhcnkgdG8gbWFrZSBpdCBlbmZvcmNlYWJsZS4gSWYgdGhlIHByb3Zpc2lvbiBjYW5ub3QgYmUgcmVmb3JtZWQsIGl0IHNoYWxsIGJlIHNldmVyZWQgZnJvbSB0aGlzIFB1YmxpYyBMaWNlbnNlIHdpdGhvdXQgYWZmZWN0aW5nIHRoZSBlbmZvcmNlYWJpbGl0eSBvZiB0aGUgcmVtYWluaW5nIHRlcm1zIGFuZCBjb25kaXRpb25zLgoKICAgICBjLglObyB0ZXJtIG9yIGNvbmRpdGlvbiBvZiB0aGlzIFB1YmxpYyBMaWNlbnNlIHdpbGwgYmUgd2FpdmVkIGFuZCBubyBmYWlsdXJlIHRvIGNvbXBseSBjb25zZW50ZWQgdG8gdW5sZXNzIGV4cHJlc3NseSBhZ3JlZWQgdG8gYnkgdGhlIExpY2Vuc29yLgoKICAgICBkLglOb3RoaW5nIGluIHRoaXMgUHVibGljIExpY2Vuc2UgY29uc3RpdHV0ZXMgb3IgbWF5IGJlIGludGVycHJldGVkIGFzIGEgbGltaXRhdGlvbiB1cG9uLCBvciB3YWl2ZXIgb2YsIGFueSBwcml2aWxlZ2VzIGFuZCBpbW11bml0aWVzIHRoYXQgYXBwbHkgdG8gdGhlIExpY2Vuc29yIG9yIFlvdSwgaW5jbHVkaW5nIGZyb20gdGhlIGxlZ2FsIHByb2Nlc3NlcyBvZiBhbnkganVyaXNkaWN0aW9uIG9yIGF1dGhvcml0eS4KCkNyZWF0aXZlIENvbW1vbnMgaXMgbm90IGEgcGFydHkgdG8gaXRzIHB1YmxpYyBsaWNlbnNlcy4gTm90d2l0aHN0YW5kaW5nLCBDcmVhdGl2ZSBDb21tb25zIG1heSBlbGVjdCB0byBhcHBseSBvbmUgb2YgaXRzIHB1YmxpYyBsaWNlbnNlcyB0byBtYXRlcmlhbCBpdCBwdWJsaXNoZXMgYW5kIGluIHRob3NlIGluc3RhbmNlcyB3aWxsIGJlIGNvbnNpZGVyZWQgdGhlIOKAnExpY2Vuc29yLuKAnSBFeGNlcHQgZm9yIHRoZSBsaW1pdGVkIHB1cnBvc2Ugb2YgaW5kaWNhdGluZyB0aGF0IG1hdGVyaWFsIGlzIHNoYXJlZCB1bmRlciBhIENyZWF0aXZlIENvbW1vbnMgcHVibGljIGxpY2Vuc2Ugb3IgYXMgb3RoZXJ3aXNlIHBlcm1pdHRlZCBieSB0aGUgQ3JlYXRpdmUgQ29tbW9ucyBwb2xpY2llcyBwdWJsaXNoZWQgYXQgY3JlYXRpdmVjb21tb25zLm9yZy9wb2xpY2llcywgQ3JlYXRpdmUgQ29tbW9ucyBkb2VzIG5vdCBhdXRob3JpemUgdGhlIHVzZSBvZiB0aGUgdHJhZGVtYXJrIOKAnENyZWF0aXZlIENvbW1vbnPigJ0gb3IgYW55IG90aGVyIHRyYWRlbWFyayBvciBsb2dvIG9mIENyZWF0aXZlIENvbW1vbnMgd2l0aG91dCBpdHMgcHJpb3Igd3JpdHRlbiBjb25zZW50IGluY2x1ZGluZywgd2l0aG91dCBsaW1pdGF0aW9uLCBpbiBjb25uZWN0aW9uIHdpdGggYW55IHVuYXV0aG9yaXplZCBtb2RpZmljYXRpb25zIHRvIGFueSBvZiBpdHMgcHVibGljIGxpY2Vuc2VzIG9yIGFueSBvdGhlciBhcnJhbmdlbWVudHMsIHVuZGVyc3RhbmRpbmdzLCBvciBhZ3JlZW1lbnRzIGNvbmNlcm5pbmcgdXNlIG9mIGxpY2Vuc2VkIG1hdGVyaWFsLiBGb3IgdGhlIGF2b2lkYW5jZSBvZiBkb3VidCwgdGhpcyBwYXJhZ3JhcGggZG9lcyBub3QgZm9ybSBwYXJ0IG9mIHRoZSBwdWJsaWMgbGljZW5zZXMuCgpDcmVhdGl2ZSBDb21tb25zIG1heSBiZSBjb250YWN0ZWQgYXQgY3JlYXRpdmVjb21tb25zLm9yZy4="},"url":"https:\/\/creativecommons.org\/licenses\/by-sa\/4.0\/legalcode"}}],"version":"6","purl":"pkg:\/Janus Troelsen\/13781114@6","supplier":{"name":"Janus Troelsen"},"bom-ref":"13781114_6_0e49e5d9-422e-4bc2-8ff8-25e11102bffe","description":"","copyright":"","properties":[{"name":"component_id","value":"8"}]},{"name":"nclick","type":"library","licenses":[{"license":{"id":"MIT","text":{"contentType":"text\/plain","encoding":"base64","content":"TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgPHllYXI+IDxjb3B5cmlnaHQgaG9sZGVycz4KClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUu"},"url":"https:\/\/opensource.org\/licenses\/MIT"}}],"version":"0.0.0","purl":"pkg:pypi\/nclick@0.0.0","supplier":{"name":"copypaste"},"bom-ref":"nclick_0.0.0_e96942e4-66d7-4a1d-b916-f2fe15db84ec","description":"","copyright":"","properties":[{"name":"component_id","value":"12141"}]},{"name":"ruby-domain_name","type":"library","licenses":[{"license":{"id":"BSD-2-Clause","text":{"contentType":"text\/plain","encoding":"base64","content":"Q29weXJpZ2h0IChjKSA8eWVhcj4gPG93bmVyPiAKClJlZGlzdHJpYnV0aW9uIGFuZCB1c2UgaW4gc291cmNlIGFuZCBiaW5hcnkgZm9ybXMsIHdpdGggb3Igd2l0aG91dCBtb2RpZmljYXRpb24sIGFyZSBwZXJtaXR0ZWQgcHJvdmlkZWQgdGhhdCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnMgYXJlIG1ldDoKCjEuIFJlZGlzdHJpYnV0aW9ucyBvZiBzb3VyY2UgY29kZSBtdXN0IHJldGFpbiB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSwgdGhpcyBsaXN0IG9mIGNvbmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1lci4KCjIuIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSwgdGhpcyBsaXN0IG9mIGNvbmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1lciBpbiB0aGUgZG9jdW1lbnRhdGlvbiBhbmQvb3Igb3RoZXIgbWF0ZXJpYWxzIHByb3ZpZGVkIHdpdGggdGhlIGRpc3RyaWJ1dGlvbi4KClRISVMgU09GVFdBUkUgSVMgUFJPVklERUQgQlkgVEhFIENPUFlSSUdIVCBIT0xERVJTIEFORCBDT05UUklCVVRPUlMgIkFTIElTIiBBTkQgQU5ZIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFIElNUExJRUQgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFSRSBESVNDTEFJTUVELiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQ09QWVJJR0hUIEhPTERFUiBPUiBDT05UUklCVVRPUlMgQkUgTElBQkxFIEZPUiBBTlkgRElSRUNULCBJTkRJUkVDVCwgSU5DSURFTlRBTCwgU1BFQ0lBTCwgRVhFTVBMQVJZLCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMgKElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBQUk9DVVJFTUVOVCBPRiBTVUJTVElUVVRFIEdPT0RTIE9SIFNFUlZJQ0VTOyBMT1NTIE9GIFVTRSwgREFUQSwgT1IgUFJPRklUUzsgT1IgQlVTSU5FU1MgSU5URVJSVVBUSU9OKSBIT1dFVkVSIENBVVNFRCBBTkQgT04gQU5ZIFRIRU9SWSBPRiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQ09OVFJBQ1QsIFNUUklDVCBMSUFCSUxJVFksIE9SIFRPUlQgKElOQ0xVRElORyBORUdMSUdFTkNFIE9SIE9USEVSV0lTRSkgQVJJU0lORyBJTiBBTlkgV0FZIE9VVCBPRiBUSEUgVVNFIE9GIFRISVMgU09GVFdBUkUsIEVWRU4gSUYgQURWSVNFRCBPRiBUSEUgUE9TU0lCSUxJVFkgT0YgU1VDSCBEQU1BR0Uu"},"url":"https:\/\/opensource.org\/licenses\/BSD-2-Clause"}}],"version":"0.5.20160826","purl":"pkg:github\/knu\/ruby-domain_name@0.5.20160826","supplier":{"name":"knu"},"bom-ref":"ruby-domain_name_0.5.20160826_4af9afe8-a8d1-4454-b198-28f18c39a563","description":"","copyright":"","properties":[{"name":"component_id","value":"15"}]},{"name":"platform_frameworks_base","type":"library","licenses":[{"license":{"id":"Apache-2.0","text":{"contentType":"text\/plain","encoding":"base64","content":"QXBhY2hlIExpY2Vuc2UKVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNApodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvCgpURVJNUyBBTkQgQ09ORElUSU9OUyBGT1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04KCjEuIERlZmluaXRpb25zLgoKIkxpY2Vuc2UiIHNoYWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBhcyBkZWZpbmVkIGJ5IFNlY3Rpb25zIDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuCgoiTGljZW5zb3IiIHNoYWxsIG1lYW4gdGhlIGNvcHlyaWdodCBvd25lciBvciBlbnRpdHkgYXV0aG9yaXplZCBieSB0aGUgY29weXJpZ2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhlIExpY2Vuc2UuCgoiTGVnYWwgRW50aXR5IiBzaGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsIG90aGVyIGVudGl0aWVzIHRoYXQgY29udHJvbCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRlciBjb21tb24gY29udHJvbCB3aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIsIGRpcmVjdCBvciBpbmRpcmVjdCwgdG8gY2F1c2UgdGhlIGRpcmVjdGlvbiBvciBtYW5hZ2VtZW50IG9mIHN1Y2ggZW50aXR5LCB3aGV0aGVyIGJ5IGNvbnRyYWN0IG9yIG90aGVyd2lzZSwgb3IgKGlpKSBvd25lcnNoaXAgb2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZSBvdXRzdGFuZGluZyBzaGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJzaGlwIG9mIHN1Y2ggZW50aXR5LgoKIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eSBleGVyY2lzaW5nIHBlcm1pc3Npb25zIGdyYW50ZWQgYnkgdGhpcyBMaWNlbnNlLgoKIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3IgbWFraW5nIG1vZGlmaWNhdGlvbnMsIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gc29mdHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRpb24gc291cmNlLCBhbmQgY29uZmlndXJhdGlvbiBmaWxlcy4KCiJPYmplY3QiIGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9ybSByZXN1bHRpbmcgZnJvbSBtZWNoYW5pY2FsIHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5zbGF0aW9uIG9mIGEgU291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gY29tcGlsZWQgb2JqZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLCBhbmQgY29udmVyc2lvbnMgdG8gb3RoZXIgbWVkaWEgdHlwZXMuCgoiV29yayIgc2hhbGwgbWVhbiB0aGUgd29yayBvZiBhdXRob3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgbWFkZSBhdmFpbGFibGUgdW5kZXIgdGhlIExpY2Vuc2UsIGFzIGluZGljYXRlZCBieSBhIGNvcHlyaWdodCBub3RpY2UgdGhhdCBpcyBpbmNsdWRlZCBpbiBvciBhdHRhY2hlZCB0byB0aGUgd29yayAoYW4gZXhhbXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBwZW5kaXggYmVsb3cpLgoKIkRlcml2YXRpdmUgV29ya3MiIHNoYWxsIG1lYW4gYW55IHdvcmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdCBmb3JtLCB0aGF0IGlzIGJhc2VkIG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBmb3Igd2hpY2ggdGhlIGVkaXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBlbGFib3JhdGlvbnMsIG9yIG90aGVyIG1vZGlmaWNhdGlvbnMgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBhbiBvcmlnaW5hbCB3b3JrIG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyBMaWNlbnNlLCBEZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQgcmVtYWluIHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAob3IgYmluZCBieSBuYW1lKSB0byB0aGUgaW50ZXJmYWNlcyBvZiwgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZi4KCiJDb250cmlidXRpb24iIHNoYWxsIG1lYW4gYW55IHdvcmsgb2YgYXV0aG9yc2hpcCwgaW5jbHVkaW5nIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBhbnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMgdG8gdGhhdCBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5IHN1Ym1pdHRlZCB0byBMaWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRoZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgYnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXplZCB0byBzdWJtaXQgb24gYmVoYWxmIG9mIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIiBtZWFucyBhbnkgZm9ybSBvZiBlbGVjdHJvbmljLCB2ZXJiYWwsIG9yIHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBzZW50IHRvIHRoZSBMaWNlbnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBtYWlsaW5nIGxpc3RzLCBzb3VyY2UgY29kZSBjb250cm9sIHN5c3RlbXMsIGFuZCBpc3N1ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQgYXJlIG1hbmFnZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwgdGhlIExpY2Vuc29yIGZvciB0aGUgcHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXByb3ZpbmcgdGhlIFdvcmssIGJ1dCBleGNsdWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlzIGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVyd2lzZSBkZXNpZ25hdGVkIGluIHdyaXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAiTm90IGEgQ29udHJpYnV0aW9uLiIKCiJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNvciBhbmQgYW55IGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IG9uIGJlaGFsZiBvZiB3aG9tIGEgQ29udHJpYnV0aW9uIGhhcyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZCBzdWJzZXF1ZW50bHkgaW5jb3Jwb3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCjIuIEdyYW50IG9mIENvcHlyaWdodCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB0aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1YWwsIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUsIGlycmV2b2NhYmxlIGNvcHlyaWdodCBsaWNlbnNlIHRvIHJlcHJvZHVjZSwgcHJlcGFyZSBEZXJpdmF0aXZlIFdvcmtzIG9mLCBwdWJsaWNseSBkaXNwbGF5LCBwdWJsaWNseSBwZXJmb3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUgV29yayBhbmQgc3VjaCBEZXJpdmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4KCjMuIEdyYW50IG9mIFBhdGVudCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB0aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1YWwsIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUsIGlycmV2b2NhYmxlIChleGNlcHQgYXMgc3RhdGVkIGluIHRoaXMgc2VjdGlvbikgcGF0ZW50IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLCB1c2UsIG9mZmVyIHRvIHNlbGwsIHNlbGwsIGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29yaywgd2hlcmUgc3VjaCBsaWNlbnNlIGFwcGxpZXMgb25seSB0byB0aG9zZSBwYXRlbnQgY2xhaW1zIGxpY2Vuc2FibGUgYnkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNlc3NhcmlseSBpbmZyaW5nZWQgYnkgdGhlaXIgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9yIGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENvbnRyaWJ1dGlvbihzKSB3aXRoIHRoZSBXb3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9uKHMpIHdhcyBzdWJtaXR0ZWQuIElmIFlvdSBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24gYWdhaW5zdCBhbnkgZW50aXR5IChpbmNsdWRpbmcgYSBjcm9zcy1jbGFpbSBvciBjb3VudGVyY2xhaW0gaW4gYSBsYXdzdWl0KSBhbGxlZ2luZyB0aGF0IHRoZSBXb3JrIG9yIGEgQ29udHJpYnV0aW9uIGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGlyZWN0IG9yIGNvbnRyaWJ1dG9yeSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGljZW5zZXMgZ3JhbnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsgc2hhbGwgdGVybWluYXRlIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0aWdhdGlvbiBpcyBmaWxlZC4KCjQuIFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBjb3BpZXMgb2YgdGhlIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mIGluIGFueSBtZWRpdW0sIHdpdGggb3Igd2l0aG91dCBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9yIE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdSBtZWV0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczoKCiAgICAgKGEpIFlvdSBtdXN0IGdpdmUgYW55IG90aGVyIHJlY2lwaWVudHMgb2YgdGhlIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgKGIpIFlvdSBtdXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBwcm9taW5lbnQgbm90aWNlcyBzdGF0aW5nIHRoYXQgWW91IGNoYW5nZWQgdGhlIGZpbGVzOyBhbmQKCiAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsbCBjb3B5cmlnaHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQgYXR0cmlidXRpb24gbm90aWNlcyBmcm9tIHRoZSBTb3VyY2UgZm9ybSBvZiB0aGUgV29yaywgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrczsgYW5kCgogICAgIChkKSBJZiB0aGUgV29yayBpbmNsdWRlcyBhICJOT1RJQ0UiIHRleHQgZmlsZSBhcyBwYXJ0IG9mIGl0cyBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0IGluY2x1ZGUgYSByZWFkYWJsZSBjb3B5IG9mIHRoZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZCB3aXRoaW4gc3VjaCBOT1RJQ0UgZmlsZSwgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiB3aXRoaW4gYSBOT1RJQ0UgdGV4dCBmaWxlIGRpc3RyaWJ1dGVkIGFzIHBhcnQgb2YgdGhlIERlcml2YXRpdmUgV29ya3M7IHdpdGhpbiB0aGUgU291cmNlIGZvcm0gb3IgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsIHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBhbmQgd2hlcmV2ZXIgc3VjaCB0aGlyZC1wYXJ0eSBub3RpY2VzIG5vcm1hbGx5IGFwcGVhci4gVGhlIGNvbnRlbnRzIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQgZG8gbm90IG1vZGlmeSB0aGUgTGljZW5zZS4gWW91IG1heSBhZGQgWW91ciBvd24gYXR0cmlidXRpb24gbm90aWNlcyB3aXRoaW4gRGVyaXZhdGl2ZSBXb3JrcyB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbG9uZ3NpZGUgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkIHRoYXQgc3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0aW9uIG5vdGljZXMgY2Fubm90IGJlIGNvbnN0cnVlZCBhcyBtb2RpZnlpbmcgdGhlIExpY2Vuc2UuCgogICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZCBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aCB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLCBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZSBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZSBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCjcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLCBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55IHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCjguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LCB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLCBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZSBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZyB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLCBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LCBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcyBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seSBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZiBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eSBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgpBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgpUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZyBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYSBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llciBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgpDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwp5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCllvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCgpVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCmRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgpTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCmxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLg=="},"url":"https:\/\/www.apache.org\/licenses\/LICENSE-2.0"}}],"version":"android-wear-n-preview-1","bom-ref":"platform_frameworks_base_android-wear-n-preview-1_9191cd2e-244b-4e0e-a4c4-9a36c5e2cbe8","description":"","copyright":"","properties":[{"name":"component_id","value":"3"}]},{"name":"tutor","type":"library","licenses":[{"license":{"id":"GPL-3.0-only","text":{"contentType":"text\/plain","encoding":"base64","content":"R05VIEdFTkVSQUwgUFVCTElDIExJQ0VOU0UKVmVyc2lvbiAzLCAyOSBKdW5lIDIwMDcKCkNvcHlyaWdodCDCqSAyMDA3IEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgSW5jLiA8aHR0cDovL2ZzZi5vcmcvPgoKRXZlcnlvbmUgaXMgcGVybWl0dGVkIHRvIGNvcHkgYW5kIGRpc3RyaWJ1dGUgdmVyYmF0aW0gY29waWVzIG9mIHRoaXMgbGljZW5zZSBkb2N1bWVudCwgYnV0IGNoYW5naW5nIGl0IGlzIG5vdCBhbGxvd2VkLgoKUHJlYW1ibGUKClRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBpcyBhIGZyZWUsIGNvcHlsZWZ0IGxpY2Vuc2UgZm9yIHNvZnR3YXJlIGFuZCBvdGhlciBraW5kcyBvZiB3b3Jrcy4KClRoZSBsaWNlbnNlcyBmb3IgbW9zdCBzb2Z0d2FyZSBhbmQgb3RoZXIgcHJhY3RpY2FsIHdvcmtzIGFyZSBkZXNpZ25lZCB0byB0YWtlIGF3YXkgeW91ciBmcmVlZG9tIHRvIHNoYXJlIGFuZCBjaGFuZ2UgdGhlIHdvcmtzLiBCeSBjb250cmFzdCwgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGlzIGludGVuZGVkIHRvIGd1YXJhbnRlZSB5b3VyIGZyZWVkb20gdG8gc2hhcmUgYW5kIGNoYW5nZSBhbGwgdmVyc2lvbnMgb2YgYSBwcm9ncmFtLS10byBtYWtlIHN1cmUgaXQgcmVtYWlucyBmcmVlIHNvZnR3YXJlIGZvciBhbGwgaXRzIHVzZXJzLiBXZSwgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdXNlIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9zdCBvZiBvdXIgc29mdHdhcmU7IGl0IGFwcGxpZXMgYWxzbyB0byBhbnkgb3RoZXIgd29yayByZWxlYXNlZCB0aGlzIHdheSBieSBpdHMgYXV0aG9ycy4gWW91IGNhbiBhcHBseSBpdCB0byB5b3VyIHByb2dyYW1zLCB0b28uCgpXaGVuIHdlIHNwZWFrIG9mIGZyZWUgc29mdHdhcmUsIHdlIGFyZSByZWZlcnJpbmcgdG8gZnJlZWRvbSwgbm90IHByaWNlLiBPdXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZXMgYXJlIGRlc2lnbmVkIHRvIG1ha2Ugc3VyZSB0aGF0IHlvdSBoYXZlIHRoZSBmcmVlZG9tIHRvIGRpc3RyaWJ1dGUgY29waWVzIG9mIGZyZWUgc29mdHdhcmUgKGFuZCBjaGFyZ2UgZm9yIHRoZW0gaWYgeW91IHdpc2gpLCB0aGF0IHlvdSByZWNlaXZlIHNvdXJjZSBjb2RlIG9yIGNhbiBnZXQgaXQgaWYgeW91IHdhbnQgaXQsIHRoYXQgeW91IGNhbiBjaGFuZ2UgdGhlIHNvZnR3YXJlIG9yIHVzZSBwaWVjZXMgb2YgaXQgaW4gbmV3IGZyZWUgcHJvZ3JhbXMsIGFuZCB0aGF0IHlvdSBrbm93IHlvdSBjYW4gZG8gdGhlc2UgdGhpbmdzLgoKVG8gcHJvdGVjdCB5b3VyIHJpZ2h0cywgd2UgbmVlZCB0byBwcmV2ZW50IG90aGVycyBmcm9tIGRlbnlpbmcgeW91IHRoZXNlIHJpZ2h0cyBvciBhc2tpbmcgeW91IHRvIHN1cnJlbmRlciB0aGUgcmlnaHRzLiBUaGVyZWZvcmUsIHlvdSBoYXZlIGNlcnRhaW4gcmVzcG9uc2liaWxpdGllcyBpZiB5b3UgZGlzdHJpYnV0ZSBjb3BpZXMgb2YgdGhlIHNvZnR3YXJlLCBvciBpZiB5b3UgbW9kaWZ5IGl0OiByZXNwb25zaWJpbGl0aWVzIHRvIHJlc3BlY3QgdGhlIGZyZWVkb20gb2Ygb3RoZXJzLgoKRm9yIGV4YW1wbGUsIGlmIHlvdSBkaXN0cmlidXRlIGNvcGllcyBvZiBzdWNoIGEgcHJvZ3JhbSwgd2hldGhlciBncmF0aXMgb3IgZm9yIGEgZmVlLCB5b3UgbXVzdCBwYXNzIG9uIHRvIHRoZSByZWNpcGllbnRzIHRoZSBzYW1lIGZyZWVkb21zIHRoYXQgeW91IHJlY2VpdmVkLiBZb3UgbXVzdCBtYWtlIHN1cmUgdGhhdCB0aGV5LCB0b28sIHJlY2VpdmUgb3IgY2FuIGdldCB0aGUgc291cmNlIGNvZGUuIEFuZCB5b3UgbXVzdCBzaG93IHRoZW0gdGhlc2UgdGVybXMgc28gdGhleSBrbm93IHRoZWlyIHJpZ2h0cy4KCkRldmVsb3BlcnMgdGhhdCB1c2UgdGhlIEdOVSBHUEwgcHJvdGVjdCB5b3VyIHJpZ2h0cyB3aXRoIHR3byBzdGVwczogKDEpIGFzc2VydCBjb3B5cmlnaHQgb24gdGhlIHNvZnR3YXJlLCBhbmQgKDIpIG9mZmVyIHlvdSB0aGlzIExpY2Vuc2UgZ2l2aW5nIHlvdSBsZWdhbCBwZXJtaXNzaW9uIHRvIGNvcHksIGRpc3RyaWJ1dGUgYW5kL29yIG1vZGlmeSBpdC4KCkZvciB0aGUgZGV2ZWxvcGVycycgYW5kIGF1dGhvcnMnIHByb3RlY3Rpb24sIHRoZSBHUEwgY2xlYXJseSBleHBsYWlucyB0aGF0IHRoZXJlIGlzIG5vIHdhcnJhbnR5IGZvciB0aGlzIGZyZWUgc29mdHdhcmUuIEZvciBib3RoIHVzZXJzJyBhbmQgYXV0aG9ycycgc2FrZSwgdGhlIEdQTCByZXF1aXJlcyB0aGF0IG1vZGlmaWVkIHZlcnNpb25zIGJlIG1hcmtlZCBhcyBjaGFuZ2VkLCBzbyB0aGF0IHRoZWlyIHByb2JsZW1zIHdpbGwgbm90IGJlIGF0dHJpYnV0ZWQgZXJyb25lb3VzbHkgdG8gYXV0aG9ycyBvZiBwcmV2aW91cyB2ZXJzaW9ucy4KClNvbWUgZGV2aWNlcyBhcmUgZGVzaWduZWQgdG8gZGVueSB1c2VycyBhY2Nlc3MgdG8gaW5zdGFsbCBvciBydW4gbW9kaWZpZWQgdmVyc2lvbnMgb2YgdGhlIHNvZnR3YXJlIGluc2lkZSB0aGVtLCBhbHRob3VnaCB0aGUgbWFudWZhY3R1cmVyIGNhbiBkbyBzby4gVGhpcyBpcyBmdW5kYW1lbnRhbGx5IGluY29tcGF0aWJsZSB3aXRoIHRoZSBhaW0gb2YgcHJvdGVjdGluZyB1c2VycycgZnJlZWRvbSB0byBjaGFuZ2UgdGhlIHNvZnR3YXJlLiBUaGUgc3lzdGVtYXRpYyBwYXR0ZXJuIG9mIHN1Y2ggYWJ1c2Ugb2NjdXJzIGluIHRoZSBhcmVhIG9mIHByb2R1Y3RzIGZvciBpbmRpdmlkdWFscyB0byB1c2UsIHdoaWNoIGlzIHByZWNpc2VseSB3aGVyZSBpdCBpcyBtb3N0IHVuYWNjZXB0YWJsZS4gVGhlcmVmb3JlLCB3ZSBoYXZlIGRlc2lnbmVkIHRoaXMgdmVyc2lvbiBvZiB0aGUgR1BMIHRvIHByb2hpYml0IHRoZSBwcmFjdGljZSBmb3IgdGhvc2UgcHJvZHVjdHMuIElmIHN1Y2ggcHJvYmxlbXMgYXJpc2Ugc3Vic3RhbnRpYWxseSBpbiBvdGhlciBkb21haW5zLCB3ZSBzdGFuZCByZWFkeSB0byBleHRlbmQgdGhpcyBwcm92aXNpb24gdG8gdGhvc2UgZG9tYWlucyBpbiBmdXR1cmUgdmVyc2lvbnMgb2YgdGhlIEdQTCwgYXMgbmVlZGVkIHRvIHByb3RlY3QgdGhlIGZyZWVkb20gb2YgdXNlcnMuCgpGaW5hbGx5LCBldmVyeSBwcm9ncmFtIGlzIHRocmVhdGVuZWQgY29uc3RhbnRseSBieSBzb2Z0d2FyZSBwYXRlbnRzLiBTdGF0ZXMgc2hvdWxkIG5vdCBhbGxvdyBwYXRlbnRzIHRvIHJlc3RyaWN0IGRldmVsb3BtZW50IGFuZCB1c2Ugb2Ygc29mdHdhcmUgb24gZ2VuZXJhbC1wdXJwb3NlIGNvbXB1dGVycywgYnV0IGluIHRob3NlIHRoYXQgZG8sIHdlIHdpc2ggdG8gYXZvaWQgdGhlIHNwZWNpYWwgZGFuZ2VyIHRoYXQgcGF0ZW50cyBhcHBsaWVkIHRvIGEgZnJlZSBwcm9ncmFtIGNvdWxkIG1ha2UgaXQgZWZmZWN0aXZlbHkgcHJvcHJpZXRhcnkuIFRvIHByZXZlbnQgdGhpcywgdGhlIEdQTCBhc3N1cmVzIHRoYXQgcGF0ZW50cyBjYW5ub3QgYmUgdXNlZCB0byByZW5kZXIgdGhlIHByb2dyYW0gbm9uLWZyZWUuCgpUaGUgcHJlY2lzZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgY29weWluZywgZGlzdHJpYnV0aW9uIGFuZCBtb2RpZmljYXRpb24gZm9sbG93LgoKVEVSTVMgQU5EIENPTkRJVElPTlMKCjAuIERlZmluaXRpb25zLgoK4oCcVGhpcyBMaWNlbnNl4oCdIHJlZmVycyB0byB2ZXJzaW9uIDMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlLgoK4oCcQ29weXJpZ2h04oCdIGFsc28gbWVhbnMgY29weXJpZ2h0LWxpa2UgbGF3cyB0aGF0IGFwcGx5IHRvIG90aGVyIGtpbmRzIG9mIHdvcmtzLCBzdWNoIGFzIHNlbWljb25kdWN0b3IgbWFza3MuCgrigJxUaGUgUHJvZ3JhbeKAnSByZWZlcnMgdG8gYW55IGNvcHlyaWdodGFibGUgd29yayBsaWNlbnNlZCB1bmRlciB0aGlzIExpY2Vuc2UuIEVhY2ggbGljZW5zZWUgaXMgYWRkcmVzc2VkIGFzIOKAnHlvdeKAnS4g4oCcTGljZW5zZWVz4oCdIGFuZCDigJxyZWNpcGllbnRz4oCdIG1heSBiZSBpbmRpdmlkdWFscyBvciBvcmdhbml6YXRpb25zLgoKVG8g4oCcbW9kaWZ54oCdIGEgd29yayBtZWFucyB0byBjb3B5IGZyb20gb3IgYWRhcHQgYWxsIG9yIHBhcnQgb2YgdGhlIHdvcmsgaW4gYSBmYXNoaW9uIHJlcXVpcmluZyBjb3B5cmlnaHQgcGVybWlzc2lvbiwgb3RoZXIgdGhhbiB0aGUgbWFraW5nIG9mIGFuIGV4YWN0IGNvcHkuIFRoZSByZXN1bHRpbmcgd29yayBpcyBjYWxsZWQgYSDigJxtb2RpZmllZCB2ZXJzaW9u4oCdIG9mIHRoZSBlYXJsaWVyIHdvcmsgb3IgYSB3b3JrIOKAnGJhc2VkIG9u4oCdIHRoZSBlYXJsaWVyIHdvcmsuCgpBIOKAnGNvdmVyZWQgd29ya+KAnSBtZWFucyBlaXRoZXIgdGhlIHVubW9kaWZpZWQgUHJvZ3JhbSBvciBhIHdvcmsgYmFzZWQgb24gdGhlIFByb2dyYW0uCgpUbyDigJxwcm9wYWdhdGXigJ0gYSB3b3JrIG1lYW5zIHRvIGRvIGFueXRoaW5nIHdpdGggaXQgdGhhdCwgd2l0aG91dCBwZXJtaXNzaW9uLCB3b3VsZCBtYWtlIHlvdSBkaXJlY3RseSBvciBzZWNvbmRhcmlseSBsaWFibGUgZm9yIGluZnJpbmdlbWVudCB1bmRlciBhcHBsaWNhYmxlIGNvcHlyaWdodCBsYXcsIGV4Y2VwdCBleGVjdXRpbmcgaXQgb24gYSBjb21wdXRlciBvciBtb2RpZnlpbmcgYSBwcml2YXRlIGNvcHkuIFByb3BhZ2F0aW9uIGluY2x1ZGVzIGNvcHlpbmcsIGRpc3RyaWJ1dGlvbiAod2l0aCBvciB3aXRob3V0IG1vZGlmaWNhdGlvbiksIG1ha2luZyBhdmFpbGFibGUgdG8gdGhlIHB1YmxpYywgYW5kIGluIHNvbWUgY291bnRyaWVzIG90aGVyIGFjdGl2aXRpZXMgYXMgd2VsbC4KClRvIOKAnGNvbnZleeKAnSBhIHdvcmsgbWVhbnMgYW55IGtpbmQgb2YgcHJvcGFnYXRpb24gdGhhdCBlbmFibGVzIG90aGVyIHBhcnRpZXMgdG8gbWFrZSBvciByZWNlaXZlIGNvcGllcy4gTWVyZSBpbnRlcmFjdGlvbiB3aXRoIGEgdXNlciB0aHJvdWdoIGEgY29tcHV0ZXIgbmV0d29yaywgd2l0aCBubyB0cmFuc2ZlciBvZiBhIGNvcHksIGlzIG5vdCBjb252ZXlpbmcuCgpBbiBpbnRlcmFjdGl2ZSB1c2VyIGludGVyZmFjZSBkaXNwbGF5cyDigJxBcHByb3ByaWF0ZSBMZWdhbCBOb3RpY2Vz4oCdIHRvIHRoZSBleHRlbnQgdGhhdCBpdCBpbmNsdWRlcyBhIGNvbnZlbmllbnQgYW5kIHByb21pbmVudGx5IHZpc2libGUgZmVhdHVyZSB0aGF0ICgxKSBkaXNwbGF5cyBhbiBhcHByb3ByaWF0ZSBjb3B5cmlnaHQgbm90aWNlLCBhbmQgKDIpIHRlbGxzIHRoZSB1c2VyIHRoYXQgdGhlcmUgaXMgbm8gd2FycmFudHkgZm9yIHRoZSB3b3JrIChleGNlcHQgdG8gdGhlIGV4dGVudCB0aGF0IHdhcnJhbnRpZXMgYXJlIHByb3ZpZGVkKSwgdGhhdCBsaWNlbnNlZXMgbWF5IGNvbnZleSB0aGUgd29yayB1bmRlciB0aGlzIExpY2Vuc2UsIGFuZCBob3cgdG8gdmlldyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlLiBJZiB0aGUgaW50ZXJmYWNlIHByZXNlbnRzIGEgbGlzdCBvZiB1c2VyIGNvbW1hbmRzIG9yIG9wdGlvbnMsIHN1Y2ggYXMgYSBtZW51LCBhIHByb21pbmVudCBpdGVtIGluIHRoZSBsaXN0IG1lZXRzIHRoaXMgY3JpdGVyaW9uLgoKMS4gU291cmNlIENvZGUuClRoZSDigJxzb3VyY2UgY29kZeKAnSBmb3IgYSB3b3JrIG1lYW5zIHRoZSBwcmVmZXJyZWQgZm9ybSBvZiB0aGUgd29yayBmb3IgbWFraW5nIG1vZGlmaWNhdGlvbnMgdG8gaXQuIOKAnE9iamVjdCBjb2Rl4oCdIG1lYW5zIGFueSBub24tc291cmNlIGZvcm0gb2YgYSB3b3JrLgoKQSDigJxTdGFuZGFyZCBJbnRlcmZhY2XigJ0gbWVhbnMgYW4gaW50ZXJmYWNlIHRoYXQgZWl0aGVyIGlzIGFuIG9mZmljaWFsIHN0YW5kYXJkIGRlZmluZWQgYnkgYSByZWNvZ25pemVkIHN0YW5kYXJkcyBib2R5LCBvciwgaW4gdGhlIGNhc2Ugb2YgaW50ZXJmYWNlcyBzcGVjaWZpZWQgZm9yIGEgcGFydGljdWxhciBwcm9ncmFtbWluZyBsYW5ndWFnZSwgb25lIHRoYXQgaXMgd2lkZWx5IHVzZWQgYW1vbmcgZGV2ZWxvcGVycyB3b3JraW5nIGluIHRoYXQgbGFuZ3VhZ2UuCgpUaGUg4oCcU3lzdGVtIExpYnJhcmllc+KAnSBvZiBhbiBleGVjdXRhYmxlIHdvcmsgaW5jbHVkZSBhbnl0aGluZywgb3RoZXIgdGhhbiB0aGUgd29yayBhcyBhIHdob2xlLCB0aGF0IChhKSBpcyBpbmNsdWRlZCBpbiB0aGUgbm9ybWFsIGZvcm0gb2YgcGFja2FnaW5nIGEgTWFqb3IgQ29tcG9uZW50LCBidXQgd2hpY2ggaXMgbm90IHBhcnQgb2YgdGhhdCBNYWpvciBDb21wb25lbnQsIGFuZCAoYikgc2VydmVzIG9ubHkgdG8gZW5hYmxlIHVzZSBvZiB0aGUgd29yayB3aXRoIHRoYXQgTWFqb3IgQ29tcG9uZW50LCBvciB0byBpbXBsZW1lbnQgYSBTdGFuZGFyZCBJbnRlcmZhY2UgZm9yIHdoaWNoIGFuIGltcGxlbWVudGF0aW9uIGlzIGF2YWlsYWJsZSB0byB0aGUgcHVibGljIGluIHNvdXJjZSBjb2RlIGZvcm0uIEEg4oCcTWFqb3IgQ29tcG9uZW504oCdLCBpbiB0aGlzIGNvbnRleHQsIG1lYW5zIGEgbWFqb3IgZXNzZW50aWFsIGNvbXBvbmVudCAoa2VybmVsLCB3aW5kb3cgc3lzdGVtLCBhbmQgc28gb24pIG9mIHRoZSBzcGVjaWZpYyBvcGVyYXRpbmcgc3lzdGVtIChpZiBhbnkpIG9uIHdoaWNoIHRoZSBleGVjdXRhYmxlIHdvcmsgcnVucywgb3IgYSBjb21waWxlciB1c2VkIHRvIHByb2R1Y2UgdGhlIHdvcmssIG9yIGFuIG9iamVjdCBjb2RlIGludGVycHJldGVyIHVzZWQgdG8gcnVuIGl0LgoKVGhlIOKAnENvcnJlc3BvbmRpbmcgU291cmNl4oCdIGZvciBhIHdvcmsgaW4gb2JqZWN0IGNvZGUgZm9ybSBtZWFucyBhbGwgdGhlIHNvdXJjZSBjb2RlIG5lZWRlZCB0byBnZW5lcmF0ZSwgaW5zdGFsbCwgYW5kIChmb3IgYW4gZXhlY3V0YWJsZSB3b3JrKSBydW4gdGhlIG9iamVjdCBjb2RlIGFuZCB0byBtb2RpZnkgdGhlIHdvcmssIGluY2x1ZGluZyBzY3JpcHRzIHRvIGNvbnRyb2wgdGhvc2UgYWN0aXZpdGllcy4gSG93ZXZlciwgaXQgZG9lcyBub3QgaW5jbHVkZSB0aGUgd29yaydzIFN5c3RlbSBMaWJyYXJpZXMsIG9yIGdlbmVyYWwtcHVycG9zZSB0b29scyBvciBnZW5lcmFsbHkgYXZhaWxhYmxlIGZyZWUgcHJvZ3JhbXMgd2hpY2ggYXJlIHVzZWQgdW5tb2RpZmllZCBpbiBwZXJmb3JtaW5nIHRob3NlIGFjdGl2aXRpZXMgYnV0IHdoaWNoIGFyZSBub3QgcGFydCBvZiB0aGUgd29yay4gRm9yIGV4YW1wbGUsIENvcnJlc3BvbmRpbmcgU291cmNlIGluY2x1ZGVzIGludGVyZmFjZSBkZWZpbml0aW9uIGZpbGVzIGFzc29jaWF0ZWQgd2l0aCBzb3VyY2UgZmlsZXMgZm9yIHRoZSB3b3JrLCBhbmQgdGhlIHNvdXJjZSBjb2RlIGZvciBzaGFyZWQgbGlicmFyaWVzIGFuZCBkeW5hbWljYWxseSBsaW5rZWQgc3VicHJvZ3JhbXMgdGhhdCB0aGUgd29yayBpcyBzcGVjaWZpY2FsbHkgZGVzaWduZWQgdG8gcmVxdWlyZSwgc3VjaCBhcyBieSBpbnRpbWF0ZSBkYXRhIGNvbW11bmljYXRpb24gb3IgY29udHJvbCBmbG93IGJldHdlZW4gdGhvc2Ugc3VicHJvZ3JhbXMgYW5kIG90aGVyIHBhcnRzIG9mIHRoZSB3b3JrLgoKVGhlIENvcnJlc3BvbmRpbmcgU291cmNlIG5lZWQgbm90IGluY2x1ZGUgYW55dGhpbmcgdGhhdCB1c2VycyBjYW4gcmVnZW5lcmF0ZSBhdXRvbWF0aWNhbGx5IGZyb20gb3RoZXIgcGFydHMgb2YgdGhlIENvcnJlc3BvbmRpbmcgU291cmNlLgoKVGhlIENvcnJlc3BvbmRpbmcgU291cmNlIGZvciBhIHdvcmsgaW4gc291cmNlIGNvZGUgZm9ybSBpcyB0aGF0IHNhbWUgd29yay4KCjIuIEJhc2ljIFBlcm1pc3Npb25zLgpBbGwgcmlnaHRzIGdyYW50ZWQgdW5kZXIgdGhpcyBMaWNlbnNlIGFyZSBncmFudGVkIGZvciB0aGUgdGVybSBvZiBjb3B5cmlnaHQgb24gdGhlIFByb2dyYW0sIGFuZCBhcmUgaXJyZXZvY2FibGUgcHJvdmlkZWQgdGhlIHN0YXRlZCBjb25kaXRpb25zIGFyZSBtZXQuIFRoaXMgTGljZW5zZSBleHBsaWNpdGx5IGFmZmlybXMgeW91ciB1bmxpbWl0ZWQgcGVybWlzc2lvbiB0byBydW4gdGhlIHVubW9kaWZpZWQgUHJvZ3JhbS4gVGhlIG91dHB1dCBmcm9tIHJ1bm5pbmcgYSBjb3ZlcmVkIHdvcmsgaXMgY292ZXJlZCBieSB0aGlzIExpY2Vuc2Ugb25seSBpZiB0aGUgb3V0cHV0LCBnaXZlbiBpdHMgY29udGVudCwgY29uc3RpdHV0ZXMgYSBjb3ZlcmVkIHdvcmsuIFRoaXMgTGljZW5zZSBhY2tub3dsZWRnZXMgeW91ciByaWdodHMgb2YgZmFpciB1c2Ugb3Igb3RoZXIgZXF1aXZhbGVudCwgYXMgcHJvdmlkZWQgYnkgY29weXJpZ2h0IGxhdy4KCllvdSBtYXkgbWFrZSwgcnVuIGFuZCBwcm9wYWdhdGUgY292ZXJlZCB3b3JrcyB0aGF0IHlvdSBkbyBub3QgY29udmV5LCB3aXRob3V0IGNvbmRpdGlvbnMgc28gbG9uZyBhcyB5b3VyIGxpY2Vuc2Ugb3RoZXJ3aXNlIHJlbWFpbnMgaW4gZm9yY2UuIFlvdSBtYXkgY29udmV5IGNvdmVyZWQgd29ya3MgdG8gb3RoZXJzIGZvciB0aGUgc29sZSBwdXJwb3NlIG9mIGhhdmluZyB0aGVtIG1ha2UgbW9kaWZpY2F0aW9ucyBleGNsdXNpdmVseSBmb3IgeW91LCBvciBwcm92aWRlIHlvdSB3aXRoIGZhY2lsaXRpZXMgZm9yIHJ1bm5pbmcgdGhvc2Ugd29ya3MsIHByb3ZpZGVkIHRoYXQgeW91IGNvbXBseSB3aXRoIHRoZSB0ZXJtcyBvZiB0aGlzIExpY2Vuc2UgaW4gY29udmV5aW5nIGFsbCBtYXRlcmlhbCBmb3Igd2hpY2ggeW91IGRvIG5vdCBjb250cm9sIGNvcHlyaWdodC4gVGhvc2UgdGh1cyBtYWtpbmcgb3IgcnVubmluZyB0aGUgY292ZXJlZCB3b3JrcyBmb3IgeW91IG11c3QgZG8gc28gZXhjbHVzaXZlbHkgb24geW91ciBiZWhhbGYsIHVuZGVyIHlvdXIgZGlyZWN0aW9uIGFuZCBjb250cm9sLCBvbiB0ZXJtcyB0aGF0IHByb2hpYml0IHRoZW0gZnJvbSBtYWtpbmcgYW55IGNvcGllcyBvZiB5b3VyIGNvcHlyaWdodGVkIG1hdGVyaWFsIG91dHNpZGUgdGhlaXIgcmVsYXRpb25zaGlwIHdpdGggeW91LgoKQ29udmV5aW5nIHVuZGVyIGFueSBvdGhlciBjaXJjdW1zdGFuY2VzIGlzIHBlcm1pdHRlZCBzb2xlbHkgdW5kZXIgdGhlIGNvbmRpdGlvbnMgc3RhdGVkIGJlbG93LiBTdWJsaWNlbnNpbmcgaXMgbm90IGFsbG93ZWQ7IHNlY3Rpb24gMTAgbWFrZXMgaXQgdW5uZWNlc3NhcnkuCgozLiBQcm90ZWN0aW5nIFVzZXJzJyBMZWdhbCBSaWdodHMgRnJvbSBBbnRpLUNpcmN1bXZlbnRpb24gTGF3LgpObyBjb3ZlcmVkIHdvcmsgc2hhbGwgYmUgZGVlbWVkIHBhcnQgb2YgYW4gZWZmZWN0aXZlIHRlY2hub2xvZ2ljYWwgbWVhc3VyZSB1bmRlciBhbnkgYXBwbGljYWJsZSBsYXcgZnVsZmlsbGluZyBvYmxpZ2F0aW9ucyB1bmRlciBhcnRpY2xlIDExIG9mIHRoZSBXSVBPIGNvcHlyaWdodCB0cmVhdHkgYWRvcHRlZCBvbiAyMCBEZWNlbWJlciAxOTk2LCBvciBzaW1pbGFyIGxhd3MgcHJvaGliaXRpbmcgb3IgcmVzdHJpY3RpbmcgY2lyY3VtdmVudGlvbiBvZiBzdWNoIG1lYXN1cmVzLgoKV2hlbiB5b3UgY29udmV5IGEgY292ZXJlZCB3b3JrLCB5b3Ugd2FpdmUgYW55IGxlZ2FsIHBvd2VyIHRvIGZvcmJpZCBjaXJjdW12ZW50aW9uIG9mIHRlY2hub2xvZ2ljYWwgbWVhc3VyZXMgdG8gdGhlIGV4dGVudCBzdWNoIGNpcmN1bXZlbnRpb24gaXMgZWZmZWN0ZWQgYnkgZXhlcmNpc2luZyByaWdodHMgdW5kZXIgdGhpcyBMaWNlbnNlIHdpdGggcmVzcGVjdCB0byB0aGUgY292ZXJlZCB3b3JrLCBhbmQgeW91IGRpc2NsYWltIGFueSBpbnRlbnRpb24gdG8gbGltaXQgb3BlcmF0aW9uIG9yIG1vZGlmaWNhdGlvbiBvZiB0aGUgd29yayBhcyBhIG1lYW5zIG9mIGVuZm9yY2luZywgYWdhaW5zdCB0aGUgd29yaydzIHVzZXJzLCB5b3VyIG9yIHRoaXJkIHBhcnRpZXMnIGxlZ2FsIHJpZ2h0cyB0byBmb3JiaWQgY2lyY3VtdmVudGlvbiBvZiB0ZWNobm9sb2dpY2FsIG1lYXN1cmVzLgoKNC4gQ29udmV5aW5nIFZlcmJhdGltIENvcGllcy4KWW91IG1heSBjb252ZXkgdmVyYmF0aW0gY29waWVzIG9mIHRoZSBQcm9ncmFtJ3Mgc291cmNlIGNvZGUgYXMgeW91IHJlY2VpdmUgaXQsIGluIGFueSBtZWRpdW0sIHByb3ZpZGVkIHRoYXQgeW91IGNvbnNwaWN1b3VzbHkgYW5kIGFwcHJvcHJpYXRlbHkgcHVibGlzaCBvbiBlYWNoIGNvcHkgYW4gYXBwcm9wcmlhdGUgY29weXJpZ2h0IG5vdGljZTsga2VlcCBpbnRhY3QgYWxsIG5vdGljZXMgc3RhdGluZyB0aGF0IHRoaXMgTGljZW5zZSBhbmQgYW55IG5vbi1wZXJtaXNzaXZlIHRlcm1zIGFkZGVkIGluIGFjY29yZCB3aXRoIHNlY3Rpb24gNyBhcHBseSB0byB0aGUgY29kZTsga2VlcCBpbnRhY3QgYWxsIG5vdGljZXMgb2YgdGhlIGFic2VuY2Ugb2YgYW55IHdhcnJhbnR5OyBhbmQgZ2l2ZSBhbGwgcmVjaXBpZW50cyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlIGFsb25nIHdpdGggdGhlIFByb2dyYW0uCgpZb3UgbWF5IGNoYXJnZSBhbnkgcHJpY2Ugb3Igbm8gcHJpY2UgZm9yIGVhY2ggY29weSB0aGF0IHlvdSBjb252ZXksIGFuZCB5b3UgbWF5IG9mZmVyIHN1cHBvcnQgb3Igd2FycmFudHkgcHJvdGVjdGlvbiBmb3IgYSBmZWUuCgo1LiBDb252ZXlpbmcgTW9kaWZpZWQgU291cmNlIFZlcnNpb25zLgpZb3UgbWF5IGNvbnZleSBhIHdvcmsgYmFzZWQgb24gdGhlIFByb2dyYW0sIG9yIHRoZSBtb2RpZmljYXRpb25zIHRvIHByb2R1Y2UgaXQgZnJvbSB0aGUgUHJvZ3JhbSwgaW4gdGhlIGZvcm0gb2Ygc291cmNlIGNvZGUgdW5kZXIgdGhlIHRlcm1zIG9mIHNlY3Rpb24gNCwgcHJvdmlkZWQgdGhhdCB5b3UgYWxzbyBtZWV0IGFsbCBvZiB0aGVzZSBjb25kaXRpb25zOgoKICAgICBhKSBUaGUgd29yayBtdXN0IGNhcnJ5IHByb21pbmVudCBub3RpY2VzIHN0YXRpbmcgdGhhdCB5b3UgbW9kaWZpZWQgaXQsIGFuZCBnaXZpbmcgYSByZWxldmFudCBkYXRlLgoKICAgICBiKSBUaGUgd29yayBtdXN0IGNhcnJ5IHByb21pbmVudCBub3RpY2VzIHN0YXRpbmcgdGhhdCBpdCBpcyByZWxlYXNlZCB1bmRlciB0aGlzIExpY2Vuc2UgYW5kIGFueSBjb25kaXRpb25zIGFkZGVkIHVuZGVyIHNlY3Rpb24gNy4gVGhpcyByZXF1aXJlbWVudCBtb2RpZmllcyB0aGUgcmVxdWlyZW1lbnQgaW4gc2VjdGlvbiA0IHRvIOKAnGtlZXAgaW50YWN0IGFsbCBub3RpY2Vz4oCdLgoKICAgICBjKSBZb3UgbXVzdCBsaWNlbnNlIHRoZSBlbnRpcmUgd29yaywgYXMgYSB3aG9sZSwgdW5kZXIgdGhpcyBMaWNlbnNlIHRvIGFueW9uZSB3aG8gY29tZXMgaW50byBwb3NzZXNzaW9uIG9mIGEgY29weS4gVGhpcyBMaWNlbnNlIHdpbGwgdGhlcmVmb3JlIGFwcGx5LCBhbG9uZyB3aXRoIGFueSBhcHBsaWNhYmxlIHNlY3Rpb24gNyBhZGRpdGlvbmFsIHRlcm1zLCB0byB0aGUgd2hvbGUgb2YgdGhlIHdvcmssIGFuZCBhbGwgaXRzIHBhcnRzLCByZWdhcmRsZXNzIG9mIGhvdyB0aGV5IGFyZSBwYWNrYWdlZC4gVGhpcyBMaWNlbnNlIGdpdmVzIG5vIHBlcm1pc3Npb24gdG8gbGljZW5zZSB0aGUgd29yayBpbiBhbnkgb3RoZXIgd2F5LCBidXQgaXQgZG9lcyBub3QgaW52YWxpZGF0ZSBzdWNoIHBlcm1pc3Npb24gaWYgeW91IGhhdmUgc2VwYXJhdGVseSByZWNlaXZlZCBpdC4KCiAgICAgZCkgSWYgdGhlIHdvcmsgaGFzIGludGVyYWN0aXZlIHVzZXIgaW50ZXJmYWNlcywgZWFjaCBtdXN0IGRpc3BsYXkgQXBwcm9wcmlhdGUgTGVnYWwgTm90aWNlczsgaG93ZXZlciwgaWYgdGhlIFByb2dyYW0gaGFzIGludGVyYWN0aXZlIGludGVyZmFjZXMgdGhhdCBkbyBub3QgZGlzcGxheSBBcHByb3ByaWF0ZSBMZWdhbCBOb3RpY2VzLCB5b3VyIHdvcmsgbmVlZCBub3QgbWFrZSB0aGVtIGRvIHNvLgoKQSBjb21waWxhdGlvbiBvZiBhIGNvdmVyZWQgd29yayB3aXRoIG90aGVyIHNlcGFyYXRlIGFuZCBpbmRlcGVuZGVudCB3b3Jrcywgd2hpY2ggYXJlIG5vdCBieSB0aGVpciBuYXR1cmUgZXh0ZW5zaW9ucyBvZiB0aGUgY292ZXJlZCB3b3JrLCBhbmQgd2hpY2ggYXJlIG5vdCBjb21iaW5lZCB3aXRoIGl0IHN1Y2ggYXMgdG8gZm9ybSBhIGxhcmdlciBwcm9ncmFtLCBpbiBvciBvbiBhIHZvbHVtZSBvZiBhIHN0b3JhZ2Ugb3IgZGlzdHJpYnV0aW9uIG1lZGl1bSwgaXMgY2FsbGVkIGFuIOKAnGFnZ3JlZ2F0ZeKAnSBpZiB0aGUgY29tcGlsYXRpb24gYW5kIGl0cyByZXN1bHRpbmcgY29weXJpZ2h0IGFyZSBub3QgdXNlZCB0byBsaW1pdCB0aGUgYWNjZXNzIG9yIGxlZ2FsIHJpZ2h0cyBvZiB0aGUgY29tcGlsYXRpb24ncyB1c2VycyBiZXlvbmQgd2hhdCB0aGUgaW5kaXZpZHVhbCB3b3JrcyBwZXJtaXQuIEluY2x1c2lvbiBvZiBhIGNvdmVyZWQgd29yayBpbiBhbiBhZ2dyZWdhdGUgZG9lcyBub3QgY2F1c2UgdGhpcyBMaWNlbnNlIHRvIGFwcGx5IHRvIHRoZSBvdGhlciBwYXJ0cyBvZiB0aGUgYWdncmVnYXRlLgoKNi4gQ29udmV5aW5nIE5vbi1Tb3VyY2UgRm9ybXMuCllvdSBtYXkgY29udmV5IGEgY292ZXJlZCB3b3JrIGluIG9iamVjdCBjb2RlIGZvcm0gdW5kZXIgdGhlIHRlcm1zIG9mIHNlY3Rpb25zIDQgYW5kIDUsIHByb3ZpZGVkIHRoYXQgeW91IGFsc28gY29udmV5IHRoZSBtYWNoaW5lLXJlYWRhYmxlIENvcnJlc3BvbmRpbmcgU291cmNlIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGlzIExpY2Vuc2UsIGluIG9uZSBvZiB0aGVzZSB3YXlzOgoKICAgICBhKSBDb252ZXkgdGhlIG9iamVjdCBjb2RlIGluLCBvciBlbWJvZGllZCBpbiwgYSBwaHlzaWNhbCBwcm9kdWN0IChpbmNsdWRpbmcgYSBwaHlzaWNhbCBkaXN0cmlidXRpb24gbWVkaXVtKSwgYWNjb21wYW5pZWQgYnkgdGhlIENvcnJlc3BvbmRpbmcgU291cmNlIGZpeGVkIG9uIGEgZHVyYWJsZSBwaHlzaWNhbCBtZWRpdW0gY3VzdG9tYXJpbHkgdXNlZCBmb3Igc29mdHdhcmUgaW50ZXJjaGFuZ2UuCgogICAgIGIpIENvbnZleSB0aGUgb2JqZWN0IGNvZGUgaW4sIG9yIGVtYm9kaWVkIGluLCBhIHBoeXNpY2FsIHByb2R1Y3QgKGluY2x1ZGluZyBhIHBoeXNpY2FsIGRpc3RyaWJ1dGlvbiBtZWRpdW0pLCBhY2NvbXBhbmllZCBieSBhIHdyaXR0ZW4gb2ZmZXIsIHZhbGlkIGZvciBhdCBsZWFzdCB0aHJlZSB5ZWFycyBhbmQgdmFsaWQgZm9yIGFzIGxvbmcgYXMgeW91IG9mZmVyIHNwYXJlIHBhcnRzIG9yIGN1c3RvbWVyIHN1cHBvcnQgZm9yIHRoYXQgcHJvZHVjdCBtb2RlbCwgdG8gZ2l2ZSBhbnlvbmUgd2hvIHBvc3Nlc3NlcyB0aGUgb2JqZWN0IGNvZGUgZWl0aGVyICgxKSBhIGNvcHkgb2YgdGhlIENvcnJlc3BvbmRpbmcgU291cmNlIGZvciBhbGwgdGhlIHNvZnR3YXJlIGluIHRoZSBwcm9kdWN0IHRoYXQgaXMgY292ZXJlZCBieSB0aGlzIExpY2Vuc2UsIG9uIGEgZHVyYWJsZSBwaHlzaWNhbCBtZWRpdW0gY3VzdG9tYXJpbHkgdXNlZCBmb3Igc29mdHdhcmUgaW50ZXJjaGFuZ2UsIGZvciBhIHByaWNlIG5vIG1vcmUgdGhhbiB5b3VyIHJlYXNvbmFibGUgY29zdCBvZiBwaHlzaWNhbGx5IHBlcmZvcm1pbmcgdGhpcyBjb252ZXlpbmcgb2Ygc291cmNlLCBvciAoMikgYWNjZXNzIHRvIGNvcHkgdGhlIENvcnJlc3BvbmRpbmcgU291cmNlIGZyb20gYSBuZXR3b3JrIHNlcnZlciBhdCBubyBjaGFyZ2UuCgogICAgIGMpIENvbnZleSBpbmRpdmlkdWFsIGNvcGllcyBvZiB0aGUgb2JqZWN0IGNvZGUgd2l0aCBhIGNvcHkgb2YgdGhlIHdyaXR0ZW4gb2ZmZXIgdG8gcHJvdmlkZSB0aGUgQ29ycmVzcG9uZGluZyBTb3VyY2UuIFRoaXMgYWx0ZXJuYXRpdmUgaXMgYWxsb3dlZCBvbmx5IG9jY2FzaW9uYWxseSBhbmQgbm9uY29tbWVyY2lhbGx5LCBhbmQgb25seSBpZiB5b3UgcmVjZWl2ZWQgdGhlIG9iamVjdCBjb2RlIHdpdGggc3VjaCBhbiBvZmZlciwgaW4gYWNjb3JkIHdpdGggc3Vic2VjdGlvbiA2Yi4KCiAgICAgZCkgQ29udmV5IHRoZSBvYmplY3QgY29kZSBieSBvZmZlcmluZyBhY2Nlc3MgZnJvbSBhIGRlc2lnbmF0ZWQgcGxhY2UgKGdyYXRpcyBvciBmb3IgYSBjaGFyZ2UpLCBhbmQgb2ZmZXIgZXF1aXZhbGVudCBhY2Nlc3MgdG8gdGhlIENvcnJlc3BvbmRpbmcgU291cmNlIGluIHRoZSBzYW1lIHdheSB0aHJvdWdoIHRoZSBzYW1lIHBsYWNlIGF0IG5vIGZ1cnRoZXIgY2hhcmdlLiBZb3UgbmVlZCBub3QgcmVxdWlyZSByZWNpcGllbnRzIHRvIGNvcHkgdGhlIENvcnJlc3BvbmRpbmcgU291cmNlIGFsb25nIHdpdGggdGhlIG9iamVjdCBjb2RlLiBJZiB0aGUgcGxhY2UgdG8gY29weSB0aGUgb2JqZWN0IGNvZGUgaXMgYSBuZXR3b3JrIHNlcnZlciwgdGhlIENvcnJlc3BvbmRpbmcgU291cmNlIG1heSBiZSBvbiBhIGRpZmZlcmVudCBzZXJ2ZXIgKG9wZXJhdGVkIGJ5IHlvdSBvciBhIHRoaXJkIHBhcnR5KSB0aGF0IHN1cHBvcnRzIGVxdWl2YWxlbnQgY29weWluZyBmYWNpbGl0aWVzLCBwcm92aWRlZCB5b3UgbWFpbnRhaW4gY2xlYXIgZGlyZWN0aW9ucyBuZXh0IHRvIHRoZSBvYmplY3QgY29kZSBzYXlpbmcgd2hlcmUgdG8gZmluZCB0aGUgQ29ycmVzcG9uZGluZyBTb3VyY2UuIFJlZ2FyZGxlc3Mgb2Ygd2hhdCBzZXJ2ZXIgaG9zdHMgdGhlIENvcnJlc3BvbmRpbmcgU291cmNlLCB5b3UgcmVtYWluIG9ibGlnYXRlZCB0byBlbnN1cmUgdGhhdCBpdCBpcyBhdmFpbGFibGUgZm9yIGFzIGxvbmcgYXMgbmVlZGVkIHRvIHNhdGlzZnkgdGhlc2UgcmVxdWlyZW1lbnRzLgoKICAgICBlKSBDb252ZXkgdGhlIG9iamVjdCBjb2RlIHVzaW5nIHBlZXItdG8tcGVlciB0cmFuc21pc3Npb24sIHByb3ZpZGVkIHlvdSBpbmZvcm0gb3RoZXIgcGVlcnMgd2hlcmUgdGhlIG9iamVjdCBjb2RlIGFuZCBDb3JyZXNwb25kaW5nIFNvdXJjZSBvZiB0aGUgd29yayBhcmUgYmVpbmcgb2ZmZXJlZCB0byB0aGUgZ2VuZXJhbCBwdWJsaWMgYXQgbm8gY2hhcmdlIHVuZGVyIHN1YnNlY3Rpb24gNmQuCgpBIHNlcGFyYWJsZSBwb3J0aW9uIG9mIHRoZSBvYmplY3QgY29kZSwgd2hvc2Ugc291cmNlIGNvZGUgaXMgZXhjbHVkZWQgZnJvbSB0aGUgQ29ycmVzcG9uZGluZyBTb3VyY2UgYXMgYSBTeXN0ZW0gTGlicmFyeSwgbmVlZCBub3QgYmUgaW5jbHVkZWQgaW4gY29udmV5aW5nIHRoZSBvYmplY3QgY29kZSB3b3JrLgoKQSDigJxVc2VyIFByb2R1Y3TigJ0gaXMgZWl0aGVyICgxKSBhIOKAnGNvbnN1bWVyIHByb2R1Y3TigJ0sIHdoaWNoIG1lYW5zIGFueSB0YW5naWJsZSBwZXJzb25hbCBwcm9wZXJ0eSB3aGljaCBpcyBub3JtYWxseSB1c2VkIGZvciBwZXJzb25hbCwgZmFtaWx5LCBvciBob3VzZWhvbGQgcHVycG9zZXMsIG9yICgyKSBhbnl0aGluZyBkZXNpZ25lZCBvciBzb2xkIGZvciBpbmNvcnBvcmF0aW9uIGludG8gYSBkd2VsbGluZy4gSW4gZGV0ZXJtaW5pbmcgd2hldGhlciBhIHByb2R1Y3QgaXMgYSBjb25zdW1lciBwcm9kdWN0LCBkb3VidGZ1bCBjYXNlcyBzaGFsbCBiZSByZXNvbHZlZCBpbiBmYXZvciBvZiBjb3ZlcmFnZS4gRm9yIGEgcGFydGljdWxhciBwcm9kdWN0IHJlY2VpdmVkIGJ5IGEgcGFydGljdWxhciB1c2VyLCDigJxub3JtYWxseSB1c2Vk4oCdIHJlZmVycyB0byBhIHR5cGljYWwgb3IgY29tbW9uIHVzZSBvZiB0aGF0IGNsYXNzIG9mIHByb2R1Y3QsIHJlZ2FyZGxlc3Mgb2YgdGhlIHN0YXR1cyBvZiB0aGUgcGFydGljdWxhciB1c2VyIG9yIG9mIHRoZSB3YXkgaW4gd2hpY2ggdGhlIHBhcnRpY3VsYXIgdXNlciBhY3R1YWxseSB1c2VzLCBvciBleHBlY3RzIG9yIGlzIGV4cGVjdGVkIHRvIHVzZSwgdGhlIHByb2R1Y3QuIEEgcHJvZHVjdCBpcyBhIGNvbnN1bWVyIHByb2R1Y3QgcmVnYXJkbGVzcyBvZiB3aGV0aGVyIHRoZSBwcm9kdWN0IGhhcyBzdWJzdGFudGlhbCBjb21tZXJjaWFsLCBpbmR1c3RyaWFsIG9yIG5vbi1jb25zdW1lciB1c2VzLCB1bmxlc3Mgc3VjaCB1c2VzIHJlcHJlc2VudCB0aGUgb25seSBzaWduaWZpY2FudCBtb2RlIG9mIHVzZSBvZiB0aGUgcHJvZHVjdC4KCuKAnEluc3RhbGxhdGlvbiBJbmZvcm1hdGlvbuKAnSBmb3IgYSBVc2VyIFByb2R1Y3QgbWVhbnMgYW55IG1ldGhvZHMsIHByb2NlZHVyZXMsIGF1dGhvcml6YXRpb24ga2V5cywgb3Igb3RoZXIgaW5mb3JtYXRpb24gcmVxdWlyZWQgdG8gaW5zdGFsbCBhbmQgZXhlY3V0ZSBtb2RpZmllZCB2ZXJzaW9ucyBvZiBhIGNvdmVyZWQgd29yayBpbiB0aGF0IFVzZXIgUHJvZHVjdCBmcm9tIGEgbW9kaWZpZWQgdmVyc2lvbiBvZiBpdHMgQ29ycmVzcG9uZGluZyBTb3VyY2UuIFRoZSBpbmZvcm1hdGlvbiBtdXN0IHN1ZmZpY2UgdG8gZW5zdXJlIHRoYXQgdGhlIGNvbnRpbnVlZCBmdW5jdGlvbmluZyBvZiB0aGUgbW9kaWZpZWQgb2JqZWN0IGNvZGUgaXMgaW4gbm8gY2FzZSBwcmV2ZW50ZWQgb3IgaW50ZXJmZXJlZCB3aXRoIHNvbGVseSBiZWNhdXNlIG1vZGlmaWNhdGlvbiBoYXMgYmVlbiBtYWRlLgoKSWYgeW91IGNvbnZleSBhbiBvYmplY3QgY29kZSB3b3JrIHVuZGVyIHRoaXMgc2VjdGlvbiBpbiwgb3Igd2l0aCwgb3Igc3BlY2lmaWNhbGx5IGZvciB1c2UgaW4sIGEgVXNlciBQcm9kdWN0LCBhbmQgdGhlIGNvbnZleWluZyBvY2N1cnMgYXMgcGFydCBvZiBhIHRyYW5zYWN0aW9uIGluIHdoaWNoIHRoZSByaWdodCBvZiBwb3NzZXNzaW9uIGFuZCB1c2Ugb2YgdGhlIFVzZXIgUHJvZHVjdCBpcyB0cmFuc2ZlcnJlZCB0byB0aGUgcmVjaXBpZW50IGluIHBlcnBldHVpdHkgb3IgZm9yIGEgZml4ZWQgdGVybSAocmVnYXJkbGVzcyBvZiBob3cgdGhlIHRyYW5zYWN0aW9uIGlzIGNoYXJhY3Rlcml6ZWQpLCB0aGUgQ29ycmVzcG9uZGluZyBTb3VyY2UgY29udmV5ZWQgdW5kZXIgdGhpcyBzZWN0aW9uIG11c3QgYmUgYWNjb21wYW5pZWQgYnkgdGhlIEluc3RhbGxhdGlvbiBJbmZvcm1hdGlvbi4gQnV0IHRoaXMgcmVxdWlyZW1lbnQgZG9lcyBub3QgYXBwbHkgaWYgbmVpdGhlciB5b3Ugbm9yIGFueSB0aGlyZCBwYXJ0eSByZXRhaW5zIHRoZSBhYmlsaXR5IHRvIGluc3RhbGwgbW9kaWZpZWQgb2JqZWN0IGNvZGUgb24gdGhlIFVzZXIgUHJvZHVjdCAoZm9yIGV4YW1wbGUsIHRoZSB3b3JrIGhhcyBiZWVuIGluc3RhbGxlZCBpbiBST00pLgoKVGhlIHJlcXVpcmVtZW50IHRvIHByb3ZpZGUgSW5zdGFsbGF0aW9uIEluZm9ybWF0aW9uIGRvZXMgbm90IGluY2x1ZGUgYSByZXF1aXJlbWVudCB0byBjb250aW51ZSB0byBwcm92aWRlIHN1cHBvcnQgc2VydmljZSwgd2FycmFudHksIG9yIHVwZGF0ZXMgZm9yIGEgd29yayB0aGF0IGhhcyBiZWVuIG1vZGlmaWVkIG9yIGluc3RhbGxlZCBieSB0aGUgcmVjaXBpZW50LCBvciBmb3IgdGhlIFVzZXIgUHJvZHVjdCBpbiB3aGljaCBpdCBoYXMgYmVlbiBtb2RpZmllZCBvciBpbnN0YWxsZWQuIEFjY2VzcyB0byBhIG5ldHdvcmsgbWF5IGJlIGRlbmllZCB3aGVuIHRoZSBtb2RpZmljYXRpb24gaXRzZWxmIG1hdGVyaWFsbHkgYW5kIGFkdmVyc2VseSBhZmZlY3RzIHRoZSBvcGVyYXRpb24gb2YgdGhlIG5ldHdvcmsgb3IgdmlvbGF0ZXMgdGhlIHJ1bGVzIGFuZCBwcm90b2NvbHMgZm9yIGNvbW11bmljYXRpb24gYWNyb3NzIHRoZSBuZXR3b3JrLgoKQ29ycmVzcG9uZGluZyBTb3VyY2UgY29udmV5ZWQsIGFuZCBJbnN0YWxsYXRpb24gSW5mb3JtYXRpb24gcHJvdmlkZWQsIGluIGFjY29yZCB3aXRoIHRoaXMgc2VjdGlvbiBtdXN0IGJlIGluIGEgZm9ybWF0IHRoYXQgaXMgcHVibGljbHkgZG9jdW1lbnRlZCAoYW5kIHdpdGggYW4gaW1wbGVtZW50YXRpb24gYXZhaWxhYmxlIHRvIHRoZSBwdWJsaWMgaW4gc291cmNlIGNvZGUgZm9ybSksIGFuZCBtdXN0IHJlcXVpcmUgbm8gc3BlY2lhbCBwYXNzd29yZCBvciBrZXkgZm9yIHVucGFja2luZywgcmVhZGluZyBvciBjb3B5aW5nLgoKNy4gQWRkaXRpb25hbCBUZXJtcy4K4oCcQWRkaXRpb25hbCBwZXJtaXNzaW9uc+KAnSBhcmUgdGVybXMgdGhhdCBzdXBwbGVtZW50IHRoZSB0ZXJtcyBvZiB0aGlzIExpY2Vuc2UgYnkgbWFraW5nIGV4Y2VwdGlvbnMgZnJvbSBvbmUgb3IgbW9yZSBvZiBpdHMgY29uZGl0aW9ucy4gQWRkaXRpb25hbCBwZXJtaXNzaW9ucyB0aGF0IGFyZSBhcHBsaWNhYmxlIHRvIHRoZSBlbnRpcmUgUHJvZ3JhbSBzaGFsbCBiZSB0cmVhdGVkIGFzIHRob3VnaCB0aGV5IHdlcmUgaW5jbHVkZWQgaW4gdGhpcyBMaWNlbnNlLCB0byB0aGUgZXh0ZW50IHRoYXQgdGhleSBhcmUgdmFsaWQgdW5kZXIgYXBwbGljYWJsZSBsYXcuIElmIGFkZGl0aW9uYWwgcGVybWlzc2lvbnMgYXBwbHkgb25seSB0byBwYXJ0IG9mIHRoZSBQcm9ncmFtLCB0aGF0IHBhcnQgbWF5IGJlIHVzZWQgc2VwYXJhdGVseSB1bmRlciB0aG9zZSBwZXJtaXNzaW9ucywgYnV0IHRoZSBlbnRpcmUgUHJvZ3JhbSByZW1haW5zIGdvdmVybmVkIGJ5IHRoaXMgTGljZW5zZSB3aXRob3V0IHJlZ2FyZCB0byB0aGUgYWRkaXRpb25hbCBwZXJtaXNzaW9ucy4KCldoZW4geW91IGNvbnZleSBhIGNvcHkgb2YgYSBjb3ZlcmVkIHdvcmssIHlvdSBtYXkgYXQgeW91ciBvcHRpb24gcmVtb3ZlIGFueSBhZGRpdGlvbmFsIHBlcm1pc3Npb25zIGZyb20gdGhhdCBjb3B5LCBvciBmcm9tIGFueSBwYXJ0IG9mIGl0LiAoQWRkaXRpb25hbCBwZXJtaXNzaW9ucyBtYXkgYmUgd3JpdHRlbiB0byByZXF1aXJlIHRoZWlyIG93biByZW1vdmFsIGluIGNlcnRhaW4gY2FzZXMgd2hlbiB5b3UgbW9kaWZ5IHRoZSB3b3JrLikgWW91IG1heSBwbGFjZSBhZGRpdGlvbmFsIHBlcm1pc3Npb25zIG9uIG1hdGVyaWFsLCBhZGRlZCBieSB5b3UgdG8gYSBjb3ZlcmVkIHdvcmssIGZvciB3aGljaCB5b3UgaGF2ZSBvciBjYW4gZ2l2ZSBhcHByb3ByaWF0ZSBjb3B5cmlnaHQgcGVybWlzc2lvbi4KCk5vdHdpdGhzdGFuZGluZyBhbnkgb3RoZXIgcHJvdmlzaW9uIG9mIHRoaXMgTGljZW5zZSwgZm9yIG1hdGVyaWFsIHlvdSBhZGQgdG8gYSBjb3ZlcmVkIHdvcmssIHlvdSBtYXkgKGlmIGF1dGhvcml6ZWQgYnkgdGhlIGNvcHlyaWdodCBob2xkZXJzIG9mIHRoYXQgbWF0ZXJpYWwpIHN1cHBsZW1lbnQgdGhlIHRlcm1zIG9mIHRoaXMgTGljZW5zZSB3aXRoIHRlcm1zOgoKICAgICBhKSBEaXNjbGFpbWluZyB3YXJyYW50eSBvciBsaW1pdGluZyBsaWFiaWxpdHkgZGlmZmVyZW50bHkgZnJvbSB0aGUgdGVybXMgb2Ygc2VjdGlvbnMgMTUgYW5kIDE2IG9mIHRoaXMgTGljZW5zZTsgb3IKCiAgICAgYikgUmVxdWlyaW5nIHByZXNlcnZhdGlvbiBvZiBzcGVjaWZpZWQgcmVhc29uYWJsZSBsZWdhbCBub3RpY2VzIG9yIGF1dGhvciBhdHRyaWJ1dGlvbnMgaW4gdGhhdCBtYXRlcmlhbCBvciBpbiB0aGUgQXBwcm9wcmlhdGUgTGVnYWwgTm90aWNlcyBkaXNwbGF5ZWQgYnkgd29ya3MgY29udGFpbmluZyBpdDsgb3IKCiAgICAgYykgUHJvaGliaXRpbmcgbWlzcmVwcmVzZW50YXRpb24gb2YgdGhlIG9yaWdpbiBvZiB0aGF0IG1hdGVyaWFsLCBvciByZXF1aXJpbmcgdGhhdCBtb2RpZmllZCB2ZXJzaW9ucyBvZiBzdWNoIG1hdGVyaWFsIGJlIG1hcmtlZCBpbiByZWFzb25hYmxlIHdheXMgYXMgZGlmZmVyZW50IGZyb20gdGhlIG9yaWdpbmFsIHZlcnNpb247IG9yCgogICAgIGQpIExpbWl0aW5nIHRoZSB1c2UgZm9yIHB1YmxpY2l0eSBwdXJwb3NlcyBvZiBuYW1lcyBvZiBsaWNlbnNvcnMgb3IgYXV0aG9ycyBvZiB0aGUgbWF0ZXJpYWw7IG9yCgogICAgIGUpIERlY2xpbmluZyB0byBncmFudCByaWdodHMgdW5kZXIgdHJhZGVtYXJrIGxhdyBmb3IgdXNlIG9mIHNvbWUgdHJhZGUgbmFtZXMsIHRyYWRlbWFya3MsIG9yIHNlcnZpY2UgbWFya3M7IG9yCgogICAgIGYpIFJlcXVpcmluZyBpbmRlbW5pZmljYXRpb24gb2YgbGljZW5zb3JzIGFuZCBhdXRob3JzIG9mIHRoYXQgbWF0ZXJpYWwgYnkgYW55b25lIHdobyBjb252ZXlzIHRoZSBtYXRlcmlhbCAob3IgbW9kaWZpZWQgdmVyc2lvbnMgb2YgaXQpIHdpdGggY29udHJhY3R1YWwgYXNzdW1wdGlvbnMgb2YgbGlhYmlsaXR5IHRvIHRoZSByZWNpcGllbnQsIGZvciBhbnkgbGlhYmlsaXR5IHRoYXQgdGhlc2UgY29udHJhY3R1YWwgYXNzdW1wdGlvbnMgZGlyZWN0bHkgaW1wb3NlIG9uIHRob3NlIGxpY2Vuc29ycyBhbmQgYXV0aG9ycy4KCkFsbCBvdGhlciBub24tcGVybWlzc2l2ZSBhZGRpdGlvbmFsIHRlcm1zIGFyZSBjb25zaWRlcmVkIOKAnGZ1cnRoZXIgcmVzdHJpY3Rpb25z4oCdIHdpdGhpbiB0aGUgbWVhbmluZyBvZiBzZWN0aW9uIDEwLiBJZiB0aGUgUHJvZ3JhbSBhcyB5b3UgcmVjZWl2ZWQgaXQsIG9yIGFueSBwYXJ0IG9mIGl0LCBjb250YWlucyBhIG5vdGljZSBzdGF0aW5nIHRoYXQgaXQgaXMgZ292ZXJuZWQgYnkgdGhpcyBMaWNlbnNlIGFsb25nIHdpdGggYSB0ZXJtIHRoYXQgaXMgYSBmdXJ0aGVyIHJlc3RyaWN0aW9uLCB5b3UgbWF5IHJlbW92ZSB0aGF0IHRlcm0uIElmIGEgbGljZW5zZSBkb2N1bWVudCBjb250YWlucyBhIGZ1cnRoZXIgcmVzdHJpY3Rpb24gYnV0IHBlcm1pdHMgcmVsaWNlbnNpbmcgb3IgY29udmV5aW5nIHVuZGVyIHRoaXMgTGljZW5zZSwgeW91IG1heSBhZGQgdG8gYSBjb3ZlcmVkIHdvcmsgbWF0ZXJpYWwgZ292ZXJuZWQgYnkgdGhlIHRlcm1zIG9mIHRoYXQgbGljZW5zZSBkb2N1bWVudCwgcHJvdmlkZWQgdGhhdCB0aGUgZnVydGhlciByZXN0cmljdGlvbiBkb2VzIG5vdCBzdXJ2aXZlIHN1Y2ggcmVsaWNlbnNpbmcgb3IgY29udmV5aW5nLgoKSWYgeW91IGFkZCB0ZXJtcyB0byBhIGNvdmVyZWQgd29yayBpbiBhY2NvcmQgd2l0aCB0aGlzIHNlY3Rpb24sIHlvdSBtdXN0IHBsYWNlLCBpbiB0aGUgcmVsZXZhbnQgc291cmNlIGZpbGVzLCBhIHN0YXRlbWVudCBvZiB0aGUgYWRkaXRpb25hbCB0ZXJtcyB0aGF0IGFwcGx5IHRvIHRob3NlIGZpbGVzLCBvciBhIG5vdGljZSBpbmRpY2F0aW5nIHdoZXJlIHRvIGZpbmQgdGhlIGFwcGxpY2FibGUgdGVybXMuCgpBZGRpdGlvbmFsIHRlcm1zLCBwZXJtaXNzaXZlIG9yIG5vbi1wZXJtaXNzaXZlLCBtYXkgYmUgc3RhdGVkIGluIHRoZSBmb3JtIG9mIGEgc2VwYXJhdGVseSB3cml0dGVuIGxpY2Vuc2UsIG9yIHN0YXRlZCBhcyBleGNlcHRpb25zOyB0aGUgYWJvdmUgcmVxdWlyZW1lbnRzIGFwcGx5IGVpdGhlciB3YXkuCgo4LiBUZXJtaW5hdGlvbi4KWW91IG1heSBub3QgcHJvcGFnYXRlIG9yIG1vZGlmeSBhIGNvdmVyZWQgd29yayBleGNlcHQgYXMgZXhwcmVzc2x5IHByb3ZpZGVkIHVuZGVyIHRoaXMgTGljZW5zZS4gQW55IGF0dGVtcHQgb3RoZXJ3aXNlIHRvIHByb3BhZ2F0ZSBvciBtb2RpZnkgaXQgaXMgdm9pZCwgYW5kIHdpbGwgYXV0b21hdGljYWxseSB0ZXJtaW5hdGUgeW91ciByaWdodHMgdW5kZXIgdGhpcyBMaWNlbnNlIChpbmNsdWRpbmcgYW55IHBhdGVudCBsaWNlbnNlcyBncmFudGVkIHVuZGVyIHRoZSB0aGlyZCBwYXJhZ3JhcGggb2Ygc2VjdGlvbiAxMSkuCgpIb3dldmVyLCBpZiB5b3UgY2Vhc2UgYWxsIHZpb2xhdGlvbiBvZiB0aGlzIExpY2Vuc2UsIHRoZW4geW91ciBsaWNlbnNlIGZyb20gYSBwYXJ0aWN1bGFyIGNvcHlyaWdodCBob2xkZXIgaXMgcmVpbnN0YXRlZCAoYSkgcHJvdmlzaW9uYWxseSwgdW5sZXNzIGFuZCB1bnRpbCB0aGUgY29weXJpZ2h0IGhvbGRlciBleHBsaWNpdGx5IGFuZCBmaW5hbGx5IHRlcm1pbmF0ZXMgeW91ciBsaWNlbnNlLCBhbmQgKGIpIHBlcm1hbmVudGx5LCBpZiB0aGUgY29weXJpZ2h0IGhvbGRlciBmYWlscyB0byBub3RpZnkgeW91IG9mIHRoZSB2aW9sYXRpb24gYnkgc29tZSByZWFzb25hYmxlIG1lYW5zIHByaW9yIHRvIDYwIGRheXMgYWZ0ZXIgdGhlIGNlc3NhdGlvbi4KCk1vcmVvdmVyLCB5b3VyIGxpY2Vuc2UgZnJvbSBhIHBhcnRpY3VsYXIgY29weXJpZ2h0IGhvbGRlciBpcyByZWluc3RhdGVkIHBlcm1hbmVudGx5IGlmIHRoZSBjb3B5cmlnaHQgaG9sZGVyIG5vdGlmaWVzIHlvdSBvZiB0aGUgdmlvbGF0aW9uIGJ5IHNvbWUgcmVhc29uYWJsZSBtZWFucywgdGhpcyBpcyB0aGUgZmlyc3QgdGltZSB5b3UgaGF2ZSByZWNlaXZlZCBub3RpY2Ugb2YgdmlvbGF0aW9uIG9mIHRoaXMgTGljZW5zZSAoZm9yIGFueSB3b3JrKSBmcm9tIHRoYXQgY29weXJpZ2h0IGhvbGRlciwgYW5kIHlvdSBjdXJlIHRoZSB2aW9sYXRpb24gcHJpb3IgdG8gMzAgZGF5cyBhZnRlciB5b3VyIHJlY2VpcHQgb2YgdGhlIG5vdGljZS4KClRlcm1pbmF0aW9uIG9mIHlvdXIgcmlnaHRzIHVuZGVyIHRoaXMgc2VjdGlvbiBkb2VzIG5vdCB0ZXJtaW5hdGUgdGhlIGxpY2Vuc2VzIG9mIHBhcnRpZXMgd2hvIGhhdmUgcmVjZWl2ZWQgY29waWVzIG9yIHJpZ2h0cyBmcm9tIHlvdSB1bmRlciB0aGlzIExpY2Vuc2UuIElmIHlvdXIgcmlnaHRzIGhhdmUgYmVlbiB0ZXJtaW5hdGVkIGFuZCBub3QgcGVybWFuZW50bHkgcmVpbnN0YXRlZCwgeW91IGRvIG5vdCBxdWFsaWZ5IHRvIHJlY2VpdmUgbmV3IGxpY2Vuc2VzIGZvciB0aGUgc2FtZSBtYXRlcmlhbCB1bmRlciBzZWN0aW9uIDEwLgoKOS4gQWNjZXB0YW5jZSBOb3QgUmVxdWlyZWQgZm9yIEhhdmluZyBDb3BpZXMuCllvdSBhcmUgbm90IHJlcXVpcmVkIHRvIGFjY2VwdCB0aGlzIExpY2Vuc2UgaW4gb3JkZXIgdG8gcmVjZWl2ZSBvciBydW4gYSBjb3B5IG9mIHRoZSBQcm9ncmFtLiBBbmNpbGxhcnkgcHJvcGFnYXRpb24gb2YgYSBjb3ZlcmVkIHdvcmsgb2NjdXJyaW5nIHNvbGVseSBhcyBhIGNvbnNlcXVlbmNlIG9mIHVzaW5nIHBlZXItdG8tcGVlciB0cmFuc21pc3Npb24gdG8gcmVjZWl2ZSBhIGNvcHkgbGlrZXdpc2UgZG9lcyBub3QgcmVxdWlyZSBhY2NlcHRhbmNlLiBIb3dldmVyLCBub3RoaW5nIG90aGVyIHRoYW4gdGhpcyBMaWNlbnNlIGdyYW50cyB5b3UgcGVybWlzc2lvbiB0byBwcm9wYWdhdGUgb3IgbW9kaWZ5IGFueSBjb3ZlcmVkIHdvcmsuIFRoZXNlIGFjdGlvbnMgaW5mcmluZ2UgY29weXJpZ2h0IGlmIHlvdSBkbyBub3QgYWNjZXB0IHRoaXMgTGljZW5zZS4gVGhlcmVmb3JlLCBieSBtb2RpZnlpbmcgb3IgcHJvcGFnYXRpbmcgYSBjb3ZlcmVkIHdvcmssIHlvdSBpbmRpY2F0ZSB5b3VyIGFjY2VwdGFuY2Ugb2YgdGhpcyBMaWNlbnNlIHRvIGRvIHNvLgoKMTAuIEF1dG9tYXRpYyBMaWNlbnNpbmcgb2YgRG93bnN0cmVhbSBSZWNpcGllbnRzLgpFYWNoIHRpbWUgeW91IGNvbnZleSBhIGNvdmVyZWQgd29yaywgdGhlIHJlY2lwaWVudCBhdXRvbWF0aWNhbGx5IHJlY2VpdmVzIGEgbGljZW5zZSBmcm9tIHRoZSBvcmlnaW5hbCBsaWNlbnNvcnMsIHRvIHJ1biwgbW9kaWZ5IGFuZCBwcm9wYWdhdGUgdGhhdCB3b3JrLCBzdWJqZWN0IHRvIHRoaXMgTGljZW5zZS4gWW91IGFyZSBub3QgcmVzcG9uc2libGUgZm9yIGVuZm9yY2luZyBjb21wbGlhbmNlIGJ5IHRoaXJkIHBhcnRpZXMgd2l0aCB0aGlzIExpY2Vuc2UuCgpBbiDigJxlbnRpdHkgdHJhbnNhY3Rpb27igJ0gaXMgYSB0cmFuc2FjdGlvbiB0cmFuc2ZlcnJpbmcgY29udHJvbCBvZiBhbiBvcmdhbml6YXRpb24sIG9yIHN1YnN0YW50aWFsbHkgYWxsIGFzc2V0cyBvZiBvbmUsIG9yIHN1YmRpdmlkaW5nIGFuIG9yZ2FuaXphdGlvbiwgb3IgbWVyZ2luZyBvcmdhbml6YXRpb25zLiBJZiBwcm9wYWdhdGlvbiBvZiBhIGNvdmVyZWQgd29yayByZXN1bHRzIGZyb20gYW4gZW50aXR5IHRyYW5zYWN0aW9uLCBlYWNoIHBhcnR5IHRvIHRoYXQgdHJhbnNhY3Rpb24gd2hvIHJlY2VpdmVzIGEgY29weSBvZiB0aGUgd29yayBhbHNvIHJlY2VpdmVzIHdoYXRldmVyIGxpY2Vuc2VzIHRvIHRoZSB3b3JrIHRoZSBwYXJ0eSdzIHByZWRlY2Vzc29yIGluIGludGVyZXN0IGhhZCBvciBjb3VsZCBnaXZlIHVuZGVyIHRoZSBwcmV2aW91cyBwYXJhZ3JhcGgsIHBsdXMgYSByaWdodCB0byBwb3NzZXNzaW9uIG9mIHRoZSBDb3JyZXNwb25kaW5nIFNvdXJjZSBvZiB0aGUgd29yayBmcm9tIHRoZSBwcmVkZWNlc3NvciBpbiBpbnRlcmVzdCwgaWYgdGhlIHByZWRlY2Vzc29yIGhhcyBpdCBvciBjYW4gZ2V0IGl0IHdpdGggcmVhc29uYWJsZSBlZmZvcnRzLgoKWW91IG1heSBub3QgaW1wb3NlIGFueSBmdXJ0aGVyIHJlc3RyaWN0aW9ucyBvbiB0aGUgZXhlcmNpc2Ugb2YgdGhlIHJpZ2h0cyBncmFudGVkIG9yIGFmZmlybWVkIHVuZGVyIHRoaXMgTGljZW5zZS4gRm9yIGV4YW1wbGUsIHlvdSBtYXkgbm90IGltcG9zZSBhIGxpY2Vuc2UgZmVlLCByb3lhbHR5LCBvciBvdGhlciBjaGFyZ2UgZm9yIGV4ZXJjaXNlIG9mIHJpZ2h0cyBncmFudGVkIHVuZGVyIHRoaXMgTGljZW5zZSwgYW5kIHlvdSBtYXkgbm90IGluaXRpYXRlIGxpdGlnYXRpb24gKGluY2x1ZGluZyBhIGNyb3NzLWNsYWltIG9yIGNvdW50ZXJjbGFpbSBpbiBhIGxhd3N1aXQpIGFsbGVnaW5nIHRoYXQgYW55IHBhdGVudCBjbGFpbSBpcyBpbmZyaW5nZWQgYnkgbWFraW5nLCB1c2luZywgc2VsbGluZywgb2ZmZXJpbmcgZm9yIHNhbGUsIG9yIGltcG9ydGluZyB0aGUgUHJvZ3JhbSBvciBhbnkgcG9ydGlvbiBvZiBpdC4KCjExLiBQYXRlbnRzLgpBIOKAnGNvbnRyaWJ1dG9y4oCdIGlzIGEgY29weXJpZ2h0IGhvbGRlciB3aG8gYXV0aG9yaXplcyB1c2UgdW5kZXIgdGhpcyBMaWNlbnNlIG9mIHRoZSBQcm9ncmFtIG9yIGEgd29yayBvbiB3aGljaCB0aGUgUHJvZ3JhbSBpcyBiYXNlZC4gVGhlIHdvcmsgdGh1cyBsaWNlbnNlZCBpcyBjYWxsZWQgdGhlIGNvbnRyaWJ1dG9yJ3Mg4oCcY29udHJpYnV0b3IgdmVyc2lvbuKAnS4KCkEgY29udHJpYnV0b3IncyDigJxlc3NlbnRpYWwgcGF0ZW50IGNsYWltc+KAnSBhcmUgYWxsIHBhdGVudCBjbGFpbXMgb3duZWQgb3IgY29udHJvbGxlZCBieSB0aGUgY29udHJpYnV0b3IsIHdoZXRoZXIgYWxyZWFkeSBhY3F1aXJlZCBvciBoZXJlYWZ0ZXIgYWNxdWlyZWQsIHRoYXQgd291bGQgYmUgaW5mcmluZ2VkIGJ5IHNvbWUgbWFubmVyLCBwZXJtaXR0ZWQgYnkgdGhpcyBMaWNlbnNlLCBvZiBtYWtpbmcsIHVzaW5nLCBvciBzZWxsaW5nIGl0cyBjb250cmlidXRvciB2ZXJzaW9uLCBidXQgZG8gbm90IGluY2x1ZGUgY2xhaW1zIHRoYXQgd291bGQgYmUgaW5mcmluZ2VkIG9ubHkgYXMgYSBjb25zZXF1ZW5jZSBvZiBmdXJ0aGVyIG1vZGlmaWNhdGlvbiBvZiB0aGUgY29udHJpYnV0b3IgdmVyc2lvbi4gRm9yIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwg4oCcY29udHJvbOKAnSBpbmNsdWRlcyB0aGUgcmlnaHQgdG8gZ3JhbnQgcGF0ZW50IHN1YmxpY2Vuc2VzIGluIGEgbWFubmVyIGNvbnNpc3RlbnQgd2l0aCB0aGUgcmVxdWlyZW1lbnRzIG9mIHRoaXMgTGljZW5zZS4KCkVhY2ggY29udHJpYnV0b3IgZ3JhbnRzIHlvdSBhIG5vbi1leGNsdXNpdmUsIHdvcmxkd2lkZSwgcm95YWx0eS1mcmVlIHBhdGVudCBsaWNlbnNlIHVuZGVyIHRoZSBjb250cmlidXRvcidzIGVzc2VudGlhbCBwYXRlbnQgY2xhaW1zLCB0byBtYWtlLCB1c2UsIHNlbGwsIG9mZmVyIGZvciBzYWxlLCBpbXBvcnQgYW5kIG90aGVyd2lzZSBydW4sIG1vZGlmeSBhbmQgcHJvcGFnYXRlIHRoZSBjb250ZW50cyBvZiBpdHMgY29udHJpYnV0b3IgdmVyc2lvbi4KCkluIHRoZSBmb2xsb3dpbmcgdGhyZWUgcGFyYWdyYXBocywgYSDigJxwYXRlbnQgbGljZW5zZeKAnSBpcyBhbnkgZXhwcmVzcyBhZ3JlZW1lbnQgb3IgY29tbWl0bWVudCwgaG93ZXZlciBkZW5vbWluYXRlZCwgbm90IHRvIGVuZm9yY2UgYSBwYXRlbnQgKHN1Y2ggYXMgYW4gZXhwcmVzcyBwZXJtaXNzaW9uIHRvIHByYWN0aWNlIGEgcGF0ZW50IG9yIGNvdmVuYW50IG5vdCB0byBzdWUgZm9yIHBhdGVudCBpbmZyaW5nZW1lbnQpLiBUbyDigJxncmFudOKAnSBzdWNoIGEgcGF0ZW50IGxpY2Vuc2UgdG8gYSBwYXJ0eSBtZWFucyB0byBtYWtlIHN1Y2ggYW4gYWdyZWVtZW50IG9yIGNvbW1pdG1lbnQgbm90IHRvIGVuZm9yY2UgYSBwYXRlbnQgYWdhaW5zdCB0aGUgcGFydHkuCgpJZiB5b3UgY29udmV5IGEgY292ZXJlZCB3b3JrLCBrbm93aW5nbHkgcmVseWluZyBvbiBhIHBhdGVudCBsaWNlbnNlLCBhbmQgdGhlIENvcnJlc3BvbmRpbmcgU291cmNlIG9mIHRoZSB3b3JrIGlzIG5vdCBhdmFpbGFibGUgZm9yIGFueW9uZSB0byBjb3B5LCBmcmVlIG9mIGNoYXJnZSBhbmQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoaXMgTGljZW5zZSwgdGhyb3VnaCBhIHB1YmxpY2x5IGF2YWlsYWJsZSBuZXR3b3JrIHNlcnZlciBvciBvdGhlciByZWFkaWx5IGFjY2Vzc2libGUgbWVhbnMsIHRoZW4geW91IG11c3QgZWl0aGVyICgxKSBjYXVzZSB0aGUgQ29ycmVzcG9uZGluZyBTb3VyY2UgdG8gYmUgc28gYXZhaWxhYmxlLCBvciAoMikgYXJyYW5nZSB0byBkZXByaXZlIHlvdXJzZWxmIG9mIHRoZSBiZW5lZml0IG9mIHRoZSBwYXRlbnQgbGljZW5zZSBmb3IgdGhpcyBwYXJ0aWN1bGFyIHdvcmssIG9yICgzKSBhcnJhbmdlLCBpbiBhIG1hbm5lciBjb25zaXN0ZW50IHdpdGggdGhlIHJlcXVpcmVtZW50cyBvZiB0aGlzIExpY2Vuc2UsIHRvIGV4dGVuZCB0aGUgcGF0ZW50IGxpY2Vuc2UgdG8gZG93bnN0cmVhbSByZWNpcGllbnRzLiDigJxLbm93aW5nbHkgcmVseWluZ+KAnSBtZWFucyB5b3UgaGF2ZSBhY3R1YWwga25vd2xlZGdlIHRoYXQsIGJ1dCBmb3IgdGhlIHBhdGVudCBsaWNlbnNlLCB5b3VyIGNvbnZleWluZyB0aGUgY292ZXJlZCB3b3JrIGluIGEgY291bnRyeSwgb3IgeW91ciByZWNpcGllbnQncyB1c2Ugb2YgdGhlIGNvdmVyZWQgd29yayBpbiBhIGNvdW50cnksIHdvdWxkIGluZnJpbmdlIG9uZSBvciBtb3JlIGlkZW50aWZpYWJsZSBwYXRlbnRzIGluIHRoYXQgY291bnRyeSB0aGF0IHlvdSBoYXZlIHJlYXNvbiB0byBiZWxpZXZlIGFyZSB2YWxpZC4KCklmLCBwdXJzdWFudCB0byBvciBpbiBjb25uZWN0aW9uIHdpdGggYSBzaW5nbGUgdHJhbnNhY3Rpb24gb3IgYXJyYW5nZW1lbnQsIHlvdSBjb252ZXksIG9yIHByb3BhZ2F0ZSBieSBwcm9jdXJpbmcgY29udmV5YW5jZSBvZiwgYSBjb3ZlcmVkIHdvcmssIGFuZCBncmFudCBhIHBhdGVudCBsaWNlbnNlIHRvIHNvbWUgb2YgdGhlIHBhcnRpZXMgcmVjZWl2aW5nIHRoZSBjb3ZlcmVkIHdvcmsgYXV0aG9yaXppbmcgdGhlbSB0byB1c2UsIHByb3BhZ2F0ZSwgbW9kaWZ5IG9yIGNvbnZleSBhIHNwZWNpZmljIGNvcHkgb2YgdGhlIGNvdmVyZWQgd29yaywgdGhlbiB0aGUgcGF0ZW50IGxpY2Vuc2UgeW91IGdyYW50IGlzIGF1dG9tYXRpY2FsbHkgZXh0ZW5kZWQgdG8gYWxsIHJlY2lwaWVudHMgb2YgdGhlIGNvdmVyZWQgd29yayBhbmQgd29ya3MgYmFzZWQgb24gaXQuCgpBIHBhdGVudCBsaWNlbnNlIGlzIOKAnGRpc2NyaW1pbmF0b3J54oCdIGlmIGl0IGRvZXMgbm90IGluY2x1ZGUgd2l0aGluIHRoZSBzY29wZSBvZiBpdHMgY292ZXJhZ2UsIHByb2hpYml0cyB0aGUgZXhlcmNpc2Ugb2YsIG9yIGlzIGNvbmRpdGlvbmVkIG9uIHRoZSBub24tZXhlcmNpc2Ugb2Ygb25lIG9yIG1vcmUgb2YgdGhlIHJpZ2h0cyB0aGF0IGFyZSBzcGVjaWZpY2FsbHkgZ3JhbnRlZCB1bmRlciB0aGlzIExpY2Vuc2UuIFlvdSBtYXkgbm90IGNvbnZleSBhIGNvdmVyZWQgd29yayBpZiB5b3UgYXJlIGEgcGFydHkgdG8gYW4gYXJyYW5nZW1lbnQgd2l0aCBhIHRoaXJkIHBhcnR5IHRoYXQgaXMgaW4gdGhlIGJ1c2luZXNzIG9mIGRpc3RyaWJ1dGluZyBzb2Z0d2FyZSwgdW5kZXIgd2hpY2ggeW91IG1ha2UgcGF5bWVudCB0byB0aGUgdGhpcmQgcGFydHkgYmFzZWQgb24gdGhlIGV4dGVudCBvZiB5b3VyIGFjdGl2aXR5IG9mIGNvbnZleWluZyB0aGUgd29yaywgYW5kIHVuZGVyIHdoaWNoIHRoZSB0aGlyZCBwYXJ0eSBncmFudHMsIHRvIGFueSBvZiB0aGUgcGFydGllcyB3aG8gd291bGQgcmVjZWl2ZSB0aGUgY292ZXJlZCB3b3JrIGZyb20geW91LCBhIGRpc2NyaW1pbmF0b3J5IHBhdGVudCBsaWNlbnNlIChhKSBpbiBjb25uZWN0aW9uIHdpdGggY29waWVzIG9mIHRoZSBjb3ZlcmVkIHdvcmsgY29udmV5ZWQgYnkgeW91IChvciBjb3BpZXMgbWFkZSBmcm9tIHRob3NlIGNvcGllcyksIG9yIChiKSBwcmltYXJpbHkgZm9yIGFuZCBpbiBjb25uZWN0aW9uIHdpdGggc3BlY2lmaWMgcHJvZHVjdHMgb3IgY29tcGlsYXRpb25zIHRoYXQgY29udGFpbiB0aGUgY292ZXJlZCB3b3JrLCB1bmxlc3MgeW91IGVudGVyZWQgaW50byB0aGF0IGFycmFuZ2VtZW50LCBvciB0aGF0IHBhdGVudCBsaWNlbnNlIHdhcyBncmFudGVkLCBwcmlvciB0byAyOCBNYXJjaCAyMDA3LgoKTm90aGluZyBpbiB0aGlzIExpY2Vuc2Ugc2hhbGwgYmUgY29uc3RydWVkIGFzIGV4Y2x1ZGluZyBvciBsaW1pdGluZyBhbnkgaW1wbGllZCBsaWNlbnNlIG9yIG90aGVyIGRlZmVuc2VzIHRvIGluZnJpbmdlbWVudCB0aGF0IG1heSBvdGhlcndpc2UgYmUgYXZhaWxhYmxlIHRvIHlvdSB1bmRlciBhcHBsaWNhYmxlIHBhdGVudCBsYXcuCgoxMi4gTm8gU3VycmVuZGVyIG9mIE90aGVycycgRnJlZWRvbS4KSWYgY29uZGl0aW9ucyBhcmUgaW1wb3NlZCBvbiB5b3UgKHdoZXRoZXIgYnkgY291cnQgb3JkZXIsIGFncmVlbWVudCBvciBvdGhlcndpc2UpIHRoYXQgY29udHJhZGljdCB0aGUgY29uZGl0aW9ucyBvZiB0aGlzIExpY2Vuc2UsIHRoZXkgZG8gbm90IGV4Y3VzZSB5b3UgZnJvbSB0aGUgY29uZGl0aW9ucyBvZiB0aGlzIExpY2Vuc2UuIElmIHlvdSBjYW5ub3QgY29udmV5IGEgY292ZXJlZCB3b3JrIHNvIGFzIHRvIHNhdGlzZnkgc2ltdWx0YW5lb3VzbHkgeW91ciBvYmxpZ2F0aW9ucyB1bmRlciB0aGlzIExpY2Vuc2UgYW5kIGFueSBvdGhlciBwZXJ0aW5lbnQgb2JsaWdhdGlvbnMsIHRoZW4gYXMgYSBjb25zZXF1ZW5jZSB5b3UgbWF5IG5vdCBjb252ZXkgaXQgYXQgYWxsLiBGb3IgZXhhbXBsZSwgaWYgeW91IGFncmVlIHRvIHRlcm1zIHRoYXQgb2JsaWdhdGUgeW91IHRvIGNvbGxlY3QgYSByb3lhbHR5IGZvciBmdXJ0aGVyIGNvbnZleWluZyBmcm9tIHRob3NlIHRvIHdob20geW91IGNvbnZleSB0aGUgUHJvZ3JhbSwgdGhlIG9ubHkgd2F5IHlvdSBjb3VsZCBzYXRpc2Z5IGJvdGggdGhvc2UgdGVybXMgYW5kIHRoaXMgTGljZW5zZSB3b3VsZCBiZSB0byByZWZyYWluIGVudGlyZWx5IGZyb20gY29udmV5aW5nIHRoZSBQcm9ncmFtLgoKMTMuIFVzZSB3aXRoIHRoZSBHTlUgQWZmZXJvIEdlbmVyYWwgUHVibGljIExpY2Vuc2UuCk5vdHdpdGhzdGFuZGluZyBhbnkgb3RoZXIgcHJvdmlzaW9uIG9mIHRoaXMgTGljZW5zZSwgeW91IGhhdmUgcGVybWlzc2lvbiB0byBsaW5rIG9yIGNvbWJpbmUgYW55IGNvdmVyZWQgd29yayB3aXRoIGEgd29yayBsaWNlbnNlZCB1bmRlciB2ZXJzaW9uIDMgb2YgdGhlIEdOVSBBZmZlcm8gR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBpbnRvIGEgc2luZ2xlIGNvbWJpbmVkIHdvcmssIGFuZCB0byBjb252ZXkgdGhlIHJlc3VsdGluZyB3b3JrLiBUaGUgdGVybXMgb2YgdGhpcyBMaWNlbnNlIHdpbGwgY29udGludWUgdG8gYXBwbHkgdG8gdGhlIHBhcnQgd2hpY2ggaXMgdGhlIGNvdmVyZWQgd29yaywgYnV0IHRoZSBzcGVjaWFsIHJlcXVpcmVtZW50cyBvZiB0aGUgR05VIEFmZmVybyBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlLCBzZWN0aW9uIDEzLCBjb25jZXJuaW5nIGludGVyYWN0aW9uIHRocm91Z2ggYSBuZXR3b3JrIHdpbGwgYXBwbHkgdG8gdGhlIGNvbWJpbmF0aW9uIGFzIHN1Y2guCgoxNC4gUmV2aXNlZCBWZXJzaW9ucyBvZiB0aGlzIExpY2Vuc2UuClRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24gbWF5IHB1Ymxpc2ggcmV2aXNlZCBhbmQvb3IgbmV3IHZlcnNpb25zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmcm9tIHRpbWUgdG8gdGltZS4gU3VjaCBuZXcgdmVyc2lvbnMgd2lsbCBiZSBzaW1pbGFyIGluIHNwaXJpdCB0byB0aGUgcHJlc2VudCB2ZXJzaW9uLCBidXQgbWF5IGRpZmZlciBpbiBkZXRhaWwgdG8gYWRkcmVzcyBuZXcgcHJvYmxlbXMgb3IgY29uY2VybnMuCgpFYWNoIHZlcnNpb24gaXMgZ2l2ZW4gYSBkaXN0aW5ndWlzaGluZyB2ZXJzaW9uIG51bWJlci4gSWYgdGhlIFByb2dyYW0gc3BlY2lmaWVzIHRoYXQgYSBjZXJ0YWluIG51bWJlcmVkIHZlcnNpb24gb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIOKAnG9yIGFueSBsYXRlciB2ZXJzaW9u4oCdIGFwcGxpZXMgdG8gaXQsIHlvdSBoYXZlIHRoZSBvcHRpb24gb2YgZm9sbG93aW5nIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBlaXRoZXIgb2YgdGhhdCBudW1iZXJlZCB2ZXJzaW9uIG9yIG9mIGFueSBsYXRlciB2ZXJzaW9uIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLiBJZiB0aGUgUHJvZ3JhbSBkb2VzIG5vdCBzcGVjaWZ5IGEgdmVyc2lvbiBudW1iZXIgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlLCB5b3UgbWF5IGNob29zZSBhbnkgdmVyc2lvbiBldmVyIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLgoKSWYgdGhlIFByb2dyYW0gc3BlY2lmaWVzIHRoYXQgYSBwcm94eSBjYW4gZGVjaWRlIHdoaWNoIGZ1dHVyZSB2ZXJzaW9ucyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgY2FuIGJlIHVzZWQsIHRoYXQgcHJveHkncyBwdWJsaWMgc3RhdGVtZW50IG9mIGFjY2VwdGFuY2Ugb2YgYSB2ZXJzaW9uIHBlcm1hbmVudGx5IGF1dGhvcml6ZXMgeW91IHRvIGNob29zZSB0aGF0IHZlcnNpb24gZm9yIHRoZSBQcm9ncmFtLgoKTGF0ZXIgbGljZW5zZSB2ZXJzaW9ucyBtYXkgZ2l2ZSB5b3UgYWRkaXRpb25hbCBvciBkaWZmZXJlbnQgcGVybWlzc2lvbnMuIEhvd2V2ZXIsIG5vIGFkZGl0aW9uYWwgb2JsaWdhdGlvbnMgYXJlIGltcG9zZWQgb24gYW55IGF1dGhvciBvciBjb3B5cmlnaHQgaG9sZGVyIGFzIGEgcmVzdWx0IG9mIHlvdXIgY2hvb3NpbmcgdG8gZm9sbG93IGEgbGF0ZXIgdmVyc2lvbi4KCjE1LiBEaXNjbGFpbWVyIG9mIFdhcnJhbnR5LgpUSEVSRSBJUyBOTyBXQVJSQU5UWSBGT1IgVEhFIFBST0dSQU0sIFRPIFRIRSBFWFRFTlQgUEVSTUlUVEVEIEJZIEFQUExJQ0FCTEUgTEFXLiBFWENFUFQgV0hFTiBPVEhFUldJU0UgU1RBVEVEIElOIFdSSVRJTkcgVEhFIENPUFlSSUdIVCBIT0xERVJTIEFORC9PUiBPVEhFUiBQQVJUSUVTIFBST1ZJREUgVEhFIFBST0dSQU0g4oCcQVMgSVPigJ0gV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRUlUSEVSIEVYUFJFU1NFRCBPUiBJTVBMSUVELCBJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFIElNUExJRUQgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBUSEUgRU5USVJFIFJJU0sgQVMgVE8gVEhFIFFVQUxJVFkgQU5EIFBFUkZPUk1BTkNFIE9GIFRIRSBQUk9HUkFNIElTIFdJVEggWU9VLiBTSE9VTEQgVEhFIFBST0dSQU0gUFJPVkUgREVGRUNUSVZFLCBZT1UgQVNTVU1FIFRIRSBDT1NUIE9GIEFMTCBORUNFU1NBUlkgU0VSVklDSU5HLCBSRVBBSVIgT1IgQ09SUkVDVElPTi4KCjE2LiBMaW1pdGF0aW9uIG9mIExpYWJpbGl0eS4KSU4gTk8gRVZFTlQgVU5MRVNTIFJFUVVJUkVEIEJZIEFQUExJQ0FCTEUgTEFXIE9SIEFHUkVFRCBUTyBJTiBXUklUSU5HIFdJTEwgQU5ZIENPUFlSSUdIVCBIT0xERVIsIE9SIEFOWSBPVEhFUiBQQVJUWSBXSE8gTU9ESUZJRVMgQU5EL09SIENPTlZFWVMgVEhFIFBST0dSQU0gQVMgUEVSTUlUVEVEIEFCT1ZFLCBCRSBMSUFCTEUgVE8gWU9VIEZPUiBEQU1BR0VTLCBJTkNMVURJTkcgQU5ZIEdFTkVSQUwsIFNQRUNJQUwsIElOQ0lERU5UQUwgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTIEFSSVNJTkcgT1VUIE9GIFRIRSBVU0UgT1IgSU5BQklMSVRZIFRPIFVTRSBUSEUgUFJPR1JBTSAoSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBMT1NTIE9GIERBVEEgT1IgREFUQSBCRUlORyBSRU5ERVJFRCBJTkFDQ1VSQVRFIE9SIExPU1NFUyBTVVNUQUlORUQgQlkgWU9VIE9SIFRISVJEIFBBUlRJRVMgT1IgQSBGQUlMVVJFIE9GIFRIRSBQUk9HUkFNIFRPIE9QRVJBVEUgV0lUSCBBTlkgT1RIRVIgUFJPR1JBTVMpLCBFVkVOIElGIFNVQ0ggSE9MREVSIE9SIE9USEVSIFBBUlRZIEhBUyBCRUVOIEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GIFNVQ0ggREFNQUdFUy4KCjE3LiBJbnRlcnByZXRhdGlvbiBvZiBTZWN0aW9ucyAxNSBhbmQgMTYuCklmIHRoZSBkaXNjbGFpbWVyIG9mIHdhcnJhbnR5IGFuZCBsaW1pdGF0aW9uIG9mIGxpYWJpbGl0eSBwcm92aWRlZCBhYm92ZSBjYW5ub3QgYmUgZ2l2ZW4gbG9jYWwgbGVnYWwgZWZmZWN0IGFjY29yZGluZyB0byB0aGVpciB0ZXJtcywgcmV2aWV3aW5nIGNvdXJ0cyBzaGFsbCBhcHBseSBsb2NhbCBsYXcgdGhhdCBtb3N0IGNsb3NlbHkgYXBwcm94aW1hdGVzIGFuIGFic29sdXRlIHdhaXZlciBvZiBhbGwgY2l2aWwgbGlhYmlsaXR5IGluIGNvbm5lY3Rpb24gd2l0aCB0aGUgUHJvZ3JhbSwgdW5sZXNzIGEgd2FycmFudHkgb3IgYXNzdW1wdGlvbiBvZiBsaWFiaWxpdHkgYWNjb21wYW5pZXMgYSBjb3B5IG9mIHRoZSBQcm9ncmFtIGluIHJldHVybiBmb3IgYSBmZWUuCgpFTkQgT0YgVEVSTVMgQU5EIENPTkRJVElPTlMKCkhvdyB0byBBcHBseSBUaGVzZSBUZXJtcyB0byBZb3VyIE5ldyBQcm9ncmFtcwoKSWYgeW91IGRldmVsb3AgYSBuZXcgcHJvZ3JhbSwgYW5kIHlvdSB3YW50IGl0IHRvIGJlIG9mIHRoZSBncmVhdGVzdCBwb3NzaWJsZSB1c2UgdG8gdGhlIHB1YmxpYywgdGhlIGJlc3Qgd2F5IHRvIGFjaGlldmUgdGhpcyBpcyB0byBtYWtlIGl0IGZyZWUgc29mdHdhcmUgd2hpY2ggZXZlcnlvbmUgY2FuIHJlZGlzdHJpYnV0ZSBhbmQgY2hhbmdlIHVuZGVyIHRoZXNlIHRlcm1zLgoKVG8gZG8gc28sIGF0dGFjaCB0aGUgZm9sbG93aW5nIG5vdGljZXMgdG8gdGhlIHByb2dyYW0uIEl0IGlzIHNhZmVzdCB0byBhdHRhY2ggdGhlbSB0byB0aGUgc3RhcnQgb2YgZWFjaCBzb3VyY2UgZmlsZSB0byBtb3N0IGVmZmVjdGl2ZWx5IHN0YXRlIHRoZSBleGNsdXNpb24gb2Ygd2FycmFudHk7IGFuZCBlYWNoIGZpbGUgc2hvdWxkIGhhdmUgYXQgbGVhc3QgdGhlIOKAnGNvcHlyaWdodOKAnSBsaW5lIGFuZCBhIHBvaW50ZXIgdG8gd2hlcmUgdGhlIGZ1bGwgbm90aWNlIGlzIGZvdW5kLgoKICAgICA8b25lIGxpbmUgdG8gZ2l2ZSB0aGUgcHJvZ3JhbSdzIG5hbWUgYW5kIGEgYnJpZWYgaWRlYSBvZiB3aGF0IGl0IGRvZXMuPgogICAgIENvcHlyaWdodCAoQykgPHllYXI+ICA8bmFtZSBvZiBhdXRob3I+CgogICAgIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uCgogICAgIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuCgogICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LgoKQWxzbyBhZGQgaW5mb3JtYXRpb24gb24gaG93IHRvIGNvbnRhY3QgeW91IGJ5IGVsZWN0cm9uaWMgYW5kIHBhcGVyIG1haWwuCgpJZiB0aGUgcHJvZ3JhbSBkb2VzIHRlcm1pbmFsIGludGVyYWN0aW9uLCBtYWtlIGl0IG91dHB1dCBhIHNob3J0IG5vdGljZSBsaWtlIHRoaXMgd2hlbiBpdCBzdGFydHMgaW4gYW4gaW50ZXJhY3RpdmUgbW9kZToKCiAgICAgPHByb2dyYW0+ICBDb3B5cmlnaHQgKEMpIDx5ZWFyPiAgPG5hbWUgb2YgYXV0aG9yPgogICAgIFRoaXMgcHJvZ3JhbSBjb21lcyB3aXRoIEFCU09MVVRFTFkgTk8gV0FSUkFOVFk7IGZvciBkZXRhaWxzIHR5cGUgYHNob3cgdycuCiAgICAgVGhpcyBpcyBmcmVlIHNvZnR3YXJlLCBhbmQgeW91IGFyZSB3ZWxjb21lIHRvIHJlZGlzdHJpYnV0ZSBpdCB1bmRlciBjZXJ0YWluIGNvbmRpdGlvbnM7IHR5cGUgYHNob3cgYycgZm9yIGRldGFpbHMuCgpUaGUgaHlwb3RoZXRpY2FsIGNvbW1hbmRzIGBzaG93IHcnIGFuZCBgc2hvdyBjJyBzaG91bGQgc2hvdyB0aGUgYXBwcm9wcmlhdGUgcGFydHMgb2YgdGhlIEdlbmVyYWwgUHVibGljIExpY2Vuc2UuIE9mIGNvdXJzZSwgeW91ciBwcm9ncmFtJ3MgY29tbWFuZHMgbWlnaHQgYmUgZGlmZmVyZW50OyBmb3IgYSBHVUkgaW50ZXJmYWNlLCB5b3Ugd291bGQgdXNlIGFuIOKAnGFib3V0IGJveOKAnS4KCllvdSBzaG91bGQgYWxzbyBnZXQgeW91ciBlbXBsb3llciAoaWYgeW91IHdvcmsgYXMgYSBwcm9ncmFtbWVyKSBvciBzY2hvb2wsIGlmIGFueSwgdG8gc2lnbiBhIOKAnGNvcHlyaWdodCBkaXNjbGFpbWVy4oCdIGZvciB0aGUgcHJvZ3JhbSwgaWYgbmVjZXNzYXJ5LiBGb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiB0aGlzLCBhbmQgaG93IHRvIGFwcGx5IGFuZCBmb2xsb3cgdGhlIEdOVSBHUEwsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uCgpUaGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZG9lcyBub3QgcGVybWl0IGluY29ycG9yYXRpbmcgeW91ciBwcm9ncmFtIGludG8gcHJvcHJpZXRhcnkgcHJvZ3JhbXMuIElmIHlvdXIgcHJvZ3JhbSBpcyBhIHN1YnJvdXRpbmUgbGlicmFyeSwgeW91IG1heSBjb25zaWRlciBpdCBtb3JlIHVzZWZ1bCB0byBwZXJtaXQgbGlua2luZyBwcm9wcmlldGFyeSBhcHBsaWNhdGlvbnMgd2l0aCB0aGUgbGlicmFyeS4gSWYgdGhpcyBpcyB3aGF0IHlvdSB3YW50IHRvIGRvLCB1c2UgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBpbnN0ZWFkIG9mIHRoaXMgTGljZW5zZS4gQnV0IGZpcnN0LCBwbGVhc2UgcmVhZCA8aHR0cDovL3d3dy5nbnUub3JnL3BoaWxvc29waHkvd2h5LW5vdC1sZ3BsLmh0bWw+Lg=="},"url":"https:\/\/www.gnu.org\/licenses\/gpl-3.0-standalone.html"}}],"version":"1.0.0-alpha","cpe":"cpe:2.3:a:themeum:tutor_lms:1.0.0:alpha:*:*:*:wordpress:*:*","purl":"pkg:github\/themeum\/tutor@1.0.0-alpha","supplier":{"name":"themeum"},"bom-ref":"tutor_1.0.0-alpha_05f9676f-d8d3-4167-841a-fddbd008d398","description":"","copyright":"","properties":[{"name":"component_id","value":"18"}]},{"name":"Joke","type":"library","licenses":[{"license":{"id":"Apache-2.0","text":{"contentType":"text\/plain","encoding":"base64","content":"QXBhY2hlIExpY2Vuc2UKVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNApodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvCgpURVJNUyBBTkQgQ09ORElUSU9OUyBGT1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04KCjEuIERlZmluaXRpb25zLgoKIkxpY2Vuc2UiIHNoYWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBhcyBkZWZpbmVkIGJ5IFNlY3Rpb25zIDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuCgoiTGljZW5zb3IiIHNoYWxsIG1lYW4gdGhlIGNvcHlyaWdodCBvd25lciBvciBlbnRpdHkgYXV0aG9yaXplZCBieSB0aGUgY29weXJpZ2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhlIExpY2Vuc2UuCgoiTGVnYWwgRW50aXR5IiBzaGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsIG90aGVyIGVudGl0aWVzIHRoYXQgY29udHJvbCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRlciBjb21tb24gY29udHJvbCB3aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIsIGRpcmVjdCBvciBpbmRpcmVjdCwgdG8gY2F1c2UgdGhlIGRpcmVjdGlvbiBvciBtYW5hZ2VtZW50IG9mIHN1Y2ggZW50aXR5LCB3aGV0aGVyIGJ5IGNvbnRyYWN0IG9yIG90aGVyd2lzZSwgb3IgKGlpKSBvd25lcnNoaXAgb2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZSBvdXRzdGFuZGluZyBzaGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJzaGlwIG9mIHN1Y2ggZW50aXR5LgoKIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eSBleGVyY2lzaW5nIHBlcm1pc3Npb25zIGdyYW50ZWQgYnkgdGhpcyBMaWNlbnNlLgoKIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3IgbWFraW5nIG1vZGlmaWNhdGlvbnMsIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gc29mdHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRpb24gc291cmNlLCBhbmQgY29uZmlndXJhdGlvbiBmaWxlcy4KCiJPYmplY3QiIGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9ybSByZXN1bHRpbmcgZnJvbSBtZWNoYW5pY2FsIHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5zbGF0aW9uIG9mIGEgU291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gY29tcGlsZWQgb2JqZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLCBhbmQgY29udmVyc2lvbnMgdG8gb3RoZXIgbWVkaWEgdHlwZXMuCgoiV29yayIgc2hhbGwgbWVhbiB0aGUgd29yayBvZiBhdXRob3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgbWFkZSBhdmFpbGFibGUgdW5kZXIgdGhlIExpY2Vuc2UsIGFzIGluZGljYXRlZCBieSBhIGNvcHlyaWdodCBub3RpY2UgdGhhdCBpcyBpbmNsdWRlZCBpbiBvciBhdHRhY2hlZCB0byB0aGUgd29yayAoYW4gZXhhbXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBwZW5kaXggYmVsb3cpLgoKIkRlcml2YXRpdmUgV29ya3MiIHNoYWxsIG1lYW4gYW55IHdvcmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdCBmb3JtLCB0aGF0IGlzIGJhc2VkIG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBmb3Igd2hpY2ggdGhlIGVkaXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBlbGFib3JhdGlvbnMsIG9yIG90aGVyIG1vZGlmaWNhdGlvbnMgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBhbiBvcmlnaW5hbCB3b3JrIG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyBMaWNlbnNlLCBEZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQgcmVtYWluIHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAob3IgYmluZCBieSBuYW1lKSB0byB0aGUgaW50ZXJmYWNlcyBvZiwgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZi4KCiJDb250cmlidXRpb24iIHNoYWxsIG1lYW4gYW55IHdvcmsgb2YgYXV0aG9yc2hpcCwgaW5jbHVkaW5nIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBhbnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMgdG8gdGhhdCBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5IHN1Ym1pdHRlZCB0byBMaWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRoZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgYnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXplZCB0byBzdWJtaXQgb24gYmVoYWxmIG9mIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIiBtZWFucyBhbnkgZm9ybSBvZiBlbGVjdHJvbmljLCB2ZXJiYWwsIG9yIHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBzZW50IHRvIHRoZSBMaWNlbnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBtYWlsaW5nIGxpc3RzLCBzb3VyY2UgY29kZSBjb250cm9sIHN5c3RlbXMsIGFuZCBpc3N1ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQgYXJlIG1hbmFnZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwgdGhlIExpY2Vuc29yIGZvciB0aGUgcHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXByb3ZpbmcgdGhlIFdvcmssIGJ1dCBleGNsdWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlzIGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVyd2lzZSBkZXNpZ25hdGVkIGluIHdyaXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAiTm90IGEgQ29udHJpYnV0aW9uLiIKCiJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNvciBhbmQgYW55IGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IG9uIGJlaGFsZiBvZiB3aG9tIGEgQ29udHJpYnV0aW9uIGhhcyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZCBzdWJzZXF1ZW50bHkgaW5jb3Jwb3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCjIuIEdyYW50IG9mIENvcHlyaWdodCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB0aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1YWwsIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUsIGlycmV2b2NhYmxlIGNvcHlyaWdodCBsaWNlbnNlIHRvIHJlcHJvZHVjZSwgcHJlcGFyZSBEZXJpdmF0aXZlIFdvcmtzIG9mLCBwdWJsaWNseSBkaXNwbGF5LCBwdWJsaWNseSBwZXJmb3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUgV29yayBhbmQgc3VjaCBEZXJpdmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4KCjMuIEdyYW50IG9mIFBhdGVudCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB0aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1YWwsIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUsIGlycmV2b2NhYmxlIChleGNlcHQgYXMgc3RhdGVkIGluIHRoaXMgc2VjdGlvbikgcGF0ZW50IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLCB1c2UsIG9mZmVyIHRvIHNlbGwsIHNlbGwsIGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29yaywgd2hlcmUgc3VjaCBsaWNlbnNlIGFwcGxpZXMgb25seSB0byB0aG9zZSBwYXRlbnQgY2xhaW1zIGxpY2Vuc2FibGUgYnkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNlc3NhcmlseSBpbmZyaW5nZWQgYnkgdGhlaXIgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9yIGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENvbnRyaWJ1dGlvbihzKSB3aXRoIHRoZSBXb3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9uKHMpIHdhcyBzdWJtaXR0ZWQuIElmIFlvdSBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24gYWdhaW5zdCBhbnkgZW50aXR5IChpbmNsdWRpbmcgYSBjcm9zcy1jbGFpbSBvciBjb3VudGVyY2xhaW0gaW4gYSBsYXdzdWl0KSBhbGxlZ2luZyB0aGF0IHRoZSBXb3JrIG9yIGEgQ29udHJpYnV0aW9uIGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGlyZWN0IG9yIGNvbnRyaWJ1dG9yeSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGljZW5zZXMgZ3JhbnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsgc2hhbGwgdGVybWluYXRlIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0aWdhdGlvbiBpcyBmaWxlZC4KCjQuIFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBjb3BpZXMgb2YgdGhlIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mIGluIGFueSBtZWRpdW0sIHdpdGggb3Igd2l0aG91dCBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9yIE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdSBtZWV0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczoKCiAgICAgKGEpIFlvdSBtdXN0IGdpdmUgYW55IG90aGVyIHJlY2lwaWVudHMgb2YgdGhlIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgKGIpIFlvdSBtdXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBwcm9taW5lbnQgbm90aWNlcyBzdGF0aW5nIHRoYXQgWW91IGNoYW5nZWQgdGhlIGZpbGVzOyBhbmQKCiAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsbCBjb3B5cmlnaHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQgYXR0cmlidXRpb24gbm90aWNlcyBmcm9tIHRoZSBTb3VyY2UgZm9ybSBvZiB0aGUgV29yaywgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrczsgYW5kCgogICAgIChkKSBJZiB0aGUgV29yayBpbmNsdWRlcyBhICJOT1RJQ0UiIHRleHQgZmlsZSBhcyBwYXJ0IG9mIGl0cyBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0IGluY2x1ZGUgYSByZWFkYWJsZSBjb3B5IG9mIHRoZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZCB3aXRoaW4gc3VjaCBOT1RJQ0UgZmlsZSwgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiB3aXRoaW4gYSBOT1RJQ0UgdGV4dCBmaWxlIGRpc3RyaWJ1dGVkIGFzIHBhcnQgb2YgdGhlIERlcml2YXRpdmUgV29ya3M7IHdpdGhpbiB0aGUgU291cmNlIGZvcm0gb3IgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsIHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBhbmQgd2hlcmV2ZXIgc3VjaCB0aGlyZC1wYXJ0eSBub3RpY2VzIG5vcm1hbGx5IGFwcGVhci4gVGhlIGNvbnRlbnRzIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQgZG8gbm90IG1vZGlmeSB0aGUgTGljZW5zZS4gWW91IG1heSBhZGQgWW91ciBvd24gYXR0cmlidXRpb24gbm90aWNlcyB3aXRoaW4gRGVyaXZhdGl2ZSBXb3JrcyB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbG9uZ3NpZGUgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkIHRoYXQgc3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0aW9uIG5vdGljZXMgY2Fubm90IGJlIGNvbnN0cnVlZCBhcyBtb2RpZnlpbmcgdGhlIExpY2Vuc2UuCgogICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZCBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aCB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLCBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZSBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZSBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCjcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLCBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55IHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCjguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LCB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLCBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZSBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZyB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLCBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LCBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcyBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seSBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZiBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eSBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgpBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgpUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZyBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYSBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llciBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgpDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwp5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCllvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCgpVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCmRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgpTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCmxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLg=="},"url":"https:\/\/www.apache.org\/licenses\/LICENSE-2.0"}}],"version":"930ed5f411b159caf1d17468372197cc5f6db65f","purl":"pkg:github\/sunshinemyson\/Joke@930ed5f411b159caf1d17468372197cc5f6db65f","supplier":{"name":"sunshinemyson"},"bom-ref":"Joke_930ed5f411b159caf1d17468372197cc5f6db65f_5a52e92e-8381-433e-863d-68dfd98d6490","description":"","copyright":"","properties":[{"name":"component_id","value":"5"}]},{"name":"majordomo-mysensor","type":"library","version":"a3c87fbd8afb8988bbaab57a2c6093fc431588a9","purl":"pkg:github\/olehs\/majordomo-mysensor@a3c87fbd8afb8988bbaab57a2c6093fc431588a9","supplier":{"name":"olehs"},"bom-ref":"majordomo-mysensor_a3c87fbd8afb8988bbaab57a2c6093fc431588a9_1f0688aa-03f7-45a2-9570-6ba32eaa65a1","description":"","copyright":"","properties":[{"name":"component_id","value":"13"}]},{"name":"pantry","type":"library","licenses":[{"license":{"id":"Apache-2.0","text":{"contentType":"text\/plain","encoding":"base64","content":"QXBhY2hlIExpY2Vuc2UKVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNApodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvCgpURVJNUyBBTkQgQ09ORElUSU9OUyBGT1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04KCjEuIERlZmluaXRpb25zLgoKIkxpY2Vuc2UiIHNoYWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBhcyBkZWZpbmVkIGJ5IFNlY3Rpb25zIDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuCgoiTGljZW5zb3IiIHNoYWxsIG1lYW4gdGhlIGNvcHlyaWdodCBvd25lciBvciBlbnRpdHkgYXV0aG9yaXplZCBieSB0aGUgY29weXJpZ2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhlIExpY2Vuc2UuCgoiTGVnYWwgRW50aXR5IiBzaGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsIG90aGVyIGVudGl0aWVzIHRoYXQgY29udHJvbCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRlciBjb21tb24gY29udHJvbCB3aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIsIGRpcmVjdCBvciBpbmRpcmVjdCwgdG8gY2F1c2UgdGhlIGRpcmVjdGlvbiBvciBtYW5hZ2VtZW50IG9mIHN1Y2ggZW50aXR5LCB3aGV0aGVyIGJ5IGNvbnRyYWN0IG9yIG90aGVyd2lzZSwgb3IgKGlpKSBvd25lcnNoaXAgb2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZSBvdXRzdGFuZGluZyBzaGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJzaGlwIG9mIHN1Y2ggZW50aXR5LgoKIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eSBleGVyY2lzaW5nIHBlcm1pc3Npb25zIGdyYW50ZWQgYnkgdGhpcyBMaWNlbnNlLgoKIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3IgbWFraW5nIG1vZGlmaWNhdGlvbnMsIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gc29mdHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRpb24gc291cmNlLCBhbmQgY29uZmlndXJhdGlvbiBmaWxlcy4KCiJPYmplY3QiIGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9ybSByZXN1bHRpbmcgZnJvbSBtZWNoYW5pY2FsIHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5zbGF0aW9uIG9mIGEgU291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gY29tcGlsZWQgb2JqZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLCBhbmQgY29udmVyc2lvbnMgdG8gb3RoZXIgbWVkaWEgdHlwZXMuCgoiV29yayIgc2hhbGwgbWVhbiB0aGUgd29yayBvZiBhdXRob3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybSwgbWFkZSBhdmFpbGFibGUgdW5kZXIgdGhlIExpY2Vuc2UsIGFzIGluZGljYXRlZCBieSBhIGNvcHlyaWdodCBub3RpY2UgdGhhdCBpcyBpbmNsdWRlZCBpbiBvciBhdHRhY2hlZCB0byB0aGUgd29yayAoYW4gZXhhbXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBwZW5kaXggYmVsb3cpLgoKIkRlcml2YXRpdmUgV29ya3MiIHNoYWxsIG1lYW4gYW55IHdvcmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdCBmb3JtLCB0aGF0IGlzIGJhc2VkIG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBmb3Igd2hpY2ggdGhlIGVkaXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBlbGFib3JhdGlvbnMsIG9yIG90aGVyIG1vZGlmaWNhdGlvbnMgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBhbiBvcmlnaW5hbCB3b3JrIG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyBMaWNlbnNlLCBEZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQgcmVtYWluIHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAob3IgYmluZCBieSBuYW1lKSB0byB0aGUgaW50ZXJmYWNlcyBvZiwgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZi4KCiJDb250cmlidXRpb24iIHNoYWxsIG1lYW4gYW55IHdvcmsgb2YgYXV0aG9yc2hpcCwgaW5jbHVkaW5nIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBhbnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMgdG8gdGhhdCBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5IHN1Ym1pdHRlZCB0byBMaWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRoZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgYnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXplZCB0byBzdWJtaXQgb24gYmVoYWxmIG9mIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIiBtZWFucyBhbnkgZm9ybSBvZiBlbGVjdHJvbmljLCB2ZXJiYWwsIG9yIHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBzZW50IHRvIHRoZSBMaWNlbnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBtYWlsaW5nIGxpc3RzLCBzb3VyY2UgY29kZSBjb250cm9sIHN5c3RlbXMsIGFuZCBpc3N1ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQgYXJlIG1hbmFnZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwgdGhlIExpY2Vuc29yIGZvciB0aGUgcHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXByb3ZpbmcgdGhlIFdvcmssIGJ1dCBleGNsdWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlzIGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVyd2lzZSBkZXNpZ25hdGVkIGluIHdyaXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAiTm90IGEgQ29udHJpYnV0aW9uLiIKCiJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNvciBhbmQgYW55IGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IG9uIGJlaGFsZiBvZiB3aG9tIGEgQ29udHJpYnV0aW9uIGhhcyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZCBzdWJzZXF1ZW50bHkgaW5jb3Jwb3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCjIuIEdyYW50IG9mIENvcHlyaWdodCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB0aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1YWwsIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUsIGlycmV2b2NhYmxlIGNvcHlyaWdodCBsaWNlbnNlIHRvIHJlcHJvZHVjZSwgcHJlcGFyZSBEZXJpdmF0aXZlIFdvcmtzIG9mLCBwdWJsaWNseSBkaXNwbGF5LCBwdWJsaWNseSBwZXJmb3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUgV29yayBhbmQgc3VjaCBEZXJpdmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4KCjMuIEdyYW50IG9mIFBhdGVudCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB0aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1YWwsIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUsIGlycmV2b2NhYmxlIChleGNlcHQgYXMgc3RhdGVkIGluIHRoaXMgc2VjdGlvbikgcGF0ZW50IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLCB1c2UsIG9mZmVyIHRvIHNlbGwsIHNlbGwsIGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29yaywgd2hlcmUgc3VjaCBsaWNlbnNlIGFwcGxpZXMgb25seSB0byB0aG9zZSBwYXRlbnQgY2xhaW1zIGxpY2Vuc2FibGUgYnkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNlc3NhcmlseSBpbmZyaW5nZWQgYnkgdGhlaXIgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9yIGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENvbnRyaWJ1dGlvbihzKSB3aXRoIHRoZSBXb3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9uKHMpIHdhcyBzdWJtaXR0ZWQuIElmIFlvdSBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24gYWdhaW5zdCBhbnkgZW50aXR5IChpbmNsdWRpbmcgYSBjcm9zcy1jbGFpbSBvciBjb3VudGVyY2xhaW0gaW4gYSBsYXdzdWl0KSBhbGxlZ2luZyB0aGF0IHRoZSBXb3JrIG9yIGEgQ29udHJpYnV0aW9uIGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGlyZWN0IG9yIGNvbnRyaWJ1dG9yeSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGljZW5zZXMgZ3JhbnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsgc2hhbGwgdGVybWluYXRlIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0aWdhdGlvbiBpcyBmaWxlZC4KCjQuIFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBjb3BpZXMgb2YgdGhlIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mIGluIGFueSBtZWRpdW0sIHdpdGggb3Igd2l0aG91dCBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9yIE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdSBtZWV0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczoKCiAgICAgKGEpIFlvdSBtdXN0IGdpdmUgYW55IG90aGVyIHJlY2lwaWVudHMgb2YgdGhlIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQKCiAgICAgKGIpIFlvdSBtdXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBwcm9taW5lbnQgbm90aWNlcyBzdGF0aW5nIHRoYXQgWW91IGNoYW5nZWQgdGhlIGZpbGVzOyBhbmQKCiAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsbCBjb3B5cmlnaHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQgYXR0cmlidXRpb24gbm90aWNlcyBmcm9tIHRoZSBTb3VyY2UgZm9ybSBvZiB0aGUgV29yaywgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrczsgYW5kCgogICAgIChkKSBJZiB0aGUgV29yayBpbmNsdWRlcyBhICJOT1RJQ0UiIHRleHQgZmlsZSBhcyBwYXJ0IG9mIGl0cyBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0IGluY2x1ZGUgYSByZWFkYWJsZSBjb3B5IG9mIHRoZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZCB3aXRoaW4gc3VjaCBOT1RJQ0UgZmlsZSwgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiB3aXRoaW4gYSBOT1RJQ0UgdGV4dCBmaWxlIGRpc3RyaWJ1dGVkIGFzIHBhcnQgb2YgdGhlIERlcml2YXRpdmUgV29ya3M7IHdpdGhpbiB0aGUgU291cmNlIGZvcm0gb3IgZG9jdW1lbnRhdGlvbiwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsIHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBhbmQgd2hlcmV2ZXIgc3VjaCB0aGlyZC1wYXJ0eSBub3RpY2VzIG5vcm1hbGx5IGFwcGVhci4gVGhlIGNvbnRlbnRzIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQgZG8gbm90IG1vZGlmeSB0aGUgTGljZW5zZS4gWW91IG1heSBhZGQgWW91ciBvd24gYXR0cmlidXRpb24gbm90aWNlcyB3aXRoaW4gRGVyaXZhdGl2ZSBXb3JrcyB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbG9uZ3NpZGUgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3ZpZGVkIHRoYXQgc3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0aW9uIG5vdGljZXMgY2Fubm90IGJlIGNvbnN0cnVlZCBhcyBtb2RpZnlpbmcgdGhlIExpY2Vuc2UuCgogICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZCBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aCB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLCBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9yIGNvbmRpdGlvbnMuIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkgdGhlIHRlcm1zIG9mIGFueSBzZXBhcmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQgd2l0aCBMaWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKNi4gVHJhZGVtYXJrcy4gVGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZSBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGljZW5zb3IsIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZSBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCjcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLCBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55IHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5zZS4KCjguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LCB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkgbmVnbGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3IgYmUgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3QsIGluZGlyZWN0LCBzcGVjaWFsLCBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEgcmVzdWx0IG9mIHRoaXMgTGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZSBXb3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZyB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLCBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LCBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcyBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seSBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZiBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eSBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uIG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgpBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgpUbyBhcHBseSB0aGUgQXBhY2hlIExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZyBib2lsZXJwbGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNsdWRlIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhlIGFwcHJvcHJpYXRlIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYSBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlIHNhbWUgInByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llciBpZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgpDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwp5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCllvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCgpVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCmRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgpTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCmxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLg=="},"url":"https:\/\/www.apache.org\/licenses\/LICENSE-2.0"}}],"version":"pantry-2.0.7","purl":"pkg:github\/Comcast\/pantry@2.0.7","supplier":{"name":"comcast"},"bom-ref":"pantry_pantry-2.0.7_f0816438-45ff-4d5e-9c41-447156631932","description":"","copyright":"","properties":[{"name":"component_id","value":"971"}]}],"vulnerabilities":[{"id":"CVE-2016-3709","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2016-3709"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":6.1,"severity":"medium","method":"CVSSv31","vector":"","justification":"sgYQ96GdGA"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2016-9596","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2016-9596"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":6.5,"severity":"medium","method":"CVSSv31","vector":"","justification":"h3JnqDiUdl"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":4.3,"severity":"medium","method":"CVSSv2","vector":"","justification":"zkTGby0uqF"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2016-9598","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2016-9598"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":6.5,"severity":"medium","method":"CVSSv31","vector":"","justification":"cOL2DRHDPZ"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":4.3,"severity":"medium","method":"CVSSv2","vector":"","justification":"mMbagzmBP2"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2017-15412","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2017-15412"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":8.8,"severity":"high","method":"CVSSv31","vector":"","justification":"X1HYArCQSh"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.0"},"score":8.8,"severity":"high","method":"CVSSv3","vector":"","justification":"kUrCBaYlVK"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":6.8,"severity":"medium","method":"CVSSv2","vector":"","justification":"MnmjDJZvmQ"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2017-18258","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2017-18258"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":6.5,"severity":"medium","method":"CVSSv31","vector":"","justification":"rB3OFLefkP"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.0"},"score":6.5,"severity":"medium","method":"CVSSv3","vector":"","justification":"tCNnW8MMqt"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":4.3,"severity":"medium","method":"CVSSv2","vector":"","justification":"ii5q8n9ziT"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2017-5130","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2017-5130"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":8.8,"severity":"high","method":"CVSSv31","vector":"","justification":"YjhdaEFWCl"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.0"},"score":8.8,"severity":"high","method":"CVSSv3","vector":"","justification":"aRB4vJwkma"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":6.8,"severity":"medium","method":"CVSSv2","vector":"","justification":"NJygbOm83L"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2017-7375","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2017-7375"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":9.8,"method":"CVSSv31","vector":"","justification":"MpVyPhtibi"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.0"},"score":9.8,"method":"CVSSv3","vector":"","justification":"hrYnu7F3Ax"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":7.5,"severity":"high","method":"CVSSv2","vector":"","justification":"NPtfjHX3sl"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2017-7376","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2017-7376"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":9.8,"method":"CVSSv31","vector":"","justification":"IpejoozU7C"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.0"},"score":9.8,"method":"CVSSv3","vector":"","justification":"G3YHZjIrq2"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":10,"severity":"high","method":"CVSSv2","vector":"","justification":"ZiLT1uWaYP"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2018-14404","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2018-14404"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":7.5,"severity":"high","method":"CVSSv31","vector":"","justification":"Ea9F0wHPJv"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.0"},"score":7.5,"severity":"high","method":"CVSSv3","vector":"","justification":"9I5xGg7Fzy"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":5,"severity":"medium","method":"CVSSv2","vector":"","justification":"eEsCpKQ8fC"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2019-19956","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2019-19956"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":7.5,"severity":"high","method":"CVSSv31","vector":"","justification":"3MQDOjSCq9"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":5,"severity":"medium","method":"CVSSv2","vector":"","justification":"aFZB365xy3"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2021-3517","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2021-3517"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":8.6,"severity":"high","method":"CVSSv31","vector":"","justification":"rRoAIE2Lsy"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":7.5,"severity":"high","method":"CVSSv2","vector":"","justification":"W5z1pPgK1N"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2021-3518","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2021-3518"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":8.8,"severity":"high","method":"CVSSv31","vector":"","justification":"X2Ann60KRQ"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":6.8,"severity":"medium","method":"CVSSv2","vector":"","justification":"c0K61wEbd5"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2021-3537","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2021-3537"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":5.9,"severity":"medium","method":"CVSSv31","vector":"","justification":"XTl9CozBy2"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":4.3,"severity":"medium","method":"CVSSv2","vector":"","justification":"4MYkVGDJCv"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2021-3541","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2021-3541"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":6.5,"severity":"medium","method":"CVSSv31","vector":"","justification":"2dXvi0pSYN"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":4,"severity":"medium","method":"CVSSv2","vector":"","justification":"hhkk62Yeni"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2022-23308","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2022-23308"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":7.5,"severity":"high","method":"CVSSv31","vector":"","justification":"tlmeZjZcQT"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":4.3,"severity":"medium","method":"CVSSv2","vector":"","justification":"Sq32QCq89v"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2022-29824","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2022-29824"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":6.5,"severity":"medium","method":"CVSSv31","vector":"","justification":"ORyUNlQixO"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":4.3,"severity":"medium","method":"CVSSv2","vector":"","justification":"RA7FIv67rU"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2022-40303","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2022-40303"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":7.5,"severity":"high","method":"CVSSv31","vector":"","justification":"iLdTHva49z"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2022-40304","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2022-40304"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":7.8,"severity":"high","method":"CVSSv31","vector":"","justification":"yiJjjYdccQ"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2023-28484","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2023-28484"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":6.5,"severity":"medium","method":"CVSSv31","vector":"","justification":"6XB9nj4uyG"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2023-29469","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2023-29469"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":6.5,"severity":"medium","method":"CVSSv31","vector":"","justification":"gMqe6sljAD"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2023-45322","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2023-45322"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":6.5,"severity":"medium","method":"CVSSv31","vector":"","justification":"mEFBRAuGKn"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2024-25062","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2024-25062"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":7.5,"severity":"high","method":"CVSSv31","vector":"","justification":"hH1PaheGMF"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2025-27113","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-27113"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":7.5,"severity":"high","method":"CVSSv31","vector":"","justification":"n4dzTpMpjf"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2025-32414","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-32414"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":7.5,"severity":"high","method":"CVSSv31","vector":"","justification":"J1PxjeKA9u"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2025-32415","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2025-32415"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":7.5,"severity":"high","method":"CVSSv31","vector":"","justification":"76AIcGNYRe"}],"affects":[{"ref":"libxml2_2.9.2-rc1_68ce0db7-3423-424c-a579-ed665ea36428"}]},{"id":"CVE-2021-23413","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2021-23413"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":5.3,"severity":"medium","method":"CVSSv31","vector":"","justification":"MgTwU2daQh"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":5,"severity":"medium","method":"CVSSv2","vector":"","justification":"7qRHvxSMPq"}],"affects":[{"ref":"jszip_2.6.0_37f396b4-dd84-4a70-999c-20fb01d3f0b5"}]},{"id":"CVE-2022-48285","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2022-48285"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":7.3,"severity":"high","method":"CVSSv31","vector":"","justification":"KyGdfz3owB"}],"affects":[{"ref":"jszip_2.6.0_37f396b4-dd84-4a70-999c-20fb01d3f0b5"}]},{"id":"CVE-2022-24771","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2022-24771"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":7.5,"severity":"high","method":"CVSSv31","vector":"","justification":"diwnMroe4e"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":5,"severity":"medium","method":"CVSSv2","vector":"","justification":"wNtcT1AWOd"}],"affects":[{"ref":"node-forge_1.0.0_2cf1f98f-bef7-49e2-a410-4f8fcc4640ff"}]},{"id":"CVE-2022-24772","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2022-24772"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":7.5,"severity":"high","method":"CVSSv31","vector":"","justification":"L8T8Y06WJR"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":5,"severity":"medium","method":"CVSSv2","vector":"","justification":"BytUFokYT0"}],"affects":[{"ref":"node-forge_1.0.0_2cf1f98f-bef7-49e2-a410-4f8fcc4640ff"}]},{"id":"CVE-2022-24773","source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2022-24773"},"ratings":[{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v3-calculator?vector=&version=3.1"},"score":5.3,"severity":"medium","method":"CVSSv31","vector":"","justification":"YpLNzsXjXj"},{"source":{"name":"NVD","url":"https:\/\/nvd.nist.gov\/vuln-metrics\/cvss\/v2-calculator?vector=&version=2.0"},"score":5,"severity":"medium","method":"CVSSv2","vector":"","justification":"rzgommKXUx"}],"affects":[{"ref":"node-forge_1.0.0_2cf1f98f-bef7-49e2-a410-4f8fcc4640ff"}]}]} \ No newline at end of file diff --git a/tests/fixtures/spdx-document.rdf b/tests/fixtures/spdx-document.rdf new file mode 100644 index 0000000..2ad7c05 --- /dev/null +++ b/tests/fixtures/spdx-document.rdf @@ -0,0 +1,8978 @@ + + + + + + + + 2025-06-20T10:19:05Z + Person: Tomas Gonzalez tomas.gonzalez@fossid.com + Tool: FossID 2025.1.0#14868210464 + 3.26 + + + SPDX-2.3 + Report for project: ProjectMix_267 + + + Android-Bluetooth/BluetoothActivityEnergyInfo.java + + + + + b50ba9b14cf9840a24f44558c211e02005779321f8ee570e74b017fc6607acdf + + + + + + 3313ba31de98878ab319e0a85d62e9ca00e27a7f + + + + + + 33367674dde4914b2ad9b9d0a15f824d + + + + + + + + Android-Bluetooth/BluetoothAudioConfig.java + + + + + fcc52b553eb699f82e9ccf1883519d54ae30e3477570994ee2bad7dad3a699d0 + + + + + + 9c24e137487ac8a0d1da72f16e38e3ff11fee8c9 + + + + + + fbdbe76bc4dd9b97efcec00c8fc19c7e + + + + + + + + Android-Bluetooth/BluetoothAvrcp.java + + + + + 1ee18800f2b0ca59ca897d1bd9b5c2d63ba820166bcebbdc706df061fc2935b3 + + + + + + a656cff39fc40783bc3ca9f8da940cea99ab18bf + + + + + + 33b65e1d754515f3aaf875dcb7ce9419 + + + + + + + + Android-Bluetooth/BluetoothAvrcpPlayerSettings.java + + + + + 43907a2701758afa7783fad7cd3cb4df96ca20d8d261bb6633ab0d3e91ab41ad + + + + + + b8f5b648138508dcdac874887b3c66fc2246c2b6 + + + + + + 85c5af7689e3aadf2f06c649977a91bd + + + + + + + + Android-Bluetooth/BluetoothDevicePicker.java + + + + + 6019fb0694ffd219862626754642f412192fee5de8089cae16f921b95a3a6c4d + + + + + + 936727ae974c1cccba345e7b9dd94839940640b3 + + + + + + a583c244accf4db868155c9302ab9c40 + + + + + + + + Android-Bluetooth/BluetoothGattCallback.java + + + + + 4934cc953e26fd064249e164dfa686fc496a2e04a9b613b98bc20a68e2d1f68c + + + + + + 81448cc136d30d0a1168c99c815037d1d9c82a79 + + + + + + c3e40ca8dc69c40dfd4d64b2d56b6f52 + + + + + + + + Android-Bluetooth/BluetoothGattCallbackWrapper.java + + + + + d6fa3f1512b448f7094c5edcab1bbd8590a461debe6dcb85f56e56e218d66e1b + + + + + + 707ace705147e68e6bbefc9d544b4bbbbb1785a9 + + + + + + e834225a4736deb48c916b8610eec7a6 + + + + + + + + Android-Bluetooth/BluetoothGattDescriptor.java + + + + + 7c3b0fe5ca31997695b4179b3f57b2e70a1480d031ad5feb37fdd240f15e2666 + + + + + + 3d43efa468a52d446be8462e50b55400da5d703d + + + + + + 99ca685a3e575145c3f970d9d50a181b + + + + + + + + Android-Bluetooth/BluetoothGattIncludedService.java + + + + + 3c27e979fd0435d4cf734dfdd99d99286c6155d849ca329ecefe0194b1b2d099 + + + + + + b9bc6d928782106af39dd9a3a49723398243fa45 + + + + + + d0cf3e79d9a847194fcbc70f6bfdf261 + + + + + + + + Android-Bluetooth/BluetoothGattServerCallback.java + + + + + f2adaaf1518592f936736ac7e7ae3d047b335ab1e9339b3546c97dacaf29cc64 + + + + + + 081e2a492da710e07de531ddde4edd09580641ec + + + + + + 534f03349629027b3aef19dbefecb25e + + + + + + + + Files with Snippets/prop_with_android_snippet.java + + + + + 9429d72cfa8b512f4d5b236f8bf0446cc3f29fde012681e7a99d377ab64e3761 + + + + + + d44be11a7532e9b8c17dbc9d5edc0bf2de0f23ae + + + + + + 80ecd4ae8196579b0e3c121558f2d2b2 + + + + + + + + Files with Snippets/prop_with_ofp_snippet.c + + + + + 0184063b1583b2ad5126f79abf13f882d2e392c852a1dd03ca6f63ab2d0dda2f + + + + + + de96131ae418916c470c9b81529c6970b9a3d335 + + + + + + 5087eaefaae32d9df9a9a3c083487fea + + + + + + + + Files with Snippets/prop_with_small_snippet.c + + + + + 50becb7cd95d37b3a5c82a4d56134c01d07eebb2e690b86154dfdf9d3751936d + + + + + + fd2d916725812cda9368798b8fc6c9b6fd534944 + + + + + + c61264fd1c6a6e7d59662cf556ec848c + + + + + + + + Files with Snippets/runner.py + + + + + d069e1389b57da69f8203b3e5fb39403dfed77ca5d244a6b21155892ddab8999 + + + + + + 04ed75493eb800e8389fe107e73f08df16d893af + + + + + + 1712d18cc6aae3f7d108df22a8ce0508 + + + + + + + + Files with Unusual Licenses/jquery.autogrowtextarea.js + + + + + 795edb928c8db4edecc2e65b378a1282dcd82c1a877478859a1f054e64b5992d + + + + + + 4b96d79a864bc54ee0c4c3d9dd87ae80848eb55f + + + + + + dfb12f0b952706a9e129216f3dbe6477 + + + + + + + + Files with Vulnerabilities/process.c + + + + + e2f8c82900e4d1c409ebe38fad3941614956848f7daf482a2780d04858554026 + + + + + + 20f9e0304984fb7a1c66ca826eb3c6aa859be666 + + + + + + 7a15ac70b7e1e360d5da65b8cd934722 + + + + + + + + Files with Vulnerabilities/xmlreader.c + + + + + 06692d022b5833eedaa582876aca06b2075565a511ee0721adec6b25da583eed + + + + + + 6056d66cc44392070433a21f0853818d879376ba + + + + + + aaf8573e0987ed8cf9b1fb0a7f5c6b1b + + + + + + + + Multi-Licensed components/crc32.js + + + + + 44ed7dd5e696f969207dc0ddeec562dba57dc1664a83144baed38b574717806f + + + + + + f0c3cd1372246bdb714b6b82d8b6fdb5369a7003 + + + + + + d87d2e264921c9298ddfb49164e72f25 + + + + + + + + Multi-Licensed components/forge.min.js + + + + + 5122c4c9dbc6bc91cd7fe7f5562a93b02a99912c83b661b652c2f770401506f2 + + + + + + 799f17805c30261c82c67830eca639feff2393cb + + + + + + e34cd774be24e16970bd2e07e2e516aa + + + + + + + + Multi-Licensed components/gen_etld_data.rb + + + + + cb6264a7ccec7a840bfe0c78c2f12907900762f9f028bcf4c51e515f821d2e66 + + + + + + b7f7e9ddb4bfa49485efd6cf8590666db60d8de3 + + + + + + 774b446069ea0cd5b95fa7c36cf6477d + + + + + + + + Multi-Licensed components/jszip.js + + + + + 0abe53cc05ce94d2614e506d42a17144b2030ddd86cd42d9afc2b8423d4f2eaf + + + + + + fd52230d61fcc4675bab01526a37aa205cf9faff + + + + + + 56deaae44a88e138e960de086ef33d76 + + + + + + + + Multi-Licensed components/prime.worker.min.js + + + + + e367bd535452e21e61e02e6886d6f1b836c9596f649101d6573b3254c6f30f79 + + + + + + 4e0ffc99be91d349669f2b365ed407ba6ce85e4d + + + + + + cb525370d1bab18df674eae5d44b282e + + + + + + + + OpenFastPath/configure.ac + + + + + 47c07c5259a9f5da9fbddcb930d11ab0c6c0339e9883618a67f11e31ede74964 + + + + + + d5b183103606f22b8a72052e64065ce11f83a17f + + + + + + f78acd5a24bd478ffd15d055d6410eee + + + + + + + + OpenFastPath/Doxyfile + + + + + 99854f7911b071daae55a64f16234952370ce01fc15b3839ba2852d3949bec3a + + + + + + 97d72b3e23e09d88bb2e63186d78b2cf5d6f6497 + + + + + + 0e7bc86dc60f4715444301b59d01c875 + + + + + + + + OpenFastPath/include/api/ofp.h + + + + + 154b1a9647eb2e5aa4310fcaeaf4c9975ed6a9ddf45574f66563f0ec9ea7bdad + + + + + + 0707f8e4606f6148c7b60a407332605ebcad9fd3 + + + + + + df367fe70fd2f0d19163cb0aa1b64ffe + + + + + + + + OpenFastPath/include/api/ofp_cli.h + + + + + 9d14651ac1f308a074b6eed01feca9dfbb9b872b01c43b4ecf90fa9b8436f86c + + + + + + 54c39b7a282854de884ed4c1df50fa8666e754fa + + + + + + 5c4a9e85ef9997942f77ee400dcdbab1 + + + + + + + + OpenFastPath/include/api/ofp_config.h + + + + + b704a8e8fc4f7ea8f7fed03e0d51921509539b2c1c318b361f2e6124ae6d7d46 + + + + + + 2a6454685cdf21d2ddba7d2f87e94128b21ae3b3 + + + + + + fb2a3020a400ee3c4fb7c516cc47c6a4 + + + + + + + + OpenFastPath/include/api/ofp_debug.h + + + + + f2576c88502f6553723d7fe702948c04322cbfe8d3e4660fbba3c8de54cb58a8 + + + + + + a7a7b25368c7c253815d3d298f17ad6f32229a77 + + + + + + 8b0fc052c30305ac57e51325fdf358b2 + + + + + + + + OpenFastPath/include/api/ofp_errno.h + + + + + 78e8dc30c18f3bc00dc7a2d89e94a40d44544b2da532b995f313ac521ab8e4b2 + + + + + + a990b39952fa841a936a7ff4d6c8e2095c1d7d51 + + + + + + df30cbb26fe0f7ace031fa4c0f3d2be6 + + + + + + + + OpenFastPath/include/api/ofp_hook.h + + + + + 26a51877ca7f0646e62fcdbc390aa580a008da6d9ade19886e2f4aa6068b0955 + + + + + + fba02d9fd10bed105bc7b0d9f0fa8eda1e6a2c3a + + + + + + 0c6e27d48eb3fcae549fa0f0903ea576 + + + + + + + + OpenFastPath/include/api/ofp_ifnet.h + + + + + 826c60b4e541cb1f34f5231d9c169aaae0199cb9bd16e7fd2b465cc089280b54 + + + + + + a4cd2d0d6cbfd66b861b074e4c28f17a4292ae40 + + + + + + a7781b7249622cac8c8a97582a54a28e + + + + + + + + OpenFastPath/include/api/ofp_if_vlan.h + + + + + 0462587214130faca69391be27c002ae017048724f7734ad177365da4ccee548 + + + + + + 94358554b1a99024b63783887f1abb896887d713 + + + + + + c54a0f46b23ea7c0c16fa37e1a7b14c0 + + + + + + + + OpenFastPath/INSTALL + + + + + dccabba4ddf2e1eb8303fed9fb25b5401ce0b8646a5e8e56e332b44c95e308d8 + + + + + + 0d3ac5a8ec1e3fcf96e18a44c95139f218b9d3f3 + + + + + + 0278479fa183a2ff8ab216669424b764 + + + + + + + + OpenFastPath/LICENSE + + + + + bc5756d522ade94b9277741041e8d3640455861f57f11852525bb087cecd9073 + + + + + + 9e0bcb6931410c62526faf53854440ed70db3f35 + + + + + + fbe4957c430eed6cc20521d4eb429fae + + + + + + + + OpenFastPath/Makefile.am + + + + + 9a9420a136dee37ebd5f625c755a184802dd41bbd3feddbaf4a0684c57c08d58 + + + + + + ee8ea84ab8abfaf3db46c2c88229642e89bf5499 + + + + + + dba34013f15b44916fb6abba84c2db1a + + + + + + + + OpenFastPath/README + + + + + e18d2d896c92d882ed752cec8c9d0efae4050904fc507339b55d38a838109095 + + + + + + 1813f2214113c22be2e292a9ace7e672b97da6ba + + + + + + 6f8c46b0684d9bf2e5e2c43584169767 + + + + + + + + OpenFastPath/scripts/start_classifier.sh + + + + + 7723dbd9dc36858da3d39913f9b38727d96e19656a4e3ea85d8d195fe09ede45 + + + + + + 1c2c6715e8cba54c910e94fba3f1e2129e6663e7 + + + + + + 198fff4b1c632b2b4127c50d073e6ed5 + + + + + + + + OpenFastPath/scripts/start_conformance.sh + + + + + 9d8a41ae6a7a34aba97552e484521b4a1db30aad52494abf3792971531f9b988 + + + + + + 0703ac74db17e5d23598361f75c98c2ca542e955 + + + + + + 621d40a450897c11c8a7bd8d6d4bd244 + + + + + + + + OpenFastPath/scripts/start_device.sh + + + + + 81f18ce361614af9d890bec640bfff9a8aad6e9905423d5bfb56965a0d8853fc + + + + + + 788c5b77bf73a187eaa6212ed767ef50d389e337 + + + + + + e2dd3a2651c9e7d5fc83b1a0b1495e4e + + + + + + + + OpenFastPath/scripts/start_socket.sh + + + + + 6c9cb3ba71e908066682627cb175bc567893a60f23af6bcfb946376a708c99ee + + + + + + 778b526f7805fb986947bd09b4ad7d5134322fb5 + + + + + + b29712845fb62bb82628535c5385f9ed + + + + + + + + OpenFastPath/scripts/start_webserver.sh + + + + + 6b9d330af4f3713b6ab1487f42d14947826e4be10846cf2dd16e09ad814c119b + + + + + + 1ad2190a74a21a5e912c8ddad59941a7cb3f1838 + + + + + + c886dfb1636805064b3502032588673c + + + + + + + + OpenFastPath/scripts/start_webserver2.sh + + + + + 2b4d24c655764bd12d976574f7f26063b58b8dbcb2f3256930f698fabe60c694 + + + + + + 7945939cd9ef8eaccb024001941aa0132e6b16d8 + + + + + + f045455928069337ab949b2b2b95c263 + + + + + + + + OpenFastPath/scripts/stop_conformance.sh + + + + + 425db327103d08d11aa4a00a837990fe49caf844520f2a07767e9c3680305778 + + + + + + 5e77a5ba2793309f33c4c3c1a9d0bbd1398a422e + + + + + + 46d22700826a5062a8183d9e33f2134b + + + + + + + + OpenFastPath/scripts/stop_webserver.sh + + + + + 0b2945698217298ddbc84de139eb11f82c7172f2eb5907ede88c2e1b6585d243 + + + + + + 9fe6333da78e331b31ecc77f18126dc234e99be1 + + + + + + 483fd4e296ab2a57ff7dbc4f7d7fa55c + + + + + + + + OpenFastPath/src/Makefile.am + + + + + 29fb9a17eceb31f860e61eb9441a56fa73f3ebd7719931d22428a7a89433c994 + + + + + + 2686ac4226405c30544bfffc1f7ff6ca6f07ce49 + + + + + + 29b382791592c3c30740d7ba91a5dd08 + + + + + + + + OpenFastPath/src/ofp_in6_proto.c + + + + + a5f6d74686f9e26b7786d71eec78d27b767967b10627fe6b21b9012b12f886fd + + + + + + fadee424ca9127f948c8beb0adc2007784e9a65d + + + + + + a1c5b01a77bbb65a3ea6f29f9f48186f + + + + + + + + OpenFastPath/src/ofp_ip6_init.c + + + + + 6ffd0298c8009ada1fec8b78e2704a0381ba8d08e57581ba12a3bf01657fb3d2 + + + + + + a87e2e4c9be744898b806894463a2470d5aab98d + + + + + + 96ae4985a9b6fd765c33f51c130b8379 + + + + + + + + OpenFastPath/src/ofp_ip_init.c + + + + + d5ee489a0325276251931ef132d739816d7d86259424d3d1ad57c38a3a225b7b + + + + + + ceafcf7bf8e60e6ba187596fc6cc45b74e1977cf + + + + + + b415881fb8d80ea57b0945a17dfd2a78 + + + + + + + + OpenFastPath/src/ofp_md5c.c + + + + + bc0395f28792900d06a7be35613ea66d7faa764d9da4882dc00d5798dafab9fe + + + + + + fcc3eb95e651bc8ba66f3a4c92dda2e85f49e5e0 + + + + + + 641457c3c921b7379f6e3a3608c7437c + + + + + + + + OpenFastPath/src/ofp_subr_hash.c + + + + + d9783a07c52fadc002c427276c377c7ab7bb210c0c0576be17323d4f314993f1 + + + + + + e1744f7f14af21e921e7c03714d4f95ac5100014 + + + + + + 8c2cd67da8b59aaa1fe0ea47c05403ba + + + + + + + + OpenFastPath/src/ofp_sys_socket.c + + + + + 3a4b17b66802bbba2f8c78fae87aa85c179294580ebe08dcde90da924e05fca5 + + + + + + aef2e39d1f70e90d121f1f2d7c1b1eb879d67d2a + + + + + + 47dcb9c6d0f8ea879e76f0089c47ab7d + + + + + + + + OpenFastPath/src/ofp_tcp_reass.c + + + + + 6b8c345ebf1b95320a96847bce7c6fb7b4ae43254b6449eb51344b0f1c2bfc8b + + + + + + b8eb52d64485c97ce099ff2d483f4ecdea664ba7 + + + + + + 5f000064d0afedfb6e6e0eb392d4e3b2 + + + + + + + + OpenFastPath/src/ofp_udp6_usrreq.c + + + + + 951f308487b136cead953717bdacd1504890c4e7b349608dcc0106090b2fc729 + + + + + + 0b59fbbff7e2ef512cac861ab23e53f78633bce7 + + + + + + 0dbb00a153644bc81d204ea676e3e684 + + + + + + + + OpenFastPath/src/ofp_uipc_domain.c + + + + + 7272f12ff41fbba8fa7e24d73ee9415cf4578f621fa5fa41550b7548520506f9 + + + + + + 7acbb4cf83136cee0c37c02708fa4020e77a2a90 + + + + + + 4c69cdeb54711238e111c71561832973 + + + + + + + + OpenFastPath/TODO + + + + + 52c6f1495c3bc5beaba2f7f1ad15005c340a3f5837d3ed6f3f88fd1fece40ef5 + + + + + + 9ae6123993222dddf6ee3752dcf4e4d7eb3fb841 + + + + + + 0f4bd9ef9bbe89e88aa4acf2a2cd9281 + + + + + + + + ProjectMix/.DS_Store + + + + + 1cc05ced0d800412bfb7ce9c2fbcd6e183e6c01141ba074d961cb365477e86b7 + + + + + + 82c0ea4f81fc85c1d8cc2c669be14e3bd2cc0938 + + + + + + 1c60cca03cdc2d4fd875faa6e95fa377 + + + + + + + + ProjectMix/Android-Bluetooth/BluetoothActivityEnergyInfo.java + + + + + b50ba9b14cf9840a24f44558c211e02005779321f8ee570e74b017fc6607acdf + + + + + + 3313ba31de98878ab319e0a85d62e9ca00e27a7f + + + + + + 33367674dde4914b2ad9b9d0a15f824d + + + + + + + + ProjectMix/Android-Bluetooth/BluetoothAudioConfig.java + + + + + fcc52b553eb699f82e9ccf1883519d54ae30e3477570994ee2bad7dad3a699d0 + + + + + + 9c24e137487ac8a0d1da72f16e38e3ff11fee8c9 + + + + + + fbdbe76bc4dd9b97efcec00c8fc19c7e + + + + + + + + ProjectMix/Android-Bluetooth/BluetoothAvrcp.java + + + + + 1ee18800f2b0ca59ca897d1bd9b5c2d63ba820166bcebbdc706df061fc2935b3 + + + + + + a656cff39fc40783bc3ca9f8da940cea99ab18bf + + + + + + 33b65e1d754515f3aaf875dcb7ce9419 + + + + + + + + ProjectMix/Android-Bluetooth/BluetoothAvrcpPlayerSettings.java + + + + + 43907a2701758afa7783fad7cd3cb4df96ca20d8d261bb6633ab0d3e91ab41ad + + + + + + b8f5b648138508dcdac874887b3c66fc2246c2b6 + + + + + + 85c5af7689e3aadf2f06c649977a91bd + + + + + + + + ProjectMix/Android-Bluetooth/BluetoothDevicePicker.java + + + + + 6019fb0694ffd219862626754642f412192fee5de8089cae16f921b95a3a6c4d + + + + + + 936727ae974c1cccba345e7b9dd94839940640b3 + + + + + + a583c244accf4db868155c9302ab9c40 + + + + + + + + ProjectMix/Android-Bluetooth/BluetoothGattCallback.java + + + + + 4934cc953e26fd064249e164dfa686fc496a2e04a9b613b98bc20a68e2d1f68c + + + + + + 81448cc136d30d0a1168c99c815037d1d9c82a79 + + + + + + c3e40ca8dc69c40dfd4d64b2d56b6f52 + + + + + + + + ProjectMix/Android-Bluetooth/BluetoothGattCallback.java + + + + + 4934cc953e26fd064249e164dfa686fc496a2e04a9b613b98bc20a68e2d1f68c + + + + + + 81448cc136d30d0a1168c99c815037d1d9c82a79 + + + + + + c3e40ca8dc69c40dfd4d64b2d56b6f52 + + + The Android Open Source Project (2013-2013) + + + + + + + ProjectMix/Android-Bluetooth/BluetoothGattCallbackWrapper.java + + + + + d6fa3f1512b448f7094c5edcab1bbd8590a461debe6dcb85f56e56e218d66e1b + + + + + + 707ace705147e68e6bbefc9d544b4bbbbb1785a9 + + + + + + e834225a4736deb48c916b8610eec7a6 + + + The Android Open Source Project (2014-2014) + + + + + + + ProjectMix/Android-Bluetooth/BluetoothGattCallbackWrapper.java + + + + + d6fa3f1512b448f7094c5edcab1bbd8590a461debe6dcb85f56e56e218d66e1b + + + + + + 707ace705147e68e6bbefc9d544b4bbbbb1785a9 + + + + + + e834225a4736deb48c916b8610eec7a6 + + + + + + + + ProjectMix/Android-Bluetooth/BluetoothGattDescriptor.java + + + + + 7c3b0fe5ca31997695b4179b3f57b2e70a1480d031ad5feb37fdd240f15e2666 + + + + + + 3d43efa468a52d446be8462e50b55400da5d703d + + + + + + 99ca685a3e575145c3f970d9d50a181b + + + + + + + + ProjectMix/Android-Bluetooth/BluetoothGattIncludedService.java + + + + + 3c27e979fd0435d4cf734dfdd99d99286c6155d849ca329ecefe0194b1b2d099 + + + + + + b9bc6d928782106af39dd9a3a49723398243fa45 + + + + + + d0cf3e79d9a847194fcbc70f6bfdf261 + + + + + + + + ProjectMix/Android-Bluetooth/BluetoothGattServerCallback.java + + + + + f2adaaf1518592f936736ac7e7ae3d047b335ab1e9339b3546c97dacaf29cc64 + + + + + + 081e2a492da710e07de531ddde4edd09580641ec + + + + + + 534f03349629027b3aef19dbefecb25e + + + + + + + + ProjectMix/Android-Bluetooth/BluetoothGattServerCallback.java + + + + + f2adaaf1518592f936736ac7e7ae3d047b335ab1e9339b3546c97dacaf29cc64 + + + + + + 081e2a492da710e07de531ddde4edd09580641ec + + + + + + 534f03349629027b3aef19dbefecb25e + + + The Android Open Source Project (2013-2013) + + + + + + + ProjectMix/Files with Snippets/prop_with_android_snippet.java + + + + + 9429d72cfa8b512f4d5b236f8bf0446cc3f29fde012681e7a99d377ab64e3761 + + + + + + d44be11a7532e9b8c17dbc9d5edc0bf2de0f23ae + + + + + + 80ecd4ae8196579b0e3c121558f2d2b2 + + + FOSSID AB (2016-2016) + + + + + + + ProjectMix/Files with Snippets/prop_with_android_snippet.java + + + + + 9429d72cfa8b512f4d5b236f8bf0446cc3f29fde012681e7a99d377ab64e3761 + + + + + + d44be11a7532e9b8c17dbc9d5edc0bf2de0f23ae + + + + + + 80ecd4ae8196579b0e3c121558f2d2b2 + + + + + + + + ProjectMix/Files with Snippets/prop_with_ofp_snippet.c + + + + + 0184063b1583b2ad5126f79abf13f882d2e392c852a1dd03ca6f63ab2d0dda2f + + + + + + de96131ae418916c470c9b81529c6970b9a3d335 + + + + + + 5087eaefaae32d9df9a9a3c083487fea + + + + + + + + ProjectMix/Files with Snippets/prop_with_small_snippet.c + + + + + 50becb7cd95d37b3a5c82a4d56134c01d07eebb2e690b86154dfdf9d3751936d + + + + + + fd2d916725812cda9368798b8fc6c9b6fd534944 + + + + + + c61264fd1c6a6e7d59662cf556ec848c + + + + + + + + ProjectMix/Files with Snippets/prop_with_small_snippet.c + + + + + 50becb7cd95d37b3a5c82a4d56134c01d07eebb2e690b86154dfdf9d3751936d + + + + + + fd2d916725812cda9368798b8fc6c9b6fd534944 + + + + + + c61264fd1c6a6e7d59662cf556ec848c + + + FOSSID (2016-2016) + + + + + + + ProjectMix/Files with Snippets/prop_with_small_snippet.c + + + + + 50becb7cd95d37b3a5c82a4d56134c01d07eebb2e690b86154dfdf9d3751936d + + + + + + fd2d916725812cda9368798b8fc6c9b6fd534944 + + + + + + c61264fd1c6a6e7d59662cf556ec848c + + + FOSSID (2016-2016) + + + + + + ProjectMix/Files with Snippets/runner.py + + + + + d069e1389b57da69f8203b3e5fb39403dfed77ca5d244a6b21155892ddab8999 + + + + + + 04ed75493eb800e8389fe107e73f08df16d893af + + + + + + 1712d18cc6aae3f7d108df22a8ce0508 + + + + + + + + ProjectMix/Files with Unusual Licenses/jquery.autogrowtextarea.js + + + + + 795edb928c8db4edecc2e65b378a1282dcd82c1a877478859a1f054e64b5992d + + + + + + 4b96d79a864bc54ee0c4c3d9dd87ae80848eb55f + + + + + + dfb12f0b952706a9e129216f3dbe6477 + + + + + + + + ProjectMix/Files with Vulnerabilities/process.c + + + + + e2f8c82900e4d1c409ebe38fad3941614956848f7daf482a2780d04858554026 + + + + + + 20f9e0304984fb7a1c66ca826eb3c6aa859be666 + + + + + + 7a15ac70b7e1e360d5da65b8cd934722 + + + + + + + + ProjectMix/Files with Vulnerabilities/xmlreader.c + + + + + 06692d022b5833eedaa582876aca06b2075565a511ee0721adec6b25da583eed + + + + + + 6056d66cc44392070433a21f0853818d879376ba + + + + + + aaf8573e0987ed8cf9b1fb0a7f5c6b1b + + + + + + + + ProjectMix/Multi-Licensed components/crc32.js + + + + + 44ed7dd5e696f969207dc0ddeec562dba57dc1664a83144baed38b574717806f + + + + + + f0c3cd1372246bdb714b6b82d8b6fdb5369a7003 + + + + + + d87d2e264921c9298ddfb49164e72f25 + + + + + + + + ProjectMix/Multi-Licensed components/forge.min.js + + + + + 5122c4c9dbc6bc91cd7fe7f5562a93b02a99912c83b661b652c2f770401506f2 + + + + + + 799f17805c30261c82c67830eca639feff2393cb + + + + + + e34cd774be24e16970bd2e07e2e516aa + + + + + + + + ProjectMix/Multi-Licensed components/gen_etld_data.rb + + + + + cb6264a7ccec7a840bfe0c78c2f12907900762f9f028bcf4c51e515f821d2e66 + + + + + + b7f7e9ddb4bfa49485efd6cf8590666db60d8de3 + + + + + + 774b446069ea0cd5b95fa7c36cf6477d + + + + + + + + ProjectMix/Multi-Licensed components/jszip.js + + + + + 0abe53cc05ce94d2614e506d42a17144b2030ddd86cd42d9afc2b8423d4f2eaf + + + + + + fd52230d61fcc4675bab01526a37aa205cf9faff + + + + + + 56deaae44a88e138e960de086ef33d76 + + + + + + + + ProjectMix/Multi-Licensed components/prime.worker.min.js + + + + + e367bd535452e21e61e02e6886d6f1b836c9596f649101d6573b3254c6f30f79 + + + + + + 4e0ffc99be91d349669f2b365ed407ba6ce85e4d + + + + + + cb525370d1bab18df674eae5d44b282e + + + + + + + + ProjectMix/OpenFastPath/configure.ac + + + + + 47c07c5259a9f5da9fbddcb930d11ab0c6c0339e9883618a67f11e31ede74964 + + + + + + d5b183103606f22b8a72052e64065ce11f83a17f + + + + + + f78acd5a24bd478ffd15d055d6410eee + + + + + + + + ProjectMix/OpenFastPath/Doxyfile + + + + + 99854f7911b071daae55a64f16234952370ce01fc15b3839ba2852d3949bec3a + + + + + + 97d72b3e23e09d88bb2e63186d78b2cf5d6f6497 + + + + + + 0e7bc86dc60f4715444301b59d01c875 + + + + + + + + ProjectMix/OpenFastPath/include/api/ofp.h + + + + + 154b1a9647eb2e5aa4310fcaeaf4c9975ed6a9ddf45574f66563f0ec9ea7bdad + + + + + + 0707f8e4606f6148c7b60a407332605ebcad9fd3 + + + + + + df367fe70fd2f0d19163cb0aa1b64ffe + + + + + + + + ProjectMix/OpenFastPath/include/api/ofp.h + + + + + 154b1a9647eb2e5aa4310fcaeaf4c9975ed6a9ddf45574f66563f0ec9ea7bdad + + + + + + 0707f8e4606f6148c7b60a407332605ebcad9fd3 + + + + + + df367fe70fd2f0d19163cb0aa1b64ffe + + + Nokia (2014-2014) + + + + + + + ProjectMix/OpenFastPath/include/api/ofp_cli.h + + + + + 9d14651ac1f308a074b6eed01feca9dfbb9b872b01c43b4ecf90fa9b8436f86c + + + + + + 54c39b7a282854de884ed4c1df50fa8666e754fa + + + + + + 5c4a9e85ef9997942f77ee400dcdbab1 + + + ENEA Software AB (2014-2014) + Nokia (2014-2014) + + + + + + + ProjectMix/OpenFastPath/include/api/ofp_cli.h + + + + + 9d14651ac1f308a074b6eed01feca9dfbb9b872b01c43b4ecf90fa9b8436f86c + + + + + + 54c39b7a282854de884ed4c1df50fa8666e754fa + + + + + + 5c4a9e85ef9997942f77ee400dcdbab1 + + + + + + + + ProjectMix/OpenFastPath/include/api/ofp_config.h + + + + + b704a8e8fc4f7ea8f7fed03e0d51921509539b2c1c318b361f2e6124ae6d7d46 + + + + + + 2a6454685cdf21d2ddba7d2f87e94128b21ae3b3 + + + + + + fb2a3020a400ee3c4fb7c516cc47c6a4 + + + + + + + + ProjectMix/OpenFastPath/include/api/ofp_config.h + + + + + b704a8e8fc4f7ea8f7fed03e0d51921509539b2c1c318b361f2e6124ae6d7d46 + + + + + + 2a6454685cdf21d2ddba7d2f87e94128b21ae3b3 + + + + + + fb2a3020a400ee3c4fb7c516cc47c6a4 + + + ENEA Software AB (2015-2015) + Nokia (2015-2015) + + + + + + + ProjectMix/OpenFastPath/include/api/ofp_debug.h + + + + + f2576c88502f6553723d7fe702948c04322cbfe8d3e4660fbba3c8de54cb58a8 + + + + + + a7a7b25368c7c253815d3d298f17ad6f32229a77 + + + + + + 8b0fc052c30305ac57e51325fdf358b2 + + + ENEA Software AB (2014-2014) + Nokia (2014-2014) + + + + + + + ProjectMix/OpenFastPath/include/api/ofp_debug.h + + + + + f2576c88502f6553723d7fe702948c04322cbfe8d3e4660fbba3c8de54cb58a8 + + + + + + a7a7b25368c7c253815d3d298f17ad6f32229a77 + + + + + + 8b0fc052c30305ac57e51325fdf358b2 + + + + + + + + ProjectMix/OpenFastPath/include/api/ofp_errno.h + + + + + 78e8dc30c18f3bc00dc7a2d89e94a40d44544b2da532b995f313ac521ab8e4b2 + + + + + + a990b39952fa841a936a7ff4d6c8e2095c1d7d51 + + + + + + df30cbb26fe0f7ace031fa4c0f3d2be6 + + + + + + + + ProjectMix/OpenFastPath/include/api/ofp_errno.h + + + + + 78e8dc30c18f3bc00dc7a2d89e94a40d44544b2da532b995f313ac521ab8e4b2 + + + + + + a990b39952fa841a936a7ff4d6c8e2095c1d7d51 + + + + + + df30cbb26fe0f7ace031fa4c0f3d2be6 + + + The Regents of the University of California (1982-1993) + UNIX System Laboratories, Inc. + + + + + + + ProjectMix/OpenFastPath/include/api/ofp_hook.h + + + + + 26a51877ca7f0646e62fcdbc390aa580a008da6d9ade19886e2f4aa6068b0955 + + + + + + fba02d9fd10bed105bc7b0d9f0fa8eda1e6a2c3a + + + + + + 0c6e27d48eb3fcae549fa0f0903ea576 + + + + + + + + ProjectMix/OpenFastPath/include/api/ofp_ifnet.h + + + + + 826c60b4e541cb1f34f5231d9c169aaae0199cb9bd16e7fd2b465cc089280b54 + + + + + + a4cd2d0d6cbfd66b861b074e4c28f17a4292ae40 + + + + + + a7781b7249622cac8c8a97582a54a28e + + + + + + + + ProjectMix/OpenFastPath/include/api/ofp_ifnet.h + + + + + 826c60b4e541cb1f34f5231d9c169aaae0199cb9bd16e7fd2b465cc089280b54 + + + + + + a4cd2d0d6cbfd66b861b074e4c28f17a4292ae40 + + + + + + a7781b7249622cac8c8a97582a54a28e + + + ENEA Software AB (2015-2015) + Nokia (2015-2015) + + + + + + + ProjectMix/OpenFastPath/include/api/ofp_if_vlan.h + + + + + 0462587214130faca69391be27c002ae017048724f7734ad177365da4ccee548 + + + + + + 94358554b1a99024b63783887f1abb896887d713 + + + + + + c54a0f46b23ea7c0c16fa37e1a7b14c0 + + + + + + + + ProjectMix/OpenFastPath/INSTALL + + + + + dccabba4ddf2e1eb8303fed9fb25b5401ce0b8646a5e8e56e332b44c95e308d8 + + + + + + 0d3ac5a8ec1e3fcf96e18a44c95139f218b9d3f3 + + + + + + 0278479fa183a2ff8ab216669424b764 + + + + + + + + ProjectMix/OpenFastPath/INSTALL + + + + + dccabba4ddf2e1eb8303fed9fb25b5401ce0b8646a5e8e56e332b44c95e308d8 + + + + + + 0d3ac5a8ec1e3fcf96e18a44c95139f218b9d3f3 + + + + + + 0278479fa183a2ff8ab216669424b764 + + + Free Software Foundation, Inc. (1994-2013) + + + + + + + ProjectMix/OpenFastPath/LICENSE + + + + + bc5756d522ade94b9277741041e8d3640455861f57f11852525bb087cecd9073 + + + + + + 9e0bcb6931410c62526faf53854440ed70db3f35 + + + + + + fbe4957c430eed6cc20521d4eb429fae + + + + + + + + ProjectMix/OpenFastPath/Makefile.am + + + + + 9a9420a136dee37ebd5f625c755a184802dd41bbd3feddbaf4a0684c57c08d58 + + + + + + ee8ea84ab8abfaf3db46c2c88229642e89bf5499 + + + + + + dba34013f15b44916fb6abba84c2db1a + + + + + + + + ProjectMix/OpenFastPath/README + + + + + e18d2d896c92d882ed752cec8c9d0efae4050904fc507339b55d38a838109095 + + + + + + 1813f2214113c22be2e292a9ace7e672b97da6ba + + + + + + 6f8c46b0684d9bf2e5e2c43584169767 + + + + + + + + ProjectMix/OpenFastPath/scripts/start_classifier.sh + + + + + 7723dbd9dc36858da3d39913f9b38727d96e19656a4e3ea85d8d195fe09ede45 + + + + + + 1c2c6715e8cba54c910e94fba3f1e2129e6663e7 + + + + + + 198fff4b1c632b2b4127c50d073e6ed5 + + + + + + + + ProjectMix/OpenFastPath/scripts/start_conformance.sh + + + + + 9d8a41ae6a7a34aba97552e484521b4a1db30aad52494abf3792971531f9b988 + + + + + + 0703ac74db17e5d23598361f75c98c2ca542e955 + + + + + + 621d40a450897c11c8a7bd8d6d4bd244 + + + + + + + + ProjectMix/OpenFastPath/scripts/start_device.sh + + + + + 81f18ce361614af9d890bec640bfff9a8aad6e9905423d5bfb56965a0d8853fc + + + + + + 788c5b77bf73a187eaa6212ed767ef50d389e337 + + + + + + e2dd3a2651c9e7d5fc83b1a0b1495e4e + + + + + + + + ProjectMix/OpenFastPath/scripts/start_socket.sh + + + + + 6c9cb3ba71e908066682627cb175bc567893a60f23af6bcfb946376a708c99ee + + + + + + 778b526f7805fb986947bd09b4ad7d5134322fb5 + + + + + + b29712845fb62bb82628535c5385f9ed + + + + + + + + ProjectMix/OpenFastPath/scripts/start_webserver.sh + + + + + 6b9d330af4f3713b6ab1487f42d14947826e4be10846cf2dd16e09ad814c119b + + + + + + 1ad2190a74a21a5e912c8ddad59941a7cb3f1838 + + + + + + c886dfb1636805064b3502032588673c + + + + + + + + ProjectMix/OpenFastPath/scripts/start_webserver2.sh + + + + + 2b4d24c655764bd12d976574f7f26063b58b8dbcb2f3256930f698fabe60c694 + + + + + + 7945939cd9ef8eaccb024001941aa0132e6b16d8 + + + + + + f045455928069337ab949b2b2b95c263 + + + + + + + + ProjectMix/OpenFastPath/scripts/stop_conformance.sh + + + + + 425db327103d08d11aa4a00a837990fe49caf844520f2a07767e9c3680305778 + + + + + + 5e77a5ba2793309f33c4c3c1a9d0bbd1398a422e + + + + + + 46d22700826a5062a8183d9e33f2134b + + + + + + + + ProjectMix/OpenFastPath/scripts/stop_webserver.sh + + + + + 0b2945698217298ddbc84de139eb11f82c7172f2eb5907ede88c2e1b6585d243 + + + + + + 9fe6333da78e331b31ecc77f18126dc234e99be1 + + + + + + 483fd4e296ab2a57ff7dbc4f7d7fa55c + + + + + + + + ProjectMix/OpenFastPath/src/Makefile.am + + + + + 29fb9a17eceb31f860e61eb9441a56fa73f3ebd7719931d22428a7a89433c994 + + + + + + 2686ac4226405c30544bfffc1f7ff6ca6f07ce49 + + + + + + 29b382791592c3c30740d7ba91a5dd08 + + + + + + + + ProjectMix/OpenFastPath/src/ofp_in6_proto.c + + + + + a5f6d74686f9e26b7786d71eec78d27b767967b10627fe6b21b9012b12f886fd + + + + + + fadee424ca9127f948c8beb0adc2007784e9a65d + + + + + + a1c5b01a77bbb65a3ea6f29f9f48186f + + + + + + + + ProjectMix/OpenFastPath/src/ofp_ip6_init.c + + + + + 6ffd0298c8009ada1fec8b78e2704a0381ba8d08e57581ba12a3bf01657fb3d2 + + + + + + a87e2e4c9be744898b806894463a2470d5aab98d + + + + + + 96ae4985a9b6fd765c33f51c130b8379 + + + + + + + + ProjectMix/OpenFastPath/src/ofp_ip_init.c + + + + + d5ee489a0325276251931ef132d739816d7d86259424d3d1ad57c38a3a225b7b + + + + + + ceafcf7bf8e60e6ba187596fc6cc45b74e1977cf + + + + + + b415881fb8d80ea57b0945a17dfd2a78 + + + + + + + + ProjectMix/OpenFastPath/src/ofp_md5c.c + + + + + bc0395f28792900d06a7be35613ea66d7faa764d9da4882dc00d5798dafab9fe + + + + + + fcc3eb95e651bc8ba66f3a4c92dda2e85f49e5e0 + + + + + + 641457c3c921b7379f6e3a3608c7437c + + + + + + + + ProjectMix/OpenFastPath/src/ofp_subr_hash.c + + + + + d9783a07c52fadc002c427276c377c7ab7bb210c0c0576be17323d4f314993f1 + + + + + + e1744f7f14af21e921e7c03714d4f95ac5100014 + + + + + + 8c2cd67da8b59aaa1fe0ea47c05403ba + + + + + + + + ProjectMix/OpenFastPath/src/ofp_sys_socket.c + + + + + 3a4b17b66802bbba2f8c78fae87aa85c179294580ebe08dcde90da924e05fca5 + + + + + + aef2e39d1f70e90d121f1f2d7c1b1eb879d67d2a + + + + + + 47dcb9c6d0f8ea879e76f0089c47ab7d + + + + + + + + ProjectMix/OpenFastPath/src/ofp_tcp_reass.c + + + + + 6b8c345ebf1b95320a96847bce7c6fb7b4ae43254b6449eb51344b0f1c2bfc8b + + + + + + b8eb52d64485c97ce099ff2d483f4ecdea664ba7 + + + + + + 5f000064d0afedfb6e6e0eb392d4e3b2 + + + + + + + + ProjectMix/OpenFastPath/src/ofp_udp6_usrreq.c + + + + + 951f308487b136cead953717bdacd1504890c4e7b349608dcc0106090b2fc729 + + + + + + 0b59fbbff7e2ef512cac861ab23e53f78633bce7 + + + + + + 0dbb00a153644bc81d204ea676e3e684 + + + + + + + + ProjectMix/OpenFastPath/src/ofp_uipc_domain.c + + + + + 7272f12ff41fbba8fa7e24d73ee9415cf4578f621fa5fa41550b7548520506f9 + + + + + + 7acbb4cf83136cee0c37c02708fa4020e77a2a90 + + + + + + 4c69cdeb54711238e111c71561832973 + + + + + + + + ProjectMix/OpenFastPath/TODO + + + + + 52c6f1495c3bc5beaba2f7f1ad15005c340a3f5837d3ed6f3f88fd1fece40ef5 + + + + + + 9ae6123993222dddf6ee3752dcf4e4d7eb3fb841 + + + + + + 0f4bd9ef9bbe89e88aa4acf2a2cd9281 + + + + + + + + ProjectMix/Snippets from Stack Overflow/python_sample_snippet.py + + + + + ec907085160480a2603c9c94948098d9e18f17af684182df6dc4d6fdf5116d34 + + + + + + b005adbed406dcb336e59a57b1e02680240477b1 + + + + + + 4a80d2ffb9490200ef3b63524f3df10b + + + + + + + + ProjectMix/test.sh + + + + + 0df7337a75a101af97d10284008eb7b732da484956e2aebbb856af0238ae8ea9 + + + + + + 19c25d28815a94ff4700e2fca539dcd801be950e + + + + + + 0085cdaab762da9e8103ce6560161bc8 + + + + + + + + ProjectMix/whitelisting/wl1_common_qcom_header.c + + + + + 72ef09e6b2318a4eba93b9458c852a262759900e11629585f8f8e31bd0b351a0 + + + + + + 275cb513ad709c1cefe584d34fe4fda0efa0d800 + + + + + + e6880ab553a64f304b18685e700ac301 + + + + + + + + ProjectMix/whitelisting/wl1_common_qcom_header.c + + + + + 72ef09e6b2318a4eba93b9458c852a262759900e11629585f8f8e31bd0b351a0 + + + + + + 275cb513ad709c1cefe584d34fe4fda0efa0d800 + + + + + + e6880ab553a64f304b18685e700ac301 + + + Qualcomm Technologies, Inc. (2014-2014) + + + + + + + ProjectMix/whitelisting/wl2_common_apache_header.c + + + + + f4ff50f2defd6c0c2a481e3a2d680adf100d9f35612601ebf5788ea054d2252c + + + + + + bcf71f5abb682ef7dfc5c4f9f6853b00fa7cd7a3 + + + + + + 47c863790c6309c0c55d85903196bd18 + + + + + + + + ProjectMix/whitelisting/wl2_common_apache_header.c + + + + + f4ff50f2defd6c0c2a481e3a2d680adf100d9f35612601ebf5788ea054d2252c + + + + + + bcf71f5abb682ef7dfc5c4f9f6853b00fa7cd7a3 + + + + + + 47c863790c6309c0c55d85903196bd18 + + + Comcast Cable Communications Management, LLC (2015-2015) + + + + + + + ProjectMix/whitelisting/wl3_common_class.java + + + + + eab8b2286970cf5fd9c6326a5731628256caf0286b8e5b7a3f6da4c2fa7c4ef3 + + + + + + 08a237746e54ca4d7eaba009e3a79a60112ec5db + + + + + + 1243824b1faf47884defec085b321b9c + + + + + + + + ProjectMix/whitelisting/wl4_public_algorithm_crc32.php + + + + + 5c14e8760773545e6e3d919c4490b619cfdd919fc10436b82bd3c067da9bb0b5 + + + + + + 27e4b6454faae3740282d2143c606b90d2b1115e + + + + + + 0dccd84f6cc6585f7b2cd0df2d2187a6 + + + + + + + + ProjectMix/whitelisting/wl5_common_array_languages.c + + + + + ede6383ac52becfe7ccf8960d4435752598301f663772888d8ce9a66c3525236 + + + + + + 87b4fb5dc1631c60d4193e583248d479a364e56a + + + + + + 8bb553c4fbe38da96793f403ae173035 + + + + + + + + ProjectMix/whitelisting/wl5_common_array_languages.c + + + + + ede6383ac52becfe7ccf8960d4435752598301f663772888d8ce9a66c3525236 + + + + + + 87b4fb5dc1631c60d4193e583248d479a364e56a + + + + + + 8bb553c4fbe38da96793f403ae173035 + + + FOSSID (2016-2016) + + + + + + + ProjectMix/whitelisting/wl6_qcomm_header_and_small_ofp_snippet.c + + + + + 798cd9d6e4d5f924b57864c5b17de73103b33fe6bd2d72029bdba54f62345a61 + + + + + + cc2425d9276de6a2581df0b88a5c10b5f68b8e41 + + + + + + ee4e48a2be05347fa1e8ec7b9b45a7f7 + + + Qualcomm Technologies, Inc. (2014-2014) + + + + + + + ProjectMix/whitelisting/wl6_qcomm_header_and_small_ofp_snippet.c + + + + + 798cd9d6e4d5f924b57864c5b17de73103b33fe6bd2d72029bdba54f62345a61 + + + + + + cc2425d9276de6a2581df0b88a5c10b5f68b8e41 + + + + + + ee4e48a2be05347fa1e8ec7b9b45a7f7 + + + + + + + + ProjectMix/whitelisting/wl7_tcn_multiple_pfms.h + + + + + b704a8e8fc4f7ea8f7fed03e0d51921509539b2c1c318b361f2e6124ae6d7d46 + + + + + + 2a6454685cdf21d2ddba7d2f87e94128b21ae3b3 + + + + + + fb2a3020a400ee3c4fb7c516cc47c6a4 + + + + + + + + ProjectMix/whitelisting/wl7_tcn_multiple_pfms.h + + + + + b704a8e8fc4f7ea8f7fed03e0d51921509539b2c1c318b361f2e6124ae6d7d46 + + + + + + 2a6454685cdf21d2ddba7d2f87e94128b21ae3b3 + + + + + + fb2a3020a400ee3c4fb7c516cc47c6a4 + + + ENEA Software AB (2015-2015) + Nokia (2015-2015) + + + + + + + Snippets from Stack Overflow/python_sample_snippet.py + + + + + ec907085160480a2603c9c94948098d9e18f17af684182df6dc4d6fdf5116d34 + + + + + + b005adbed406dcb336e59a57b1e02680240477b1 + + + + + + 4a80d2ffb9490200ef3b63524f3df10b + + + + + + + + whitelisting/wl1_common_qcom_header.c + + + + + 72ef09e6b2318a4eba93b9458c852a262759900e11629585f8f8e31bd0b351a0 + + + + + + 275cb513ad709c1cefe584d34fe4fda0efa0d800 + + + + + + e6880ab553a64f304b18685e700ac301 + + + + + + + + whitelisting/wl2_common_apache_header.c + + + + + f4ff50f2defd6c0c2a481e3a2d680adf100d9f35612601ebf5788ea054d2252c + + + + + + bcf71f5abb682ef7dfc5c4f9f6853b00fa7cd7a3 + + + + + + 47c863790c6309c0c55d85903196bd18 + + + + + + + + whitelisting/wl3_common_class.java + + + + + eab8b2286970cf5fd9c6326a5731628256caf0286b8e5b7a3f6da4c2fa7c4ef3 + + + + + + 08a237746e54ca4d7eaba009e3a79a60112ec5db + + + + + + 1243824b1faf47884defec085b321b9c + + + + + + + + whitelisting/wl4_public_algorithm_crc32.php + + + + + 5c14e8760773545e6e3d919c4490b619cfdd919fc10436b82bd3c067da9bb0b5 + + + + + + 27e4b6454faae3740282d2143c606b90d2b1115e + + + + + + 0dccd84f6cc6585f7b2cd0df2d2187a6 + + + + + + + + whitelisting/wl5_common_array_languages.c + + + + + ede6383ac52becfe7ccf8960d4435752598301f663772888d8ce9a66c3525236 + + + + + + 87b4fb5dc1631c60d4193e583248d479a364e56a + + + + + + 8bb553c4fbe38da96793f403ae173035 + + + + + + + + whitelisting/wl6_qcomm_header_and_small_ofp_snippet.c + + + + + 798cd9d6e4d5f924b57864c5b17de73103b33fe6bd2d72029bdba54f62345a61 + + + + + + cc2425d9276de6a2581df0b88a5c10b5f68b8e41 + + + + + + ee4e48a2be05347fa1e8ec7b9b45a7f7 + + + + + + + + whitelisting/wl7_tcn_multiple_pfms.h + + + + + b704a8e8fc4f7ea8f7fed03e0d51921509539b2c1c318b361f2e6124ae6d7d46 + + + + + + 2a6454685cdf21d2ddba7d2f87e94128b21ae3b3 + + + + + + fb2a3020a400ee3c4fb7c516cc47c6a4 + + + + + + + + __MACOSX/._ProjectMix + + + + + a3b58d43c99bdbf34001940e4c6b0f15606a2c40f45bb27756f0fb660bd99218 + + + + + + 801f5851166eaf78b863b911678bbdd286ab388b + + + + + + bd8b0a185dad945bb72055dcabf0e9ce + + + + + + + + __MACOSX/ProjectMix/._.DS_Store + + + + + 2f380f4a3d05a8d90c2106f50da75064e9ce57a598599dc5404f8f69a0223aa9 + + + + + + 0bed7e90c2bade9763fa18f1fb4441d31f91c87c + + + + + + b9a94cc8f4aac450fb21641eaf065c6d + + + + + + + + __MACOSX/ProjectMix/._Android-Bluetooth + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/._Files with Snippets + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/._Files with Unusual Licenses + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/._Files with Vulnerabilities + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/._Multi-Licensed components + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/._OpenFastPath + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/._Snippets from Stack Overflow + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/._whitelisting + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Android-Bluetooth/._BluetoothActivityEnergyInfo.java + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Android-Bluetooth/._BluetoothAudioConfig.java + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Android-Bluetooth/._BluetoothAvrcp.java + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Android-Bluetooth/._BluetoothAvrcpPlayerSettings.java + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Android-Bluetooth/._BluetoothDevicePicker.java + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Android-Bluetooth/._BluetoothGattCallback.java + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Android-Bluetooth/._BluetoothGattCallbackWrapper.java + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Android-Bluetooth/._BluetoothGattDescriptor.java + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Android-Bluetooth/._BluetoothGattIncludedService.java + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Android-Bluetooth/._BluetoothGattServerCallback.java + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Files with Snippets/._prop_with_android_snippet.java + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Files with Snippets/._prop_with_ofp_snippet.c + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Files with Snippets/._prop_with_small_snippet.c + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Files with Snippets/._runner.py + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Files with Unusual Licenses/._jquery.autogrowtextarea.js + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Files with Vulnerabilities/._process.c + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Files with Vulnerabilities/._xmlreader.c + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Multi-Licensed components/._crc32.js + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Multi-Licensed components/._forge.min.js + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Multi-Licensed components/._gen_etld_data.rb + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Multi-Licensed components/._jszip.js + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Multi-Licensed components/._prime.worker.min.js + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/._configure.ac + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/._Doxyfile + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/._include + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/._INSTALL + + + + + 41cad08a293a357ca5238680c84f5ba766f4d8aa84c64b524bfc0f77476d0763 + + + + + + a23fdb2665c380a168bf258ee616f6e22b2e9e8d + + + + + + d9542e0a5397300ea9993c881b7f8d48 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/._LICENSE + + + + + 1e4797fbdf0b9c22524238e5ef5c43dd78fdfc6eafc0f16777419bb61c79b7b1 + + + + + + 392a9eda467ff89a797b5e292e025292ff2cb737 + + + + + + 6569dd62ea938547e9e407d3f8a08e14 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/._Makefile.am + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/._README + + + + + 15a17b42a4480dbc11c8a91b0457126fa853e095749af97660b61503510bf604 + + + + + + 249f5ba1c6ae69e09352f2348fd6bb4e9ddf0b7f + + + + + + bc71e7c3a5f25619bdb72cf96f5523fc + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/._scripts + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/._src + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/._TODO + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/include/._api + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/include/api/._ofp.h + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/include/api/._ofp_cli.h + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/include/api/._ofp_config.h + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/include/api/._ofp_debug.h + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/include/api/._ofp_errno.h + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/include/api/._ofp_hook.h + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/include/api/._ofp_ifnet.h + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/include/api/._ofp_if_vlan.h + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/scripts/._start_classifier.sh + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/scripts/._start_conformance.sh + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/scripts/._start_device.sh + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/scripts/._start_socket.sh + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/scripts/._start_webserver.sh + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/scripts/._start_webserver2.sh + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/scripts/._stop_conformance.sh + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/scripts/._stop_webserver.sh + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/src/._Makefile.am + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/src/._ofp_in6_proto.c + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/src/._ofp_ip6_init.c + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/src/._ofp_ip_init.c + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/src/._ofp_md5c.c + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/src/._ofp_subr_hash.c + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/src/._ofp_sys_socket.c + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/src/._ofp_tcp_reass.c + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/src/._ofp_udp6_usrreq.c + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/OpenFastPath/src/._ofp_uipc_domain.c + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/Snippets from Stack Overflow/._python_sample_snippet.py + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/whitelisting/._wl1_common_qcom_header.c + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/whitelisting/._wl2_common_apache_header.c + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/whitelisting/._wl3_common_class.java + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/whitelisting/._wl4_public_algorithm_crc32.php + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/whitelisting/._wl5_common_array_languages.c + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/whitelisting/._wl6_qcomm_header_and_small_ofp_snippet.c + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + __MACOSX/ProjectMix/whitelisting/._wl7_tcn_multiple_pfms.h + + + + + 3706e62bd8b15ff820af2ef537c866fa0de3d5446f98118dd98bf58ec27164bb + + + + + + 92052a371a8fc11feb60fd715312513448e38463 + + + + + + e945f43967558fb9ec999fd8fe094f40 + + + + + + + + + + + ofp + 1.1 + NOASSERTION + https://github.com/OpenFastPath/ofp/archive/v1.1.tar.gz + + + ed781a88536a3fc2509e700ff03642646893b180 + + + + + + + + ProjectMix/Files with Snippets/prop_with_ofp_snippet.c + + + + + 0184063b1583b2ad5126f79abf13f882d2e392c852a1dd03ca6f63ab2d0dda2f + + + + + + de96131ae418916c470c9b81529c6970b9a3d335 + + + + + + 5087eaefaae32d9df9a9a3c083487fea + + + FOSSID (2016-2016) + + + + + + + ProjectMix/Files with Snippets/prop_with_ofp_snippet.c + + + + + 0184063b1583b2ad5126f79abf13f882d2e392c852a1dd03ca6f63ab2d0dda2f + + + + + + de96131ae418916c470c9b81529c6970b9a3d335 + + + + + + 5087eaefaae32d9df9a9a3c083487fea + + + FOSSID (2016-2016) + + + + + + + ProjectMix/OpenFastPath/configure.ac + + + + + 47c07c5259a9f5da9fbddcb930d11ab0c6c0339e9883618a67f11e31ede74964 + + + + + + d5b183103606f22b8a72052e64065ce11f83a17f + + + + + + f78acd5a24bd478ffd15d055d6410eee + + + + + + + + ProjectMix/OpenFastPath/Doxyfile + + + + + 99854f7911b071daae55a64f16234952370ce01fc15b3839ba2852d3949bec3a + + + + + + 97d72b3e23e09d88bb2e63186d78b2cf5d6f6497 + + + + + + 0e7bc86dc60f4715444301b59d01c875 + + + + + + + + ProjectMix/OpenFastPath/Doxyfile + + + + + 99854f7911b071daae55a64f16234952370ce01fc15b3839ba2852d3949bec3a + + + + + + 97d72b3e23e09d88bb2e63186d78b2cf5d6f6497 + + + + + + 0e7bc86dc60f4715444301b59d01c875 + + + + + + + + ProjectMix/OpenFastPath/include/api/ofp.h + + + + + 154b1a9647eb2e5aa4310fcaeaf4c9975ed6a9ddf45574f66563f0ec9ea7bdad + + + + + + 0707f8e4606f6148c7b60a407332605ebcad9fd3 + + + + + + df367fe70fd2f0d19163cb0aa1b64ffe + + + Nokia (2014-2014) + + + + + + ProjectMix/OpenFastPath/include/api/ofp_cli.h + + + + + 9d14651ac1f308a074b6eed01feca9dfbb9b872b01c43b4ecf90fa9b8436f86c + + + + + + 54c39b7a282854de884ed4c1df50fa8666e754fa + + + + + + 5c4a9e85ef9997942f77ee400dcdbab1 + + + ENEA Software AB (2014-2014) + Nokia (2014-2014) + + + + + + ProjectMix/OpenFastPath/include/api/ofp_config.h + + + + + b704a8e8fc4f7ea8f7fed03e0d51921509539b2c1c318b361f2e6124ae6d7d46 + + + + + + 2a6454685cdf21d2ddba7d2f87e94128b21ae3b3 + + + + + + fb2a3020a400ee3c4fb7c516cc47c6a4 + + + ENEA Software AB (2015-2015) + Nokia (2015-2015) + + + + + + ProjectMix/OpenFastPath/include/api/ofp_debug.h + + + + + f2576c88502f6553723d7fe702948c04322cbfe8d3e4660fbba3c8de54cb58a8 + + + + + + a7a7b25368c7c253815d3d298f17ad6f32229a77 + + + + + + 8b0fc052c30305ac57e51325fdf358b2 + + + ENEA Software AB (2014-2014) + Nokia (2014-2014) + + + + + + ProjectMix/OpenFastPath/include/api/ofp_errno.h + + + + + 78e8dc30c18f3bc00dc7a2d89e94a40d44544b2da532b995f313ac521ab8e4b2 + + + + + + a990b39952fa841a936a7ff4d6c8e2095c1d7d51 + + + + + + df30cbb26fe0f7ace031fa4c0f3d2be6 + + + The Regents of the University of California (1982-1993) + UNIX System Laboratories Inc. + + + + + + ProjectMix/OpenFastPath/include/api/ofp_hook.h + + + + + 26a51877ca7f0646e62fcdbc390aa580a008da6d9ade19886e2f4aa6068b0955 + + + + + + fba02d9fd10bed105bc7b0d9f0fa8eda1e6a2c3a + + + + + + 0c6e27d48eb3fcae549fa0f0903ea576 + + + ENEA Software AB (2014-2014) + Nokia (2014-2014) + + + + + + + ProjectMix/OpenFastPath/include/api/ofp_hook.h + + + + + 26a51877ca7f0646e62fcdbc390aa580a008da6d9ade19886e2f4aa6068b0955 + + + + + + fba02d9fd10bed105bc7b0d9f0fa8eda1e6a2c3a + + + + + + 0c6e27d48eb3fcae549fa0f0903ea576 + + + ENEA Software AB (2014-2014) + Nokia (2014-2014) + + + + + + + ProjectMix/OpenFastPath/include/api/ofp_ifnet.h + + + + + 826c60b4e541cb1f34f5231d9c169aaae0199cb9bd16e7fd2b465cc089280b54 + + + + + + a4cd2d0d6cbfd66b861b074e4c28f17a4292ae40 + + + + + + a7781b7249622cac8c8a97582a54a28e + + + ENEA Software AB (2015-2015) + Nokia (2015-2015) + + + + + + ProjectMix/OpenFastPath/include/api/ofp_if_vlan.h + + + + + 0462587214130faca69391be27c002ae017048724f7734ad177365da4ccee548 + + + + + + 94358554b1a99024b63783887f1abb896887d713 + + + + + + c54a0f46b23ea7c0c16fa37e1a7b14c0 + + + ENEA Software AB (2014-2014) + Nokia (2014-2014) + Massachusetts Institute of Technology (1998-1998) + + + + + + + + + + + + ProjectMix/OpenFastPath/include/api/ofp_if_vlan.h + + + + + 0462587214130faca69391be27c002ae017048724f7734ad177365da4ccee548 + + + + + + 94358554b1a99024b63783887f1abb896887d713 + + + + + + c54a0f46b23ea7c0c16fa37e1a7b14c0 + + + ENEA Software AB (2014-2014) + Nokia (2014-2014) + Massachusetts Institute of Technology (1998-1998) + + + + + + + + + + + + ProjectMix/OpenFastPath/INSTALL + + + + + dccabba4ddf2e1eb8303fed9fb25b5401ce0b8646a5e8e56e332b44c95e308d8 + + + + + + 0d3ac5a8ec1e3fcf96e18a44c95139f218b9d3f3 + + + + + + 0278479fa183a2ff8ab216669424b764 + + + Free Software Foundation Inc. (1994-2013) + + + + + + ProjectMix/OpenFastPath/LICENSE + + + + + bc5756d522ade94b9277741041e8d3640455861f57f11852525bb087cecd9073 + + + + + + 9e0bcb6931410c62526faf53854440ed70db3f35 + + + + + + fbe4957c430eed6cc20521d4eb429fae + + + OpenFP (2014-2014) + + + + + + + ProjectMix/OpenFastPath/LICENSE + + + + + bc5756d522ade94b9277741041e8d3640455861f57f11852525bb087cecd9073 + + + + + + 9e0bcb6931410c62526faf53854440ed70db3f35 + + + + + + fbe4957c430eed6cc20521d4eb429fae + + + OpenFP (2014-2014) + + + + + + + ProjectMix/OpenFastPath/Makefile.am + + + + + 9a9420a136dee37ebd5f625c755a184802dd41bbd3feddbaf4a0684c57c08d58 + + + + + + ee8ea84ab8abfaf3db46c2c88229642e89bf5499 + + + + + + dba34013f15b44916fb6abba84c2db1a + + + + + + + + ProjectMix/OpenFastPath/README + + + + + e18d2d896c92d882ed752cec8c9d0efae4050904fc507339b55d38a838109095 + + + + + + 1813f2214113c22be2e292a9ace7e672b97da6ba + + + + + + 6f8c46b0684d9bf2e5e2c43584169767 + + + + + + + + + + + + + ProjectMix/OpenFastPath/README + + + + + e18d2d896c92d882ed752cec8c9d0efae4050904fc507339b55d38a838109095 + + + + + + 1813f2214113c22be2e292a9ace7e672b97da6ba + + + + + + 6f8c46b0684d9bf2e5e2c43584169767 + + + + + + + + + + + + + ProjectMix/OpenFastPath/scripts/start_classifier.sh + + + + + 7723dbd9dc36858da3d39913f9b38727d96e19656a4e3ea85d8d195fe09ede45 + + + + + + 1c2c6715e8cba54c910e94fba3f1e2129e6663e7 + + + + + + 198fff4b1c632b2b4127c50d073e6ed5 + + + + + + + + ProjectMix/OpenFastPath/scripts/start_classifier.sh + + + + + 7723dbd9dc36858da3d39913f9b38727d96e19656a4e3ea85d8d195fe09ede45 + + + + + + 1c2c6715e8cba54c910e94fba3f1e2129e6663e7 + + + + + + 198fff4b1c632b2b4127c50d073e6ed5 + + + + + + + + ProjectMix/OpenFastPath/scripts/start_conformance.sh + + + + + 9d8a41ae6a7a34aba97552e484521b4a1db30aad52494abf3792971531f9b988 + + + + + + 0703ac74db17e5d23598361f75c98c2ca542e955 + + + + + + 621d40a450897c11c8a7bd8d6d4bd244 + + + + + + + + ProjectMix/OpenFastPath/scripts/start_conformance.sh + + + + + 9d8a41ae6a7a34aba97552e484521b4a1db30aad52494abf3792971531f9b988 + + + + + + 0703ac74db17e5d23598361f75c98c2ca542e955 + + + + + + 621d40a450897c11c8a7bd8d6d4bd244 + + + + + + + + ProjectMix/OpenFastPath/scripts/start_device.sh + + + + + 81f18ce361614af9d890bec640bfff9a8aad6e9905423d5bfb56965a0d8853fc + + + + + + 788c5b77bf73a187eaa6212ed767ef50d389e337 + + + + + + e2dd3a2651c9e7d5fc83b1a0b1495e4e + + + + + + + + ProjectMix/OpenFastPath/scripts/start_device.sh + + + + + 81f18ce361614af9d890bec640bfff9a8aad6e9905423d5bfb56965a0d8853fc + + + + + + 788c5b77bf73a187eaa6212ed767ef50d389e337 + + + + + + e2dd3a2651c9e7d5fc83b1a0b1495e4e + + + + + + + + ProjectMix/OpenFastPath/scripts/start_socket.sh + + + + + 6c9cb3ba71e908066682627cb175bc567893a60f23af6bcfb946376a708c99ee + + + + + + 778b526f7805fb986947bd09b4ad7d5134322fb5 + + + + + + b29712845fb62bb82628535c5385f9ed + + + + + + + + ProjectMix/OpenFastPath/scripts/start_socket.sh + + + + + 6c9cb3ba71e908066682627cb175bc567893a60f23af6bcfb946376a708c99ee + + + + + + 778b526f7805fb986947bd09b4ad7d5134322fb5 + + + + + + b29712845fb62bb82628535c5385f9ed + + + + + + + + ProjectMix/OpenFastPath/scripts/start_webserver.sh + + + + + 6b9d330af4f3713b6ab1487f42d14947826e4be10846cf2dd16e09ad814c119b + + + + + + 1ad2190a74a21a5e912c8ddad59941a7cb3f1838 + + + + + + c886dfb1636805064b3502032588673c + + + + + + + + ProjectMix/OpenFastPath/scripts/start_webserver.sh + + + + + 6b9d330af4f3713b6ab1487f42d14947826e4be10846cf2dd16e09ad814c119b + + + + + + 1ad2190a74a21a5e912c8ddad59941a7cb3f1838 + + + + + + c886dfb1636805064b3502032588673c + + + + + + + + ProjectMix/OpenFastPath/scripts/start_webserver2.sh + + + + + 2b4d24c655764bd12d976574f7f26063b58b8dbcb2f3256930f698fabe60c694 + + + + + + 7945939cd9ef8eaccb024001941aa0132e6b16d8 + + + + + + f045455928069337ab949b2b2b95c263 + + + + + + + + ProjectMix/OpenFastPath/scripts/start_webserver2.sh + + + + + 2b4d24c655764bd12d976574f7f26063b58b8dbcb2f3256930f698fabe60c694 + + + + + + 7945939cd9ef8eaccb024001941aa0132e6b16d8 + + + + + + f045455928069337ab949b2b2b95c263 + + + + + + + + ProjectMix/OpenFastPath/scripts/stop_conformance.sh + + + + + 425db327103d08d11aa4a00a837990fe49caf844520f2a07767e9c3680305778 + + + + + + 5e77a5ba2793309f33c4c3c1a9d0bbd1398a422e + + + + + + 46d22700826a5062a8183d9e33f2134b + + + + + + + + ProjectMix/OpenFastPath/scripts/stop_conformance.sh + + + + + 425db327103d08d11aa4a00a837990fe49caf844520f2a07767e9c3680305778 + + + + + + 5e77a5ba2793309f33c4c3c1a9d0bbd1398a422e + + + + + + 46d22700826a5062a8183d9e33f2134b + + + + + + + + ProjectMix/OpenFastPath/scripts/stop_webserver.sh + + + + + 0b2945698217298ddbc84de139eb11f82c7172f2eb5907ede88c2e1b6585d243 + + + + + + 9fe6333da78e331b31ecc77f18126dc234e99be1 + + + + + + 483fd4e296ab2a57ff7dbc4f7d7fa55c + + + + + + + + ProjectMix/OpenFastPath/scripts/stop_webserver.sh + + + + + 0b2945698217298ddbc84de139eb11f82c7172f2eb5907ede88c2e1b6585d243 + + + + + + 9fe6333da78e331b31ecc77f18126dc234e99be1 + + + + + + 483fd4e296ab2a57ff7dbc4f7d7fa55c + + + + + + + + ProjectMix/OpenFastPath/src/Makefile.am + + + + + 29fb9a17eceb31f860e61eb9441a56fa73f3ebd7719931d22428a7a89433c994 + + + + + + 2686ac4226405c30544bfffc1f7ff6ca6f07ce49 + + + + + + 29b382791592c3c30740d7ba91a5dd08 + + + + + + + + ProjectMix/OpenFastPath/src/ofp_in6_proto.c + + + + + a5f6d74686f9e26b7786d71eec78d27b767967b10627fe6b21b9012b12f886fd + + + + + + fadee424ca9127f948c8beb0adc2007784e9a65d + + + + + + a1c5b01a77bbb65a3ea6f29f9f48186f + + + WIDE Project (1995-1998) + The Regents of the University of California (1982-1993) + + + + + + + + + + + + ProjectMix/OpenFastPath/src/ofp_in6_proto.c + + + + + a5f6d74686f9e26b7786d71eec78d27b767967b10627fe6b21b9012b12f886fd + + + + + + fadee424ca9127f948c8beb0adc2007784e9a65d + + + + + + a1c5b01a77bbb65a3ea6f29f9f48186f + + + WIDE Project (1995-1998) + The Regents of the University of California (1982-1993) + + + + + + + + + + + + ProjectMix/OpenFastPath/src/ofp_ip6_init.c + + + + + 6ffd0298c8009ada1fec8b78e2704a0381ba8d08e57581ba12a3bf01657fb3d2 + + + + + + a87e2e4c9be744898b806894463a2470d5aab98d + + + + + + 96ae4985a9b6fd765c33f51c130b8379 + + + WIDE Project (1995-1998) + The Regents of the University of California (1982-1993) + + + + + + + + + + + + ProjectMix/OpenFastPath/src/ofp_ip6_init.c + + + + + 6ffd0298c8009ada1fec8b78e2704a0381ba8d08e57581ba12a3bf01657fb3d2 + + + + + + a87e2e4c9be744898b806894463a2470d5aab98d + + + + + + 96ae4985a9b6fd765c33f51c130b8379 + + + WIDE Project (1995-1998) + The Regents of the University of California (1982-1993) + + + + + + + + + + + + ProjectMix/OpenFastPath/src/ofp_ip_init.c + + + + + d5ee489a0325276251931ef132d739816d7d86259424d3d1ad57c38a3a225b7b + + + + + + ceafcf7bf8e60e6ba187596fc6cc45b74e1977cf + + + + + + b415881fb8d80ea57b0945a17dfd2a78 + + + The Regents of the University of California (1982-1993) + + + + + + + ProjectMix/OpenFastPath/src/ofp_ip_init.c + + + + + d5ee489a0325276251931ef132d739816d7d86259424d3d1ad57c38a3a225b7b + + + + + + ceafcf7bf8e60e6ba187596fc6cc45b74e1977cf + + + + + + b415881fb8d80ea57b0945a17dfd2a78 + + + The Regents of the University of California (1982-1993) + + + + + + + ProjectMix/OpenFastPath/src/ofp_md5c.c + + + + + bc0395f28792900d06a7be35613ea66d7faa764d9da4882dc00d5798dafab9fe + + + + + + fcc3eb95e651bc8ba66f3a4c92dda2e85f49e5e0 + + + + + + 641457c3c921b7379f6e3a3608c7437c + + + RSA Data Security, Inc. Created (1991-1991) + + + + + + + ProjectMix/OpenFastPath/src/ofp_md5c.c + + + + + bc0395f28792900d06a7be35613ea66d7faa764d9da4882dc00d5798dafab9fe + + + + + + fcc3eb95e651bc8ba66f3a4c92dda2e85f49e5e0 + + + + + + 641457c3c921b7379f6e3a3608c7437c + + + RSA Data Security, Inc. Created (1991-1991) + + + + + + + ProjectMix/OpenFastPath/src/ofp_subr_hash.c + + + + + d9783a07c52fadc002c427276c377c7ab7bb210c0c0576be17323d4f314993f1 + + + + + + e1744f7f14af21e921e7c03714d4f95ac5100014 + + + + + + 8c2cd67da8b59aaa1fe0ea47c05403ba + + + The Regents of the University of California (1982-1993) + Nokia (2014-2014) + Enea Software AB (2014-2014) + UNIX System Laboratories, Inc. + + + + + + + ProjectMix/OpenFastPath/src/ofp_subr_hash.c + + + + + d9783a07c52fadc002c427276c377c7ab7bb210c0c0576be17323d4f314993f1 + + + + + + e1744f7f14af21e921e7c03714d4f95ac5100014 + + + + + + 8c2cd67da8b59aaa1fe0ea47c05403ba + + + The Regents of the University of California (1982-1993) + Nokia (2014-2014) + Enea Software AB (2014-2014) + UNIX System Laboratories, Inc. + + + + + + + ProjectMix/OpenFastPath/src/ofp_sys_socket.c + + + + + 3a4b17b66802bbba2f8c78fae87aa85c179294580ebe08dcde90da924e05fca5 + + + + + + aef2e39d1f70e90d121f1f2d7c1b1eb879d67d2a + + + + + + 47dcb9c6d0f8ea879e76f0089c47ab7d + + + The Regents of the University of California (1982-1993) + Nokia Solutions and Networks (2015-2015) + Enea Software AB (2015-2015) + + + + + + + ProjectMix/OpenFastPath/src/ofp_sys_socket.c + + + + + 3a4b17b66802bbba2f8c78fae87aa85c179294580ebe08dcde90da924e05fca5 + + + + + + aef2e39d1f70e90d121f1f2d7c1b1eb879d67d2a + + + + + + 47dcb9c6d0f8ea879e76f0089c47ab7d + + + The Regents of the University of California (1982-1993) + Nokia Solutions and Networks (2015-2015) + Enea Software AB (2015-2015) + + + + + + + ProjectMix/OpenFastPath/src/ofp_tcp_reass.c + + + + + 6b8c345ebf1b95320a96847bce7c6fb7b4ae43254b6449eb51344b0f1c2bfc8b + + + + + + b8eb52d64485c97ce099ff2d483f4ecdea664ba7 + + + + + + 5f000064d0afedfb6e6e0eb392d4e3b2 + + + The Regents of the University of California (1982-1995) + Nokia Solutions and Networks (2015-2015) + Enea Software AB (2015-2015) + + + + + + + ProjectMix/OpenFastPath/src/ofp_tcp_reass.c + + + + + 6b8c345ebf1b95320a96847bce7c6fb7b4ae43254b6449eb51344b0f1c2bfc8b + + + + + + b8eb52d64485c97ce099ff2d483f4ecdea664ba7 + + + + + + 5f000064d0afedfb6e6e0eb392d4e3b2 + + + The Regents of the University of California (1982-1995) + Nokia Solutions and Networks (2015-2015) + Enea Software AB (2015-2015) + + + + + + + ProjectMix/OpenFastPath/src/ofp_udp6_usrreq.c + + + + + 951f308487b136cead953717bdacd1504890c4e7b349608dcc0106090b2fc729 + + + + + + 0b59fbbff7e2ef512cac861ab23e53f78633bce7 + + + + + + 0dbb00a153644bc81d204ea676e3e684 + + + WIDE Project (1995-1998) + Juniper Networks, Inc. (2010-2011) + The Regents of the University of California (1982-1995) + + + + + + + + + + + + ProjectMix/OpenFastPath/src/ofp_udp6_usrreq.c + + + + + 951f308487b136cead953717bdacd1504890c4e7b349608dcc0106090b2fc729 + + + + + + 0b59fbbff7e2ef512cac861ab23e53f78633bce7 + + + + + + 0dbb00a153644bc81d204ea676e3e684 + + + WIDE Project (1995-1998) + Juniper Networks, Inc. (2010-2011) + The Regents of the University of California (1982-1995) + + + + + + + + + + + + ProjectMix/OpenFastPath/src/ofp_uipc_domain.c + + + + + 7272f12ff41fbba8fa7e24d73ee9415cf4578f621fa5fa41550b7548520506f9 + + + + + + 7acbb4cf83136cee0c37c02708fa4020e77a2a90 + + + + + + 4c69cdeb54711238e111c71561832973 + + + The Regents of the University of California (1982-1993) + + + + + + + ProjectMix/OpenFastPath/src/ofp_uipc_domain.c + + + + + 7272f12ff41fbba8fa7e24d73ee9415cf4578f621fa5fa41550b7548520506f9 + + + + + + 7acbb4cf83136cee0c37c02708fa4020e77a2a90 + + + + + + 4c69cdeb54711238e111c71561832973 + + + The Regents of the University of California (1982-1993) + + + + + + + ProjectMix/OpenFastPath/TODO + + + + + 52c6f1495c3bc5beaba2f7f1ad15005c340a3f5837d3ed6f3f88fd1fece40ef5 + + + + + + 9ae6123993222dddf6ee3752dcf4e4d7eb3fb841 + + + + + + 0f4bd9ef9bbe89e88aa4acf2a2cd9281 + + + + + + + + ProjectMix/whitelisting/wl7_tcn_multiple_pfms.h + + + + + b704a8e8fc4f7ea8f7fed03e0d51921509539b2c1c318b361f2e6124ae6d7d46 + + + + + + 2a6454685cdf21d2ddba7d2f87e94128b21ae3b3 + + + + + + fb2a3020a400ee3c4fb7c516cc47c6a4 + + + ENEA Software AB (2015-2015) + Nokia (2015-2015) + + + + + + + + + + + + + + platform_frameworks_base + android-wear-n-preview-1 + NOASSERTION + https://github.com/android/platform_frameworks_base/archive/android-wear-n-preview-1.tar.gz + + + 6077144b04bd72497ef65ed1e95eb632b186fef7 + + + + + + + + ProjectMix/Android-Bluetooth/BluetoothGattCallback.java + + + + + 4934cc953e26fd064249e164dfa686fc496a2e04a9b613b98bc20a68e2d1f68c + + + + + + 81448cc136d30d0a1168c99c815037d1d9c82a79 + + + + + + c3e40ca8dc69c40dfd4d64b2d56b6f52 + + + The Android Open Source Project (2013-2013) + + + + + + ProjectMix/Android-Bluetooth/BluetoothGattCallbackWrapper.java + + + + + d6fa3f1512b448f7094c5edcab1bbd8590a461debe6dcb85f56e56e218d66e1b + + + + + + 707ace705147e68e6bbefc9d544b4bbbbb1785a9 + + + + + + e834225a4736deb48c916b8610eec7a6 + + + The Android Open Source Project (2014-2014) + + + + + + ProjectMix/Android-Bluetooth/BluetoothGattServerCallback.java + + + + + f2adaaf1518592f936736ac7e7ae3d047b335ab1e9339b3546c97dacaf29cc64 + + + + + + 081e2a492da710e07de531ddde4edd09580641ec + + + + + + 534f03349629027b3aef19dbefecb25e + + + The Android Open Source Project (2013-2013) + + + + + + ProjectMix/Files with Snippets/prop_with_android_snippet.java + + + + + 9429d72cfa8b512f4d5b236f8bf0446cc3f29fde012681e7a99d377ab64e3761 + + + + + + d44be11a7532e9b8c17dbc9d5edc0bf2de0f23ae + + + + + + 80ecd4ae8196579b0e3c121558f2d2b2 + + + FOSSID AB (2016-2016) + + + + + + + + + + + + + Joke + 930ed5f411b159caf1d17468372197cc5f6db65f + Organization: sunshinemyson + https://github.com/sunshinemyson/Joke/archive/930ed5f411b159caf1d17468372197cc5f6db65f.tar.gz + + + 75b14f2c64008ce3916233a40bb252bb73fe6230 + + + + + + + + + + pkg:github/sunshinemyson/Joke@930ed5f411b159caf1d17468372197cc5f6db65f + + + + + ProjectMix/whitelisting/wl1_common_qcom_header.c + + + + + 72ef09e6b2318a4eba93b9458c852a262759900e11629585f8f8e31bd0b351a0 + + + + + + 275cb513ad709c1cefe584d34fe4fda0efa0d800 + + + + + + e6880ab553a64f304b18685e700ac301 + + + Qualcomm Technologies Inc. (2014-2014) + + + + + + ProjectMix/whitelisting/wl6_qcomm_header_and_small_ofp_snippet.c + + + + + 798cd9d6e4d5f924b57864c5b17de73103b33fe6bd2d72029bdba54f62345a61 + + + + + + cc2425d9276de6a2581df0b88a5c10b5f68b8e41 + + + + + + ee4e48a2be05347fa1e8ec7b9b45a7f7 + + + Qualcomm Technologies Inc. (2014-2014) + + + + + + + + + + + + + jszip + 2.6.0 + + + + + + + + + + Organization: stuk + https://github.com/Stuk/jszip/archive/v2.6.0.zip + + + b2f729dda6e4dfbe52b3de3bf7c11d4575f99e6e + + + + + + + + + + pkg:github/Stuk/jszip@2.6.0 + + + + + ProjectMix/Multi-Licensed components/crc32.js + + + + + 44ed7dd5e696f969207dc0ddeec562dba57dc1664a83144baed38b574717806f + + + + + + f0c3cd1372246bdb714b6b82d8b6fdb5369a7003 + + + + + + d87d2e264921c9298ddfb49164e72f25 + + + + + + + + ProjectMix/Multi-Licensed components/crc32.js + + + + + 44ed7dd5e696f969207dc0ddeec562dba57dc1664a83144baed38b574717806f + + + + + + f0c3cd1372246bdb714b6b82d8b6fdb5369a7003 + + + + + + d87d2e264921c9298ddfb49164e72f25 + + + + + + + + ProjectMix/Multi-Licensed components/jszip.js + + + + + 0abe53cc05ce94d2614e506d42a17144b2030ddd86cd42d9afc2b8423d4f2eaf + + + + + + fd52230d61fcc4675bab01526a37aa205cf9faff + + + + + + 56deaae44a88e138e960de086ef33d76 + + + Stuart Knightley (2009-2014) + + + + + + + + + + + + ProjectMix/Multi-Licensed components/jszip.js + + + + + 0abe53cc05ce94d2614e506d42a17144b2030ddd86cd42d9afc2b8423d4f2eaf + + + + + + fd52230d61fcc4675bab01526a37aa205cf9faff + + + + + + 56deaae44a88e138e960de086ef33d76 + + + Stuart Knightley (2009-2014) + + + + + + + + + + + + + + + + + + + node-forge + 1.0.0 + + + + + + + + + + Organization: npmjs + https://registry.npmjs.org/node-forge/-/node-forge-1.0.0.tgz + + + 082b4ee9fea0a820e3f7d03c7f1ce370f515c451 + + + + + + + + + + pkg:npm/npmjs/node-forge@1.0.0 + + + + + ProjectMix/Multi-Licensed components/forge.min.js + + + + + 5122c4c9dbc6bc91cd7fe7f5562a93b02a99912c83b661b652c2f770401506f2 + + + + + + 799f17805c30261c82c67830eca639feff2393cb + + + + + + e34cd774be24e16970bd2e07e2e516aa + + + + + + + + ProjectMix/Multi-Licensed components/forge.min.js + + + + + 5122c4c9dbc6bc91cd7fe7f5562a93b02a99912c83b661b652c2f770401506f2 + + + + + + 799f17805c30261c82c67830eca639feff2393cb + + + + + + e34cd774be24e16970bd2e07e2e516aa + + + + + + + + ProjectMix/Multi-Licensed components/prime.worker.min.js + + + + + e367bd535452e21e61e02e6886d6f1b836c9596f649101d6573b3254c6f30f79 + + + + + + 4e0ffc99be91d349669f2b365ed407ba6ce85e4d + + + + + + cb525370d1bab18df674eae5d44b282e + + + + + + + + ProjectMix/Multi-Licensed components/prime.worker.min.js + + + + + e367bd535452e21e61e02e6886d6f1b836c9596f649101d6573b3254c6f30f79 + + + + + + 4e0ffc99be91d349669f2b365ed407ba6ce85e4d + + + + + + cb525370d1bab18df674eae5d44b282e + + + + + + + + + + + + + + + 13781114 + 6 + Organization: Janus Troelsen + https://stackoverflow.com/revisions/13781114/6 + + + f901876caacb6bc4bc937fe44b039b5939f32b9a + + + + + + + + + + pkg:/Janus-Troelsen/13781114@6 + + + + + ProjectMix/Snippets from Stack Overflow/python_sample_snippet.py + + + + + ec907085160480a2603c9c94948098d9e18f17af684182df6dc4d6fdf5116d34 + + + + + + b005adbed406dcb336e59a57b1e02680240477b1 + + + + + + 4a80d2ffb9490200ef3b63524f3df10b + + + + + + + + ProjectMix/Snippets from Stack Overflow/python_sample_snippet.py + + + + + ec907085160480a2603c9c94948098d9e18f17af684182df6dc4d6fdf5116d34 + + + + + + b005adbed406dcb336e59a57b1e02680240477b1 + + + + + + 4a80d2ffb9490200ef3b63524f3df10b + + + + + + + + + + + + + + + libxml2 + 2.9.2-rc1 + + + + + + + + + + Organization: gnome + https://github.com/GNOME/libxml2/archive/v2.9.2-rc1.zip + + + 914f99cf8f3ebb6d193d12a73ad3129909af51e6 + + + + + + + + + + pkg:github/GNOME/libxml2@2.9.2-rc1 + + + + + ProjectMix/Files with Vulnerabilities/xmlreader.c + + + + + 06692d022b5833eedaa582876aca06b2075565a511ee0721adec6b25da583eed + + + + + + 6056d66cc44392070433a21f0853818d879376ba + + + + + + aaf8573e0987ed8cf9b1fb0a7f5c6b1b + + + for the status of + + + + + + + ProjectMix/Files with Vulnerabilities/xmlreader.c + + + + + 06692d022b5833eedaa582876aca06b2075565a511ee0721adec6b25da583eed + + + + + + 6056d66cc44392070433a21f0853818d879376ba + + + + + + aaf8573e0987ed8cf9b1fb0a7f5c6b1b + + + for the status of + + + + + + + + + + + + + + majordomo-mysensor + a3c87fbd8afb8988bbaab57a2c6093fc431588a9 + Organization: olehs + https://github.com/olehs/majordomo-mysensor/archive/a3c87fbd8afb8988bbaab57a2c6093fc431588a9.tar.gz + + + 58dee2d291191f75a83986eb4fe554ce6046b71f + + + + + + + + + + pkg:github/olehs/majordomo-mysensor@a3c87fbd8afb8988bbaab57a2c6093fc431588a9 + + + + + ProjectMix/whitelisting/wl4_public_algorithm_crc32.php + + + + + 5c14e8760773545e6e3d919c4490b619cfdd919fc10436b82bd3c067da9bb0b5 + + + + + + 27e4b6454faae3740282d2143c606b90d2b1115e + + + + + + 0dccd84f6cc6585f7b2cd0df2d2187a6 + + + + + + + + + + + + + + + ruby-domain_name + 0.5.20160826 + Organization: knu + https://github.com/knu/ruby-domain_name/archive/v0.5.20160826.tar.gz + + + eaa3b4f5ff196456711a4ee5c65c40544f586b39 + + + + + + + + + + pkg:github/knu/ruby-domain_name@0.5.20160826 + + + + + ProjectMix/Multi-Licensed components/gen_etld_data.rb + + + + + cb6264a7ccec7a840bfe0c78c2f12907900762f9f028bcf4c51e515f821d2e66 + + + + + + b7f7e9ddb4bfa49485efd6cf8590666db60d8de3 + + + + + + 774b446069ea0cd5b95fa7c36cf6477d + + + + + + + + ProjectMix/Multi-Licensed components/gen_etld_data.rb + + + + + cb6264a7ccec7a840bfe0c78c2f12907900762f9f028bcf4c51e515f821d2e66 + + + + + + b7f7e9ddb4bfa49485efd6cf8590666db60d8de3 + + + + + + 774b446069ea0cd5b95fa7c36cf6477d + + + + + + + + + + + + + + + samba + tevent-0.9.34 + Organization: samba-team + https://github.com/samba-team/samba/archive/tevent-0.9.34.tar.gz + + + 147e4e65614f159f6b6581682bf052bda129123d + + + + + + + + + + pkg:github/samba-team/samba@0.9.34 + + + + + ProjectMix/Files with Vulnerabilities/process.c + + + + + e2f8c82900e4d1c409ebe38fad3941614956848f7daf482a2780d04858554026 + + + + + + 20f9e0304984fb7a1c66ca826eb3c6aa859be666 + + + + + + 7a15ac70b7e1e360d5da65b8cd934722 + + + Andrew Tridgell 1998 (1992-1992) + Volker Lendecke (2005-2007) + + + + + + + ProjectMix/Files with Vulnerabilities/process.c + + + + + e2f8c82900e4d1c409ebe38fad3941614956848f7daf482a2780d04858554026 + + + + + + 20f9e0304984fb7a1c66ca826eb3c6aa859be666 + + + + + + 7a15ac70b7e1e360d5da65b8cd934722 + + + Andrew Tridgell 1998 (1992-1992) + Volker Lendecke (2005-2007) + + + + + + + + + + + + + + tutor + 1.0.0-alpha + + + + + + + + + + Organization: themeum + https://github.com/themeum/tutor/archive/v1.0.0-alpha.tar.gz + + + a4459260a32d37d0cf294fa713d6f3c321354139 + + + + + + + + + + pkg:github/themeum/tutor@1.0.0-alpha + + + + + ProjectMix/whitelisting/wl5_common_array_languages.c + + + + + ede6383ac52becfe7ccf8960d4435752598301f663772888d8ce9a66c3525236 + + + + + + 87b4fb5dc1631c60d4193e583248d479a364e56a + + + + + + 8bb553c4fbe38da96793f403ae173035 + + + FOSSID (2016-2016) + + + + + + + + + + + + + 9082892 + 1 + Organization: Milan Mendpara + https://stackoverflow.com/revisions/9082892/1 + + + 4ebf9d630bf85e7e2cd2abdc88768a15bf1bfb11 + + + + + + + + + + pkg:/Milan-Mendpara/9082892@1 + + + + + ProjectMix/whitelisting/wl3_common_class.java + + + + + eab8b2286970cf5fd9c6326a5731628256caf0286b8e5b7a3f6da4c2fa7c4ef3 + + + + + + 08a237746e54ca4d7eaba009e3a79a60112ec5db + + + + + + 1243824b1faf47884defec085b321b9c + + + FOSSID AB + + + + + + + ProjectMix/whitelisting/wl3_common_class.java + + + + + eab8b2286970cf5fd9c6326a5731628256caf0286b8e5b7a3f6da4c2fa7c4ef3 + + + + + + 08a237746e54ca4d7eaba009e3a79a60112ec5db + + + + + + 1243824b1faf47884defec085b321b9c + + + FOSSID AB + + + + + + + + + + + + + + pantry + pantry-2.0.7 + Organization: comcast + https://github.com/Comcast/pantry/archive/pantry-2.0.7.tar.gz + + + 09c34181f67604152aac1de1d1b19f51a4d3c30b + + + + + + + + + + pkg:github/Comcast/pantry@2.0.7 + + + + + ProjectMix/whitelisting/wl2_common_apache_header.c + + + + + f4ff50f2defd6c0c2a481e3a2d680adf100d9f35612601ebf5788ea054d2252c + + + + + + bcf71f5abb682ef7dfc5c4f9f6853b00fa7cd7a3 + + + + + + 47c863790c6309c0c55d85903196bd18 + + + Comcast Cable Communications Management LLC (2015-2015) + + + + + + + + + + + + + android_frameworks_base + android-n-mr1-preview-1 + Organization: crdroidandroid + https://github.com/crdroidandroid/android_frameworks_base/archive/android-n-mr1-preview-1.tar.gz + + + 2ee50741fca360768f20e40cec7cac9eb415b954 + + + • The Android Open Source Project (2005-2008) +• The Apache Software Foundation (1999-2006) +• The Apache Software Foundation (2005-2006) +• Nuance Communications, but (2007-2007) +• PacketVideo, but (1998-2009) +• Apple Computer, Inc. but (2004-2004) +• John Cowan (2002-2008) +• VisualOn, but (2003-2010) +• NXP Software (2004-2010) +• The Android Open Source Project, but (2010-2010) +• Unicode, Inc. (1991-2008) + + + + + + + + + pkg:github/crdroidandroid/android_frameworks_base@android-n-mr1-preview-1 + + + + + ProjectMix/Android-Bluetooth/BluetoothActivityEnergyInfo.java + + + + + b50ba9b14cf9840a24f44558c211e02005779321f8ee570e74b017fc6607acdf + + + + + + 3313ba31de98878ab319e0a85d62e9ca00e27a7f + + + + + + 33367674dde4914b2ad9b9d0a15f824d + + + The Android Open Source Project (2014-2014) + + + + + + + ProjectMix/Android-Bluetooth/BluetoothActivityEnergyInfo.java + + + + + b50ba9b14cf9840a24f44558c211e02005779321f8ee570e74b017fc6607acdf + + + + + + 3313ba31de98878ab319e0a85d62e9ca00e27a7f + + + + + + 33367674dde4914b2ad9b9d0a15f824d + + + The Android Open Source Project (2014-2014) + + + + + + + ProjectMix/Android-Bluetooth/BluetoothAudioConfig.java + + + + + fcc52b553eb699f82e9ccf1883519d54ae30e3477570994ee2bad7dad3a699d0 + + + + + + 9c24e137487ac8a0d1da72f16e38e3ff11fee8c9 + + + + + + fbdbe76bc4dd9b97efcec00c8fc19c7e + + + The Android Open Source Project (2009-2009) + + + + + + + ProjectMix/Android-Bluetooth/BluetoothAudioConfig.java + + + + + fcc52b553eb699f82e9ccf1883519d54ae30e3477570994ee2bad7dad3a699d0 + + + + + + 9c24e137487ac8a0d1da72f16e38e3ff11fee8c9 + + + + + + fbdbe76bc4dd9b97efcec00c8fc19c7e + + + The Android Open Source Project (2009-2009) + + + + + + + ProjectMix/Android-Bluetooth/BluetoothAvrcp.java + + + + + 1ee18800f2b0ca59ca897d1bd9b5c2d63ba820166bcebbdc706df061fc2935b3 + + + + + + a656cff39fc40783bc3ca9f8da940cea99ab18bf + + + + + + 33b65e1d754515f3aaf875dcb7ce9419 + + + The Android Open Source Project (2014-2014) + + + + + + + ProjectMix/Android-Bluetooth/BluetoothAvrcp.java + + + + + 1ee18800f2b0ca59ca897d1bd9b5c2d63ba820166bcebbdc706df061fc2935b3 + + + + + + a656cff39fc40783bc3ca9f8da940cea99ab18bf + + + + + + 33b65e1d754515f3aaf875dcb7ce9419 + + + The Android Open Source Project (2014-2014) + + + + + + + ProjectMix/Android-Bluetooth/BluetoothAvrcpPlayerSettings.java + + + + + 43907a2701758afa7783fad7cd3cb4df96ca20d8d261bb6633ab0d3e91ab41ad + + + + + + b8f5b648138508dcdac874887b3c66fc2246c2b6 + + + + + + 85c5af7689e3aadf2f06c649977a91bd + + + The Android Open Source Project (2015-2015) + + + + + + + ProjectMix/Android-Bluetooth/BluetoothAvrcpPlayerSettings.java + + + + + 43907a2701758afa7783fad7cd3cb4df96ca20d8d261bb6633ab0d3e91ab41ad + + + + + + b8f5b648138508dcdac874887b3c66fc2246c2b6 + + + + + + 85c5af7689e3aadf2f06c649977a91bd + + + The Android Open Source Project (2015-2015) + + + + + + + ProjectMix/Android-Bluetooth/BluetoothDevicePicker.java + + + + + 6019fb0694ffd219862626754642f412192fee5de8089cae16f921b95a3a6c4d + + + + + + 936727ae974c1cccba345e7b9dd94839940640b3 + + + + + + a583c244accf4db868155c9302ab9c40 + + + The Android Open Source Project (2009-2009) + + + + + + + ProjectMix/Android-Bluetooth/BluetoothDevicePicker.java + + + + + 6019fb0694ffd219862626754642f412192fee5de8089cae16f921b95a3a6c4d + + + + + + 936727ae974c1cccba345e7b9dd94839940640b3 + + + + + + a583c244accf4db868155c9302ab9c40 + + + The Android Open Source Project (2009-2009) + + + + + + + ProjectMix/Android-Bluetooth/BluetoothGattDescriptor.java + + + + + 7c3b0fe5ca31997695b4179b3f57b2e70a1480d031ad5feb37fdd240f15e2666 + + + + + + 3d43efa468a52d446be8462e50b55400da5d703d + + + + + + 99ca685a3e575145c3f970d9d50a181b + + + The Android Open Source Project (2013-2013) + + + + + + + ProjectMix/Android-Bluetooth/BluetoothGattDescriptor.java + + + + + 7c3b0fe5ca31997695b4179b3f57b2e70a1480d031ad5feb37fdd240f15e2666 + + + + + + 3d43efa468a52d446be8462e50b55400da5d703d + + + + + + 99ca685a3e575145c3f970d9d50a181b + + + The Android Open Source Project (2013-2013) + + + + + + + ProjectMix/Android-Bluetooth/BluetoothGattIncludedService.java + + + + + 3c27e979fd0435d4cf734dfdd99d99286c6155d849ca329ecefe0194b1b2d099 + + + + + + b9bc6d928782106af39dd9a3a49723398243fa45 + + + + + + d0cf3e79d9a847194fcbc70f6bfdf261 + + + The Android Open Source Project (2016-2016) + + + + + + + ProjectMix/Android-Bluetooth/BluetoothGattIncludedService.java + + + + + 3c27e979fd0435d4cf734dfdd99d99286c6155d849ca329ecefe0194b1b2d099 + + + + + + b9bc6d928782106af39dd9a3a49723398243fa45 + + + + + + d0cf3e79d9a847194fcbc70f6bfdf261 + + + The Android Open Source Project (2016-2016) + + + + + + + + + + + + + + blaze-material-ui + 0.1.9 + Organization: codesignal + https://github.com/CodeSignal/blaze-material-ui/archive/0.1.9.tar.gz + + + 4cf8e7ea0c64865a9133432840ef3669019650a6 + + + + + + + + + + pkg:github/codesignal/blaze-material-ui@0.1.9 + + + + + ProjectMix/Files with Unusual Licenses/jquery.autogrowtextarea.js + + + + + 795edb928c8db4edecc2e65b378a1282dcd82c1a877478859a1f054e64b5992d + + + + + + 4b96d79a864bc54ee0c4c3d9dd87ae80848eb55f + + + + + + dfb12f0b952706a9e129216f3dbe6477 + + + + + + + + ProjectMix/Files with Unusual Licenses/jquery.autogrowtextarea.js + + + + + 795edb928c8db4edecc2e65b378a1282dcd82c1a877478859a1f054e64b5992d + + + + + + 4b96d79a864bc54ee0c4c3d9dd87ae80848eb55f + + + + + + dfb12f0b952706a9e129216f3dbe6477 + + + + + + + + + + + + + + + nclick + 0.0.0 + Organization: copypaste + https://files.pythonhosted.org/packages/95/12/7fb2efb2f32ee977d29cc1f696e73570b100be1b7a7251f162f1114d7f7f/nclick-0.0.0.tar.gz + + + 01ecd01fbf7d87e90626465b8735613cff4b3d76 + + + + + + + + + + pkg:pypi/nclick@0.0.0 + + + + + ProjectMix/Files with Snippets/runner.py + + + + + d069e1389b57da69f8203b3e5fb39403dfed77ca5d244a6b21155892ddab8999 + + + + + + 04ed75493eb800e8389fe107e73f08df16d893af + + + + + + 1712d18cc6aae3f7d108df22a8ce0508 + + + + + + + + ProjectMix/Files with Snippets/runner.py + + + + + d069e1389b57da69f8203b3e5fb39403dfed77ca5d244a6b21155892ddab8999 + + + + + + 04ed75493eb800e8389fe107e73f08df16d893af + + + + + + 1712d18cc6aae3f7d108df22a8ce0508 + + + + + + + + + + + + + + ProjectMix + 2025-06-20 22:19:05 + Person: Tomas Gonzalez tomas.gonzalez@fossid.com + NOASSERTION + false + + + + + + + + + + LicenseRef-BSD-3-Clause-UC + BSD-3-Clause (University of California-Specific) + BSD-3-Clause (University of California-Specific) + +Copyright [various years] The Regents of the University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + + 4. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + + + LicenseRef-GPL + GPL + GPL + + + + + LicenseRef-GPL-3.0 + GPL + GPL-3.0 + + + + + LicenseRef-MIT-1998 + MIT License 1998 + Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that both the above copyright notice and this +permission notice appear in all copies, that both the above +copyright notice and this permission notice appear in all +supporting documentation, and that the name of M.I.T. not be used +in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. M.I.T. makes +no representations about the suitability of this software for any +purpose. It is provided "as is" without express or implied +warranty. + +THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS +ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT +SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + + + + diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index b8c8166..fd1027b 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -306,7 +306,7 @@ def mock_workbench_api(mocker): mock_api.wait_for_scan_to_finish.return_value = ({"status": "FINISHED", "is_finished": "1"}, 10.0) # --- Mock Status Checkers --- - mock_api.ensure_process_can_start = MagicMock(return_value=None) + mock_api.ensure_scan_is_idle = MagicMock(return_value=None) mock_api.get_scan_information.return_value = {"status": "NEW", "usage": "git"} mock_api.get_scan_status.return_value = {"status": "FINISHED", "is_finished": "1"} mock_api._standard_scan_status_accessor.return_value = "FINISHED" diff --git a/tests/integration/test_integration.py b/tests/integration/test_integration.py index b3fbee9..cb07088 100644 --- a/tests/integration/test_integration.py +++ b/tests/integration/test_integration.py @@ -166,7 +166,7 @@ def test_scan_fail_during_scan(mock_open, mock_getsize, mock_isdir, mock_exists, {"json_data": {"status": "1", "data": []}}, # 4. create_webapp_scan call {"json_data": {"status": "1", "data": {"scan_id": "123"}}}, - # 5. _assert_scan_is_idle -> get_scan_status (check scan status before starting) + # 5. _ensure_scan_is_idle -> get_scan_status (check scan status before starting) {"json_data": {"status": "1", "data": {"status": "NEW"}}}, # 6. upload_files {"status_code": 200, "json_data": {"status": "1"}}, diff --git a/tests/integration/test_scan_integration.py b/tests/integration/test_scan_integration.py index b1c1957..c94dc00 100644 --- a/tests/integration/test_scan_integration.py +++ b/tests/integration/test_scan_integration.py @@ -47,7 +47,7 @@ def test_scan_success_flow_simple(self, mocker, tmp_path, capsys): return_value=({"status": "FINISHED", "is_finished": "1"}, 10.0)) # Mock status checkers with correct class name - mocker.patch('workbench_cli.api.helpers.scan_status_checkers.StatusCheckers.ensure_process_can_start', + mocker.patch('workbench_cli.api.helpers.scan_status_checkers.StatusCheckers.ensure_scan_is_idle', return_value=None) # File system operations @@ -98,7 +98,7 @@ def test_scan_with_autoid_flags(self, mocker, tmp_path, capsys): return_value=({"status": "FINISHED", "is_finished": "1"}, 10.0)) # Mock status checkers - mocker.patch('workbench_cli.api.helpers.scan_status_checkers.StatusCheckers.ensure_process_can_start', + mocker.patch('workbench_cli.api.helpers.scan_status_checkers.StatusCheckers.ensure_scan_is_idle', return_value=None) # File system operations @@ -152,7 +152,7 @@ def test_scan_with_dependency_analysis(self, mocker, tmp_path, capsys): return_value=({"status": "FINISHED", "is_finished": "1"}, 10.0)) # Mock status checkers - mocker.patch('workbench_cli.api.helpers.scan_status_checkers.StatusCheckers.ensure_process_can_start', + mocker.patch('workbench_cli.api.helpers.scan_status_checkers.StatusCheckers.ensure_scan_is_idle', return_value=None) # File system operations diff --git a/tests/unit/api/helpers/test_scan_status_checkers.py b/tests/unit/api/helpers/test_scan_status_checkers.py index 897dc5d..8353b7b 100644 --- a/tests/unit/api/helpers/test_scan_status_checkers.py +++ b/tests/unit/api/helpers/test_scan_status_checkers.py @@ -100,71 +100,4 @@ def test_standard_scan_status_accessor_access_error(status_checker_inst): status = status_checker_inst._standard_scan_status_accessor(data) assert status == "ACCESS_ERROR" -# --- Test ensure_process_can_start --- -def test_ensure_process_can_start_when_new(status_checker_inst, mocker): - """Test ensure_process_can_start when the initial status is NEW.""" - mocker.patch.object(status_checker_inst, 'get_scan_status', return_value={"status": "NEW"}) - - # Should not raise any exception - status_checker_inst.ensure_process_can_start("SCAN", "scan1", 30, 5) - -def test_ensure_process_can_start_when_finished(status_checker_inst, mocker): - """Test ensure_process_can_start when the initial status is FINISHED.""" - mocker.patch.object(status_checker_inst, 'get_scan_status', return_value={"status": "FINISHED"}) - - # Should not raise any exception - status_checker_inst.ensure_process_can_start("SCAN", "scan1", 30, 5) - -def test_ensure_process_can_start_when_failed(status_checker_inst, mocker): - """Test ensure_process_can_start when the initial status is FAILED.""" - mocker.patch.object(status_checker_inst, 'get_scan_status', return_value={"status": "FAILED"}) - - # Should not raise any exception - status_checker_inst.ensure_process_can_start("SCAN", "scan1", 30, 5) - -def test_ensure_process_can_start_when_running_then_wait_success(status_checker_inst, mocker): - """Test ensure_process_can_start when status is running but wait succeeds.""" - mocker.patch.object(status_checker_inst, 'get_scan_status', return_value={"status": "RUNNING"}) - mocker.patch.object(status_checker_inst, 'wait_for_scan_to_finish', return_value=None) - - status_checker_inst.ensure_process_can_start("SCAN", "scan1", 30, 5) - - # Verify wait_for_scan_to_finish was called - status_checker_inst.wait_for_scan_to_finish.assert_called_once_with("SCAN", "scan1", 30, 5) - -def test_ensure_process_can_start_when_running_then_wait_error(status_checker_inst, mocker): - """Test ensure_process_can_start when status is running and wait fails.""" - mocker.patch.object(status_checker_inst, 'get_scan_status', return_value={"status": "RUNNING"}) - mocker.patch.object(status_checker_inst, 'wait_for_scan_to_finish', side_effect=ProcessTimeoutError("Timeout")) - - with pytest.raises(ProcessError, match="Could not start SCAN for 'scan1' because waiting for the existing process failed: Timeout"): - status_checker_inst.ensure_process_can_start("SCAN", "scan1", 30, 5) - - # Verify wait_for_scan_to_finish was called - status_checker_inst.wait_for_scan_to_finish.assert_called_once_with("SCAN", "scan1", 30, 5) - -def test_ensure_process_can_start_other_status(status_checker_inst, mocker): - """Test ensure_process_can_start with a status that isn't allowed.""" - # Mocking get_scan_status to return a status that's not in the allowed list - mocker.patch.object( - status_checker_inst, - 'get_scan_status', - return_value={"status": "NOT_ALLOWED_STATUS"} - ) - - with pytest.raises(CompatibilityError): - # The helper's ensure_process_can_start method should raise a ProcessError - # for statuses that are not NEW, FINISHED, FAILED, CANCELLED, or RUNNING/QUEUED. - status_checker_inst.ensure_process_can_start("SCAN", "scan1", 1, 1) - -def test_ensure_process_can_start_scan_not_found(status_checker_inst, mocker): - """Test ensure_process_can_start when the scan is not found.""" - mocker.patch.object(status_checker_inst, 'get_scan_status', side_effect=ScanNotFoundError("Not Found")) - - with pytest.raises(ScanNotFoundError): - status_checker_inst.ensure_process_can_start("SCAN", "scan1", 30, 5) - -def test_ensure_process_can_start_invalid_type(status_checker_inst): - """Test that an invalid process type raises a ValueError.""" - with pytest.raises(ValueError, match="Invalid process_type 'INVALID' provided to ensure_process_can_start"): - status_checker_inst.ensure_process_can_start("INVALID", "scan1", 30, 5) \ No newline at end of file + \ No newline at end of file diff --git a/tests/unit/api/test_scans_api.py b/tests/unit/api/test_scans_api.py index 400330c..1f7057e 100644 --- a/tests/unit/api/test_scans_api.py +++ b/tests/unit/api/test_scans_api.py @@ -202,7 +202,7 @@ def test_extract_archives_api_error(mock_send, scans_api_inst): scans_api_inst.extract_archives("scan1", True, True) # --- Tests for run_scan and related methods --- -@patch.object(ScansAPI, 'ensure_process_can_start') +@patch.object(ScansAPI, 'ensure_scan_is_idle') @patch.object(ScansAPI, '_send_request') def test_run_scan_basic_success(mock_send, mock_ensure, scans_api_inst): mock_send.return_value = {"status": "1"} @@ -229,7 +229,7 @@ def test_run_scan_basic_success(mock_send, mock_ensure, scans_api_inst): assert payload['data']['delta_only'] == 0 assert 'reuse_identification' not in payload['data'] -@patch.object(ScansAPI, 'ensure_process_can_start') +@patch.object(ScansAPI, 'ensure_scan_is_idle') @patch.object(ScansAPI, '_send_request') def test_run_scan_with_run_dependency_analysis(mock_send, mock_ensure, scans_api_inst): mock_send.return_value = {"status": "1"} @@ -251,7 +251,7 @@ def test_run_scan_with_run_dependency_analysis(mock_send, mock_ensure, scans_api assert payload['data']['scan_code'] == 'scan1' assert payload['data']['run_dependency_analysis'] == "1" -@patch.object(ScansAPI, 'ensure_process_can_start') +@patch.object(ScansAPI, 'ensure_scan_is_idle') @patch.object(ScansAPI, '_send_request') def test_run_scan_with_id_reuse_any(mock_send, mock_ensure, scans_api_inst): mock_send.return_value = {"status": "1"} @@ -270,7 +270,7 @@ def test_run_scan_with_id_reuse_any(mock_send, mock_ensure, scans_api_inst): assert payload['data']['reuse_identification'] == "1" assert payload['data']['identification_reuse_type'] == "any" -@patch.object(ScansAPI, 'ensure_process_can_start') +@patch.object(ScansAPI, 'ensure_scan_is_idle') @patch.object(ScansAPI, '_send_request') def test_run_scan_with_id_reuse_project(mock_send, mock_ensure, scans_api_inst): mock_send.return_value = {"status": "1"} @@ -291,7 +291,7 @@ def test_run_scan_with_id_reuse_project(mock_send, mock_ensure, scans_api_inst): assert payload['data']['identification_reuse_type'] == "specific_project" assert payload['data']['specific_code'] == "PROJECT_CODE" -@patch.object(ScansAPI, 'ensure_process_can_start') +@patch.object(ScansAPI, 'ensure_scan_is_idle') @patch.object(ScansAPI, '_send_request') def test_run_scan_with_id_reuse_scan(mock_send, mock_ensure, scans_api_inst): mock_send.return_value = {"status": "1"} @@ -312,7 +312,7 @@ def test_run_scan_with_id_reuse_scan(mock_send, mock_ensure, scans_api_inst): assert payload['data']['identification_reuse_type'] == "specific_scan" assert payload['data']['specific_code'] == "OTHER_SCAN_CODE" -@patch.object(ScansAPI, 'ensure_process_can_start') +@patch.object(ScansAPI, 'ensure_scan_is_idle') @patch.object(ScansAPI, '_send_request') def test_run_scan_not_found(mock_send, mock_ensure, scans_api_inst): mock_send.return_value = {"status": "0", "error": "Scan not found"} @@ -328,7 +328,7 @@ def test_run_scan_not_found(mock_send, mock_ensure, scans_api_inst): id_reuse=False ) -@patch.object(ScansAPI, 'ensure_process_can_start') +@patch.object(ScansAPI, 'ensure_scan_is_idle') @patch.object(ScansAPI, '_send_request') def test_run_scan_id_reuse_validation_error(mock_send, mock_ensure, scans_api_inst): # Configure mock to return success @@ -359,7 +359,7 @@ def test_run_scan_id_reuse_validation_error(mock_send, mock_ensure, scans_api_in assert "specific_code" not in payload["data"], "specific_code should not be in payload when disabled" # --- Tests for dependency analysis --- -@patch.object(ScansAPI, 'ensure_process_can_start') +@patch.object(ScansAPI, 'ensure_scan_is_idle') @patch.object(ScansAPI, '_send_request') def test_start_dependency_analysis_success(mock_send, mock_ensure, scans_api_inst): mock_send.return_value = {"status": "1"} @@ -371,7 +371,7 @@ def test_start_dependency_analysis_success(mock_send, mock_ensure, scans_api_ins assert payload['data']['scan_code'] == 'scan1' assert payload['data']['import_only'] == "0" -@patch.object(ScansAPI, 'ensure_process_can_start') +@patch.object(ScansAPI, 'ensure_scan_is_idle') @patch.object(ScansAPI, '_send_request') def test_start_dependency_analysis_import_only(mock_send, mock_ensure, scans_api_inst): mock_send.return_value = {"status": "1"} @@ -379,7 +379,7 @@ def test_start_dependency_analysis_import_only(mock_send, mock_ensure, scans_api payload = mock_send.call_args[0][0] assert payload['data']['import_only'] == "1" -@patch.object(ScansAPI, 'ensure_process_can_start') +@patch.object(ScansAPI, 'ensure_scan_is_idle') @patch.object(ScansAPI, '_send_request') def test_start_dependency_analysis_scan_not_found(mock_send, mock_ensure, scans_api_inst): mock_send.return_value = {"status": "0", "error": "Scan not found"} @@ -591,19 +591,50 @@ def test_check_scan_report_status_success(mock_send, scans_api_inst): assert payload['data']['type'] == 'REPORT_GENERATION' @patch.object(ScansAPI, '_send_request') -@patch.object(ScansAPI, 'ensure_process_can_start') -def test_get_scan_information_failure(mock_ensure_process_can_start, mock_send_request, scans_api_inst): +@patch.object(ScansAPI, 'ensure_scan_is_idle') +def test_get_scan_information_failure(mock_ensure_scan_is_idle, mock_send_request, scans_api_inst): mock_send_request.return_value = {"status": "0", "error": "Not found"} with pytest.raises(ApiError, match="Not found"): scans_api_inst.get_scan_information("scan1") @patch.object(ScansAPI, '_send_request') -@patch.object(ScansAPI, 'ensure_process_can_start') -def test_method_pre_check_failure(mock_ensure_process_can_start, mock_send_request, scans_api_inst, caplog): - mock_ensure_process_can_start.side_effect = Exception("Pre-check failed") +@patch.object(ScansAPI, 'ensure_scan_is_idle') +def test_method_pre_check_failure(mock_ensure_scan_is_idle, mock_send_request, scans_api_inst, caplog): + mock_ensure_scan_is_idle.side_effect = Exception("Pre-check failed") with pytest.raises(Exception, match="Pre-check failed"): scans_api_inst.run_scan("scan1", 10, 10, False, False, False, False, False) assert "Pre-scan check failed" in caplog.text - mock_send_request.assert_not_called() \ No newline at end of file + mock_send_request.assert_not_called() + +# --- Tests for import_report method --- +@patch.object(ScansAPI, '_send_request') +def test_import_report_success(mock_send, scans_api_inst): + """Test successful SBOM/report import.""" + mock_send.return_value = {"status": "1", "data": {"message": "Import started successfully"}} + + result = scans_api_inst.import_report("scan1") + + assert result is None + mock_send.assert_called_once() + payload = mock_send.call_args[0][0] + assert payload['group'] == 'scans' + assert payload['action'] == 'import_report' + assert payload['data']['scan_code'] == 'scan1' + +@patch.object(ScansAPI, '_send_request') +def test_import_report_scan_not_found(mock_send, scans_api_inst): + """Test import_report with scan not found.""" + mock_send.return_value = {"status": "0", "error": "Scan not found"} + + with pytest.raises(ScanNotFoundError, match="Scan 'scan1' not found"): + scans_api_inst.import_report("scan1") + +@patch.object(ScansAPI, '_send_request') +def test_import_report_api_error(mock_send, scans_api_inst): + """Test import_report with API error.""" + mock_send.return_value = {"status": "0", "error": "Import failed"} + + with pytest.raises(ApiError, match="Failed to start SBOM report import for 'scan1': Import failed"): + scans_api_inst.import_report("scan1") \ No newline at end of file diff --git a/tests/unit/api/test_upload_api.py b/tests/unit/api/test_upload_api.py index e1f59a9..d80745a 100644 --- a/tests/unit/api/test_upload_api.py +++ b/tests/unit/api/test_upload_api.py @@ -117,4 +117,34 @@ def test_upload_dependency_analysis_results_validation(mock_isfile, mock_exists, upload_api_inst.upload_dependency_analysis_results("scan1", "/path/to/directory") mock_exists.assert_called_once_with("/path/to/directory") - mock_isfile.assert_called_once_with("/path/to/directory") \ No newline at end of file + mock_isfile.assert_called_once_with("/path/to/directory") + +@patch('os.path.exists') +@patch('os.path.isfile') +def test_upload_sbom_file_validation(mock_isfile, mock_exists, upload_api_inst): + """Test that upload_sbom_file validates file existence.""" + mock_exists.return_value = False + + with pytest.raises(FileSystemError, match="SBOM file does not exist"): + upload_api_inst.upload_sbom_file("scan1", "/nonexistent/sbom.json") + + mock_exists.assert_called_once_with("/nonexistent/sbom.json") + +@patch('os.path.exists') +@patch('os.path.isfile') +def test_upload_sbom_file_not_a_file(mock_isfile, mock_exists, upload_api_inst): + """Test that upload_sbom_file validates that path is a file.""" + mock_exists.return_value = True + mock_isfile.return_value = False # Path exists but is not a file + + with pytest.raises(FileSystemError, match="SBOM file does not exist"): + upload_api_inst.upload_sbom_file("scan1", "/path/to/directory") + + mock_exists.assert_called_once_with("/path/to/directory") + mock_isfile.assert_called_once_with("/path/to/directory") + +@pytest.mark.skip(reason="Upload file tests require more complex mocking than is feasible") +def test_upload_sbom_file_success(upload_api_inst): + # This test is skipped because it requires complex mocking of file I/O operations + # and needs access to the internal implementation of the upload_sbom_file method + pass \ No newline at end of file diff --git a/tests/unit/cli/conftest.py b/tests/unit/cli/conftest.py index 3ad21b0..122547b 100644 --- a/tests/unit/cli/conftest.py +++ b/tests/unit/cli/conftest.py @@ -51,26 +51,37 @@ def mock_main_dependencies(): mocks['workbench_instance'] = MagicMock() mock_wb.return_value = mocks['workbench_instance'] - # Mock all handlers - with patch("workbench_cli.main.handle_scan") as mock_scan: + # Set up common API methods that handlers might use + mocks['workbench_instance'].resolve_project.return_value = "TEST_PROJECT_CODE" + mocks['workbench_instance'].resolve_scan.return_value = ("TEST_SCAN_CODE", 123) + mocks['workbench_instance'].ensure_scan_is_idle.return_value = None + + # Set up API methods that return empty/simple data to avoid JSON serialization issues + mocks['workbench_instance'].get_scan_folder_metrics.return_value = {} + mocks['workbench_instance'].get_dependency_analysis_results.return_value = [] + mocks['workbench_instance'].get_scan_identified_licenses.return_value = [] + mocks['workbench_instance'].get_scan_identified_components.return_value = [] + mocks['workbench_instance'].get_policy_warnings_counter.return_value = {} + mocks['workbench_instance'].list_vulnerabilities.return_value = [] + + # Mock all handlers - need to patch them at the main module level where they're imported + with patch("workbench_cli.main.handle_scan") as mock_scan, \ + patch("workbench_cli.main.handle_scan_git") as mock_scan_git, \ + patch("workbench_cli.main.handle_import_da") as mock_import, \ + patch("workbench_cli.main.handle_import_sbom") as mock_import_sbom, \ + patch("workbench_cli.main.handle_show_results") as mock_show, \ + patch("workbench_cli.main.handle_download_reports") as mock_download, \ + patch("workbench_cli.main.handle_evaluate_gates") as mock_gates: + mocks['handle_scan'] = mock_scan + mocks['handle_scan_git'] = mock_scan_git + mocks['handle_import_da'] = mock_import + mocks['handle_import_sbom'] = mock_import_sbom + mocks['handle_show_results'] = mock_show + mocks['handle_download_reports'] = mock_download + mocks['handle_evaluate_gates'] = mock_gates - with patch("workbench_cli.main.handle_scan_git") as mock_scan_git: - mocks['handle_scan_git'] = mock_scan_git - - with patch("workbench_cli.main.handle_import_da") as mock_import: - mocks['handle_import_da'] = mock_import - - with patch("workbench_cli.main.handle_show_results") as mock_show: - mocks['handle_show_results'] = mock_show - - with patch("workbench_cli.main.handle_download_reports") as mock_download: - mocks['handle_download_reports'] = mock_download - - with patch("workbench_cli.main.handle_evaluate_gates") as mock_gates: - mocks['handle_evaluate_gates'] = mock_gates - - yield mocks + yield mocks class ArgBuilder: @@ -108,6 +119,10 @@ def import_da(self, project='TestProject', scan='TestScan', path='results.json') self.args.extend(['import-da', '--project-name', project, '--scan-name', scan, '--path', path]) return self + def import_sbom(self, project='TestProject', scan='TestScan', path='bom.json'): + self.args.extend(['import-sbom', '--project-name', project, '--scan-name', scan, '--path', path]) + return self + def download_reports(self, scope='scan'): self.args.extend(['download-reports', '--report-scope', scope]) return self diff --git a/tests/unit/cli/test_argument_parsing.py b/tests/unit/cli/test_argument_parsing.py index 3a6f13e..2f4d340 100644 --- a/tests/unit/cli/test_argument_parsing.py +++ b/tests/unit/cli/test_argument_parsing.py @@ -79,6 +79,16 @@ def test_parse_import_da_command(self, args, arg_parser, mock_path_exists): assert parsed.scan_name == 'DAScan' assert parsed.path == 'results.json' + def test_parse_import_sbom_command(self, args, arg_parser, mock_path_exists): + """Test import-sbom command parsing.""" + cmd_args = args().import_sbom(project='SBOMProject', scan='SBOMScan', path='bom.json').build() + parsed = arg_parser(cmd_args) + + assert parsed.command == 'import-sbom' + assert parsed.project_name == 'SBOMProject' + assert parsed.scan_name == 'SBOMScan' + assert parsed.path == 'bom.json' + def test_parse_download_reports_scan_scope(self, args, arg_parser): """Test download-reports with scan scope.""" cmd_args = (args() diff --git a/tests/unit/cli/test_argument_validation.py b/tests/unit/cli/test_argument_validation.py index 5e6e2b5..10de34f 100644 --- a/tests/unit/cli/test_argument_validation.py +++ b/tests/unit/cli/test_argument_validation.py @@ -77,9 +77,9 @@ def test_scan_non_existent_path(self, args, arg_parser): def test_import_da_non_existent_path(self, args, arg_parser): """Test validation when import-da path doesn't exist.""" with patch('os.path.exists', return_value=False): - cmd_args = args().import_da(path='/non/existent/file.json').build() - - with pytest.raises(ValidationError, match=re.escape("Path does not exist: /non/existent/file.json")): + cmd_args = args().import_da(path='/non/existent/analyzer.json').build() + + with pytest.raises(ValidationError, match=re.escape("Path does not exist: /non/existent/analyzer.json")): arg_parser(cmd_args) @@ -168,6 +168,14 @@ def test_import_da_missing_path_raises_system_exit(self, arg_parser): with pytest.raises(SystemExit): arg_parser(cmd_args) + def test_import_sbom_missing_path_raises_system_exit(self, arg_parser): + """Test that import-sbom without path raises SystemExit.""" + cmd_args = ['workbench-cli', '--api-url', 'X', '--api-user', 'Y', '--api-token', 'Z', + 'import-sbom', '--project-name', 'P', '--scan-name', 'S'] + + with pytest.raises(SystemExit): + arg_parser(cmd_args) + def test_unknown_command_raises_system_exit(self, arg_parser): """Test that unknown command raises SystemExit.""" cmd_args = ['workbench-cli', '--api-url', 'X', '--api-user', 'Y', '--api-token', 'Z', 'unknown-command'] diff --git a/tests/unit/cli/test_main_function.py b/tests/unit/cli/test_main_function.py index b725e58..b9c7830 100644 --- a/tests/unit/cli/test_main_function.py +++ b/tests/unit/cli/test_main_function.py @@ -56,9 +56,21 @@ def test_main_success_with_import_da_handler(self, mock_main_dependencies): assert result == 0 mock_main_dependencies['handle_import_da'].assert_called_once() + def test_main_success_with_import_sbom_handler(self, mock_main_dependencies): + """Test successful main() execution with import-sbom handler.""" + mock_args = MagicMock(command="import-sbom", log="INFO") + mock_main_dependencies['handle_import_sbom'].return_value = True + + with patch("workbench_cli.main.parse_cmdline_args", return_value=mock_args): + result = main() + + assert result == 0 + mock_main_dependencies['handle_import_sbom'].assert_called_once() + def test_main_success_with_show_results_handler(self, mock_main_dependencies): """Test successful main() execution with show-results handler.""" mock_args = MagicMock(command="show-results", log="INFO") + mock_args.path_result = None # Don't trigger save functionality mock_main_dependencies['handle_show_results'].return_value = True with patch("workbench_cli.main.parse_cmdline_args", return_value=mock_args): diff --git a/tests/unit/handlers/conftest.py b/tests/unit/handlers/conftest.py index 969b643..895c7dd 100644 --- a/tests/unit/handlers/conftest.py +++ b/tests/unit/handlers/conftest.py @@ -33,7 +33,7 @@ def mock_workbench(mocker): # Common methods used across handlers mock.resolve_project = mocker.MagicMock(return_value='TEST_PROJ_CODE') mock.resolve_scan = mocker.MagicMock(return_value=('TEST_SCAN_CODE', 123)) - mock.ensure_process_can_start = mocker.MagicMock() + mock.ensure_scan_is_idle = mocker.MagicMock() mock.upload_dependency_analysis_results = mocker.MagicMock() mock.start_dependency_analysis = mocker.MagicMock() mock.wait_for_scan_to_finish = mocker.MagicMock(return_value=({}, 5.0)) diff --git a/tests/unit/handlers/test_evaluate_gates.py b/tests/unit/handlers/test_evaluate_gates.py index 589b483..0fcf7c9 100644 --- a/tests/unit/handlers/test_evaluate_gates.py +++ b/tests/unit/handlers/test_evaluate_gates.py @@ -5,6 +5,7 @@ # Import handler and dependencies from workbench_cli.handlers.evaluate_gates import handle_evaluate_gates +from workbench_cli.api import WorkbenchAPI from workbench_cli.exceptions import ( WorkbenchCLIError, ApiError, @@ -19,8 +20,7 @@ class TestEvaluateGatesHandler: """Test cases for the evaluate-gates handler.""" - @patch('workbench_cli.handlers.evaluate_gates.wait_for_scan_completion') - def test_handle_evaluate_gates_pass(self, mock_wait, mock_workbench, mock_params): + def test_handle_evaluate_gates_pass(self, mock_workbench, mock_params): """Test passing gate check with all conditions in good state.""" mock_params.command = 'evaluate-gates' mock_params.project_name = "ProjB" @@ -33,7 +33,7 @@ def test_handle_evaluate_gates_pass(self, mock_wait, mock_workbench, mock_params # Setup mocks mock_workbench.resolve_project.return_value = "PROJ_B_CODE" mock_workbench.resolve_scan.return_value = ("SCAN_CLEAN_CODE", 456) - mock_wait.return_value = (True, True, {}) # scan and DA completed + mock_workbench.ensure_scan_is_idle.return_value = None # scan and DA completed successfully successfully mock_workbench.get_pending_files.return_value = {} mock_workbench.get_policy_warnings_counter.return_value = { "policy_warnings_total": 0, @@ -46,8 +46,7 @@ def test_handle_evaluate_gates_pass(self, mock_wait, mock_workbench, mock_params result = handle_evaluate_gates(mock_workbench, mock_params) assert result is True # Should return True for PASS - @patch('workbench_cli.handlers.evaluate_gates.wait_for_scan_completion') - def test_handle_evaluate_gates_fail_pending(self, mock_wait, mock_workbench, mock_params): + def test_handle_evaluate_gates_fail_pending(self, mock_workbench, mock_params): """Test failing gate check due to pending files.""" mock_params.command = 'evaluate-gates' mock_params.project_name = "P" @@ -60,7 +59,7 @@ def test_handle_evaluate_gates_fail_pending(self, mock_wait, mock_workbench, moc # Setup mocks mock_workbench.resolve_project.return_value = "PC" mock_workbench.resolve_scan.return_value = ("SC", 1) - mock_wait.return_value = (True, True, {}) # scan completed + mock_workbench.ensure_scan_is_idle.return_value = None # scan completed successfully mock_workbench.get_pending_files.return_value = {"1": "/file/a"} mock_workbench.get_policy_warnings_counter.return_value = { "policy_warnings_total": 0, @@ -73,8 +72,7 @@ def test_handle_evaluate_gates_fail_pending(self, mock_wait, mock_workbench, moc result = handle_evaluate_gates(mock_workbench, mock_params) assert result is False # Should FAIL because of pending files - @patch('workbench_cli.handlers.evaluate_gates.wait_for_scan_completion') - def test_handle_evaluate_gates_fail_policy(self, mock_wait, mock_workbench, mock_params): + def test_handle_evaluate_gates_fail_policy(self, mock_workbench, mock_params): """Test failing gate check due to policy violations.""" mock_params.command = 'evaluate-gates' mock_params.project_name = "P" @@ -87,7 +85,7 @@ def test_handle_evaluate_gates_fail_policy(self, mock_wait, mock_workbench, mock # Setup mocks mock_workbench.resolve_project.return_value = "PC" mock_workbench.resolve_scan.return_value = ("SC", 1) - mock_wait.return_value = (True, True, {}) # scan completed + mock_workbench.ensure_scan_is_idle.return_value = None # scan completed successfully mock_workbench.get_pending_files.return_value = {} mock_workbench.get_policy_warnings_counter.return_value = { "policy_warnings_total": 5, @@ -100,8 +98,7 @@ def test_handle_evaluate_gates_fail_policy(self, mock_wait, mock_workbench, mock result = handle_evaluate_gates(mock_workbench, mock_params) assert result is False # Should FAIL because of policy violations - @patch('workbench_cli.handlers.evaluate_gates.wait_for_scan_completion') - def test_handle_evaluate_gates_fail_vulnerabilities(self, mock_wait, mock_workbench, mock_params): + def test_handle_evaluate_gates_fail_vulnerabilities(self, mock_workbench, mock_params): """Test failing gate check due to vulnerabilities.""" mock_params.command = 'evaluate-gates' mock_params.project_name = "P" @@ -114,7 +111,7 @@ def test_handle_evaluate_gates_fail_vulnerabilities(self, mock_wait, mock_workbe # Setup mocks mock_workbench.resolve_project.return_value = "PC" mock_workbench.resolve_scan.return_value = ("SC", 1) - mock_wait.return_value = (True, True, {}) # scan completed + mock_workbench.ensure_scan_is_idle.return_value = None # scan completed successfully mock_workbench.get_pending_files.return_value = {} mock_workbench.get_policy_warnings_counter.return_value = { "policy_warnings_total": 0, @@ -130,8 +127,7 @@ def test_handle_evaluate_gates_fail_vulnerabilities(self, mock_wait, mock_workbe result = handle_evaluate_gates(mock_workbench, mock_params) assert result is False # Should FAIL because of high severity vulnerabilities - @patch('workbench_cli.handlers.evaluate_gates.wait_for_scan_completion') - def test_handle_evaluate_gates_pass_low_vulnerabilities(self, mock_wait, mock_workbench, mock_params): + def test_handle_evaluate_gates_pass_low_vulnerabilities(self, mock_workbench, mock_params): """Test passing gate check with only low severity vulnerabilities.""" mock_params.command = 'evaluate-gates' mock_params.project_name = "P" @@ -144,7 +140,7 @@ def test_handle_evaluate_gates_pass_low_vulnerabilities(self, mock_wait, mock_wo # Setup mocks mock_workbench.resolve_project.return_value = "PC" mock_workbench.resolve_scan.return_value = ("SC", 1) - mock_wait.return_value = (True, True, {}) # scan completed + mock_workbench.ensure_scan_is_idle.return_value = None # scan completed successfully mock_workbench.get_pending_files.return_value = {} mock_workbench.get_policy_warnings_counter.return_value = { "policy_warnings_total": 0, @@ -160,8 +156,7 @@ def test_handle_evaluate_gates_pass_low_vulnerabilities(self, mock_wait, mock_wo result = handle_evaluate_gates(mock_workbench, mock_params) assert result is True # Should PASS with only medium/low vulnerabilities - @patch('workbench_cli.handlers.evaluate_gates.wait_for_scan_completion') - def test_handle_evaluate_gates_warn_vulnerabilities_no_fail_flag(self, mock_wait, mock_workbench, mock_params): + def test_handle_evaluate_gates_warn_vulnerabilities_no_fail_flag(self, mock_workbench, mock_params): """Test gate passes with vulnerabilities when no fail flag is set.""" mock_params.command = 'evaluate-gates' mock_params.project_name = "P" @@ -174,7 +169,7 @@ def test_handle_evaluate_gates_warn_vulnerabilities_no_fail_flag(self, mock_wait # Setup mocks mock_workbench.resolve_project.return_value = "PC" mock_workbench.resolve_scan.return_value = ("SC", 1) - mock_wait.return_value = (True, True, {}) # scan completed + mock_workbench.ensure_scan_is_idle.return_value = None # scan completed successfully mock_workbench.get_pending_files.return_value = {} mock_workbench.get_policy_warnings_counter.return_value = { "policy_warnings_total": 0, @@ -190,8 +185,7 @@ def test_handle_evaluate_gates_warn_vulnerabilities_no_fail_flag(self, mock_wait result = handle_evaluate_gates(mock_workbench, mock_params) assert result is True # Should PASS despite vulnerabilities when no fail flag - @patch('workbench_cli.handlers.evaluate_gates.wait_for_scan_completion') - def test_handle_evaluate_gates_scan_not_completed(self, mock_wait, mock_workbench, mock_params): + def test_handle_evaluate_gates_scan_not_completed(self, mock_workbench, mock_params): """Test gate fails when scan has not completed.""" mock_params.command = 'evaluate-gates' mock_params.project_name = "P" @@ -203,14 +197,13 @@ def test_handle_evaluate_gates_scan_not_completed(self, mock_wait, mock_workbenc # Setup mocks mock_workbench.resolve_project.return_value = "PC" mock_workbench.resolve_scan.return_value = ("SC", 1) - mock_wait.return_value = (False, False, {}) # scan NOT completed + mock_workbench.ensure_scan_is_idle.side_effect = ProcessTimeoutError("Scan not completed") # scan NOT completed # Run handler result = handle_evaluate_gates(mock_workbench, mock_params) assert result is False # Should FAIL when scan not completed - @patch('workbench_cli.handlers.evaluate_gates.wait_for_scan_completion') - def test_handle_evaluate_gates_api_error_pending(self, mock_wait, mock_workbench, mock_params): + def test_handle_evaluate_gates_api_error_pending(self, mock_workbench, mock_params): """Test handling of ApiError from get_pending_files.""" mock_params.command = 'evaluate-gates' mock_params.project_name = "P" @@ -223,7 +216,7 @@ def test_handle_evaluate_gates_api_error_pending(self, mock_wait, mock_workbench # Setup mocks mock_workbench.resolve_project.return_value = "PC" mock_workbench.resolve_scan.return_value = ("SC", 1) - mock_wait.return_value = (True, True, {}) # scan completed + mock_workbench.ensure_scan_is_idle.return_value = None # scan completed successfully mock_workbench.get_pending_files.side_effect = ApiError("API Error") mock_workbench.get_policy_warnings_counter.return_value = { "policy_warnings_total": 0, @@ -236,8 +229,7 @@ def test_handle_evaluate_gates_api_error_pending(self, mock_wait, mock_workbench result = handle_evaluate_gates(mock_workbench, mock_params) assert result is False # Should FAIL due to API error when fail_on_pending is True - @patch('workbench_cli.handlers.evaluate_gates.wait_for_scan_completion') - def test_handle_evaluate_gates_api_error_policy(self, mock_wait, mock_workbench, mock_params): + def test_handle_evaluate_gates_api_error_policy(self, mock_workbench, mock_params): """Test handling of ApiError from get_policy_warnings_counter.""" mock_params.command = 'evaluate-gates' mock_params.project_name = "P" @@ -250,7 +242,7 @@ def test_handle_evaluate_gates_api_error_policy(self, mock_wait, mock_workbench, # Setup mocks mock_workbench.resolve_project.return_value = "PC" mock_workbench.resolve_scan.return_value = ("SC", 1) - mock_wait.return_value = (True, True, {}) # scan completed + mock_workbench.ensure_scan_is_idle.return_value = None # scan completed successfully mock_workbench.get_pending_files.return_value = {} mock_workbench.get_policy_warnings_counter.side_effect = ApiError("Policy API Error") mock_workbench.list_vulnerabilities.return_value = [] @@ -259,8 +251,7 @@ def test_handle_evaluate_gates_api_error_policy(self, mock_wait, mock_workbench, result = handle_evaluate_gates(mock_workbench, mock_params) assert result is False # Should FAIL due to API error when fail_on_policy is True - @patch('workbench_cli.handlers.evaluate_gates.wait_for_scan_completion') - def test_handle_evaluate_gates_api_error_vulnerabilities(self, mock_wait, mock_workbench, mock_params): + def test_handle_evaluate_gates_api_error_vulnerabilities(self, mock_workbench, mock_params): """Test handling of ApiError from list_vulnerabilities.""" mock_params.command = 'evaluate-gates' mock_params.project_name = "P" @@ -273,7 +264,7 @@ def test_handle_evaluate_gates_api_error_vulnerabilities(self, mock_wait, mock_w # Setup mocks mock_workbench.resolve_project.return_value = "PC" mock_workbench.resolve_scan.return_value = ("SC", 1) - mock_wait.return_value = (True, True, {}) # scan completed + mock_workbench.ensure_scan_is_idle.return_value = None # scan completed successfully mock_workbench.get_pending_files.return_value = {} mock_workbench.get_policy_warnings_counter.return_value = { "policy_warnings_total": 0, @@ -308,8 +299,7 @@ def test_handle_evaluate_gates_scan_resolve_fails(self, mock_workbench, mock_par with pytest.raises(ScanNotFoundError): handle_evaluate_gates(mock_workbench, mock_params) - @patch('workbench_cli.handlers.evaluate_gates.wait_for_scan_completion') - def test_handle_evaluate_gates_show_pending_files(self, mock_wait, mock_workbench, mock_params): + def test_handle_evaluate_gates_show_pending_files(self, mock_workbench, mock_params): """Test showing pending files when requested.""" mock_params.command = 'evaluate-gates' mock_params.project_name = "P" @@ -322,7 +312,7 @@ def test_handle_evaluate_gates_show_pending_files(self, mock_wait, mock_workbenc # Setup mocks mock_workbench.resolve_project.return_value = "PC" mock_workbench.resolve_scan.return_value = ("SC", 1) - mock_wait.return_value = (True, True, {}) # scan completed + mock_workbench.ensure_scan_is_idle.return_value = None # scan completed successfully mock_workbench.get_pending_files.return_value = { "1": "/file/a.py", "2": "/file/b.py", @@ -339,8 +329,7 @@ def test_handle_evaluate_gates_show_pending_files(self, mock_wait, mock_workbenc result = handle_evaluate_gates(mock_workbench, mock_params) assert result is True # Should PASS when not failing on pending files - @patch('workbench_cli.handlers.evaluate_gates.wait_for_scan_completion') - def test_handle_evaluate_gates_policy_data_format_nested(self, mock_wait, mock_workbench, mock_params): + def test_handle_evaluate_gates_policy_data_format_nested(self, mock_workbench, mock_params): """Test handling of nested policy data format.""" mock_params.command = 'evaluate-gates' mock_params.project_name = "P" @@ -353,7 +342,7 @@ def test_handle_evaluate_gates_policy_data_format_nested(self, mock_wait, mock_w # Setup mocks mock_workbench.resolve_project.return_value = "PC" mock_workbench.resolve_scan.return_value = ("SC", 1) - mock_wait.return_value = (True, True, {}) # scan completed + mock_workbench.ensure_scan_is_idle.return_value = None # scan completed successfully mock_workbench.get_pending_files.return_value = {} # Test nested data format mock_workbench.get_policy_warnings_counter.return_value = { diff --git a/tests/unit/handlers/test_import_da.py b/tests/unit/handlers/test_import_da.py index 815f89b..0a0e3cd 100644 --- a/tests/unit/handlers/test_import_da.py +++ b/tests/unit/handlers/test_import_da.py @@ -26,10 +26,9 @@ class TestImportDAHandler: @patch('workbench_cli.handlers.import_da.fetch_display_save_results') @patch('workbench_cli.handlers.import_da.print_operation_summary') @patch('workbench_cli.handlers.import_da.ensure_scan_compatibility') - @patch('workbench_cli.handlers.import_da.assert_scan_is_idle') @patch('os.path.exists', return_value=True) @patch('os.path.isfile', return_value=True) - def test_handle_import_da_success(self, mock_isfile, mock_exists, mock_assert_idle, + def test_handle_import_da_success(self, mock_isfile, mock_exists, mock_ensure_compat, mock_print_summary, mock_fetch, mock_workbench, mock_params): """Tests the successful execution of handle_import_da.""" @@ -58,8 +57,8 @@ def test_handle_import_da_success(self, mock_isfile, mock_exists, mock_assert_id mock_workbench.upload_dependency_analysis_results.assert_called_once_with( scan_code="TEST_SCAN_CODE", path="/path/to/results.json" ) - mock_workbench.ensure_process_can_start.assert_called_once_with( - "DEPENDENCY_ANALYSIS", "TEST_SCAN_CODE", wait_max_tries=10, wait_interval=5 + mock_workbench.ensure_scan_is_idle.assert_called_once_with( + "TEST_SCAN_CODE", mock_params, ["DEPENDENCY_ANALYSIS"] ) mock_workbench.start_dependency_analysis.assert_called_once_with( scan_code="TEST_SCAN_CODE", import_only=True @@ -72,10 +71,9 @@ def test_handle_import_da_success(self, mock_isfile, mock_exists, mock_assert_id @patch('workbench_cli.handlers.import_da.print_operation_summary') @patch('workbench_cli.handlers.import_da.ensure_scan_compatibility') - @patch('workbench_cli.handlers.import_da.assert_scan_is_idle') @patch('os.path.exists', return_value=True) @patch('os.path.isfile', return_value=True) - def test_handle_import_da_no_wait(self, mock_isfile, mock_exists, mock_assert_idle, + def test_handle_import_da_no_wait(self, mock_isfile, mock_exists, mock_ensure_compat, mock_print_summary, mock_workbench, mock_params): """Tests the execution of handle_import_da with no wait.""" @@ -182,10 +180,9 @@ def test_handle_import_da_path_not_file(self, mock_isfile, mock_exists, side_effect=ApiError("Error fetching results")) @patch('workbench_cli.handlers.import_da.print_operation_summary') @patch('workbench_cli.handlers.import_da.ensure_scan_compatibility') - @patch('workbench_cli.handlers.import_da.assert_scan_is_idle') @patch('os.path.exists', return_value=True) @patch('os.path.isfile', return_value=True) - def test_handle_import_da_fetch_api_error(self, mock_isfile, mock_exists, mock_assert_idle, + def test_handle_import_da_fetch_api_error(self, mock_isfile, mock_exists, mock_ensure_compat, mock_print_summary, mock_fetch, mock_workbench, mock_params): """Tests handling of ApiError from fetch_display_save_results.""" diff --git a/tests/unit/handlers/test_import_sbom.py b/tests/unit/handlers/test_import_sbom.py new file mode 100644 index 0000000..c49b944 --- /dev/null +++ b/tests/unit/handlers/test_import_sbom.py @@ -0,0 +1,333 @@ +# tests/unit/handlers/test_import_sbom.py + +import pytest +import os +from unittest.mock import MagicMock, patch, call + +from workbench_cli.handlers.import_sbom import handle_import_sbom, _get_project_and_scan_codes, _validate_sbom_file +from workbench_cli.exceptions import ( + ProjectNotFoundError, + ScanNotFoundError, + FileSystemError, + ValidationError, + ApiError, + NetworkError, + WorkbenchCLIError, + ProcessError, + ProcessTimeoutError, + CompatibilityError +) + + +class TestImportSBOMHandler: + """Test cases for the import-sbom handler.""" + + @patch('workbench_cli.handlers.import_sbom.fetch_display_save_results') + @patch('workbench_cli.handlers.import_sbom.print_operation_summary') + @patch('workbench_cli.handlers.import_sbom.ensure_scan_compatibility') + @patch('workbench_cli.handlers.import_sbom._validate_sbom_file') + @patch('os.path.exists', return_value=True) + @patch('os.path.isfile', return_value=True) + def test_handle_import_sbom_success(self, mock_isfile, mock_exists, mock_validate_sbom, + mock_ensure_compat, mock_print_summary, + mock_fetch, mock_workbench, mock_params): + """Tests the successful execution of handle_import_sbom.""" + # Configure params + mock_params.command = 'import-sbom' + mock_params.project_name = "SBOMProj" + mock_params.scan_name = "SBOMScan" + mock_params.path = "/path/to/sbom.json" + mock_params.scan_number_of_tries = 10 + mock_params.scan_wait_time = 5 + + # Configure mocks + mock_validate_sbom.return_value = ('cyclonedx', '1.6', {'components_count': 42}, {}) + mock_workbench.resolve_project.return_value = 'TEST_PROJ_CODE' + mock_workbench.resolve_scan.return_value = ('TEST_SCAN_CODE', 123) + mock_workbench.wait_for_scan_to_finish.return_value = ({}, 5.0) + + # Execute the handler + result = handle_import_sbom(mock_workbench, mock_params) + + # Verify the result and expected calls + assert result is True + mock_validate_sbom.assert_called_once_with("/path/to/sbom.json") + mock_workbench.resolve_project.assert_called_once_with("SBOMProj", create_if_missing=True) + mock_workbench.resolve_scan.assert_called_once_with("SBOMScan", "SBOMProj", + create_if_missing=True, params=mock_params, + import_from_report=True) + mock_ensure_compat.assert_called_once_with(mock_workbench, mock_params, "TEST_SCAN_CODE") + mock_workbench.ensure_scan_is_idle.assert_called_once_with("TEST_SCAN_CODE", mock_params, ["REPORT_IMPORT"]) + mock_workbench.upload_sbom_file.assert_called_once_with( + scan_code="TEST_SCAN_CODE", path="/path/to/sbom.json" + ) + mock_workbench.import_report.assert_called_once_with(scan_code="TEST_SCAN_CODE") + mock_workbench.wait_for_scan_to_finish.assert_called_once_with( + "REPORT_IMPORT", "TEST_SCAN_CODE", 10, 2 + ) + mock_fetch.assert_called_once() + mock_print_summary.assert_called_once() + + @patch('os.path.exists', return_value=False) + def test_handle_import_sbom_path_not_exists(self, mock_exists, mock_workbench, mock_params): + """Tests file system error when path doesn't exist.""" + # Configure params + mock_params.command = 'import-sbom' + mock_params.path = "/nonexistent/path" + + # Execute and verify exception + with pytest.raises(FileSystemError, match="does not exist"): + handle_import_sbom(mock_workbench, mock_params) + + @patch('workbench_cli.handlers.import_sbom._validate_sbom_file') + @patch('os.path.exists', return_value=True) + @patch('os.path.isfile', return_value=True) + def test_handle_import_sbom_scan_not_found(self, mock_isfile, mock_exists, mock_validate_sbom, + mock_workbench, mock_params): + """Tests the execution of handle_import_sbom with a scan not found.""" + # Configure params + mock_params.command = 'import-sbom' + mock_params.project_name = "SBOMProj" + mock_params.scan_name = "SBOMScan" + mock_params.path = "/path/to/sbom.json" + mock_params.scan_number_of_tries = 10 + mock_params.scan_wait_time = 5 + + # Configure mocks + mock_validate_sbom.return_value = ('cyclonedx', '1.5', {}, {}) + mock_workbench.resolve_project.return_value = 'TEST_PROJ_CODE' + mock_workbench.resolve_scan.side_effect = ScanNotFoundError("Scan not found") + + # Execute and verify exception + with pytest.raises(ScanNotFoundError): + handle_import_sbom(mock_workbench, mock_params) + + @patch('workbench_cli.handlers.import_sbom._validate_sbom_file') + @patch('os.path.exists', return_value=True) + @patch('os.path.isfile', return_value=True) + def test_handle_import_sbom_project_not_found(self, mock_isfile, mock_exists, mock_validate_sbom, + mock_workbench, mock_params): + """Tests the execution of handle_import_sbom with a project not found.""" + # Configure params + mock_params.command = 'import-sbom' + mock_params.project_name = "NonExistent" + mock_params.scan_name = "SBOMScan" + mock_params.path = "/path/to/sbom.json" + + # Configure mocks + mock_validate_sbom.return_value = ('cyclonedx', '1.4', {}, {}) + mock_workbench.resolve_project.side_effect = ProjectNotFoundError("Project not found") + + # Execute and verify exception + with pytest.raises(ProjectNotFoundError): + handle_import_sbom(mock_workbench, mock_params) + + @patch('os.path.exists', return_value=False) + def test_handle_import_sbom_path_not_exists(self, mock_exists, mock_workbench, mock_params): + """Tests file system error when path doesn't exist.""" + # Configure params + mock_params.command = 'import-sbom' + mock_params.path = "/nonexistent/path" + + # Execute and verify exception + with pytest.raises(FileSystemError, match="does not exist"): + handle_import_sbom(mock_workbench, mock_params) + + @patch('os.path.exists', return_value=True) + @patch('os.path.isfile', return_value=False) + def test_handle_import_sbom_path_not_file(self, mock_isfile, mock_exists, + mock_workbench, mock_params): + """Tests validation error when path is not a file.""" + # Configure params + mock_params.command = 'import-sbom' + mock_params.path = "/path/to/directory" + + # Execute and verify exception + with pytest.raises(ValidationError, match="must be a file"): + handle_import_sbom(mock_workbench, mock_params) + + @patch('workbench_cli.handlers.import_sbom._validate_sbom_file', + side_effect=ValidationError("Invalid SBOM format")) + @patch('os.path.exists', return_value=True) + @patch('os.path.isfile', return_value=True) + def test_handle_import_sbom_validation_error(self, mock_isfile, mock_exists, mock_validate_sbom, + mock_workbench, mock_params): + """Tests handling of SBOM validation error.""" + # Configure params + mock_params.command = 'import-sbom' + mock_params.path = "/path/to/invalid.json" + + # Execute and verify exception + with pytest.raises(ValidationError, match="Invalid SBOM format"): + handle_import_sbom(mock_workbench, mock_params) + + @patch('workbench_cli.handlers.import_sbom.fetch_display_save_results', + side_effect=ApiError("Error fetching results")) + @patch('workbench_cli.handlers.import_sbom.print_operation_summary') + @patch('workbench_cli.handlers.import_sbom.ensure_scan_compatibility') + @patch('workbench_cli.handlers.import_sbom._validate_sbom_file') + @patch('os.path.exists', return_value=True) + @patch('os.path.isfile', return_value=True) + def test_handle_import_sbom_fetch_api_error(self, mock_isfile, mock_exists, mock_validate_sbom, + mock_ensure_compat, mock_print_summary, + mock_fetch, mock_workbench, mock_params): + """Tests handling of ApiError from fetch_display_save_results (should not fail the whole operation).""" + # Configure params + mock_params.command = 'import-sbom' + mock_params.path = "/path/to/sbom.json" + + mock_spdx_doc = MagicMock() + mock_spdx_doc.creation_info = MagicMock() + mock_spdx_doc.files = [] + mock_spdx_doc.packages = [] + mock_spdx_doc.snippets = [] + mock_spdx_doc.extracted_licensing_info = [] + + mock_validate_sbom.return_value = ('spdx', '2.3', {}, mock_spdx_doc) + mock_workbench.resolve_project.return_value = 'TEST_PROJ_CODE' + mock_workbench.resolve_scan.return_value = ('TEST_SCAN_CODE', 123) + mock_workbench.wait_for_scan_to_finish.return_value = ({}, 5.0) + + result = handle_import_sbom(mock_workbench, mock_params) + + assert result is True + mock_fetch.assert_called_once() + + @patch('workbench_cli.handlers.import_sbom.print_operation_summary') + @patch('workbench_cli.handlers.import_sbom.ensure_scan_compatibility') + @patch('workbench_cli.handlers.import_sbom._validate_sbom_file') + @patch('os.path.exists', return_value=True) + @patch('os.path.isfile', return_value=True) + def test_handle_import_sbom_upload_error(self, mock_isfile, mock_exists, mock_validate_sbom, + mock_ensure_compat, mock_print_summary, + mock_workbench, mock_params): + """Tests handling of upload error.""" + # Configure params + mock_params.command = 'import-sbom' + mock_params.path = "/path/to/sbom.json" + + mock_spdx_doc = MagicMock() + mock_spdx_doc.creation_info = MagicMock() + mock_spdx_doc.files = [] + mock_spdx_doc.packages = [] + mock_spdx_doc.snippets = [] + mock_spdx_doc.extracted_licensing_info = [] + + mock_validate_sbom.return_value = ('spdx', '2.2', {}, mock_spdx_doc) + mock_workbench.resolve_project.return_value = 'TEST_PROJ_CODE' + mock_workbench.resolve_scan.return_value = ('TEST_SCAN_CODE', 123) + mock_workbench.upload_sbom_file.side_effect = ApiError("Upload failed") + + with pytest.raises(WorkbenchCLIError, match="Failed to upload SBOM file"): + handle_import_sbom(mock_workbench, mock_params) + + @patch('workbench_cli.handlers.import_sbom.print_operation_summary') + @patch('workbench_cli.handlers.import_sbom.ensure_scan_compatibility') + @patch('workbench_cli.handlers.import_sbom._validate_sbom_file') + @patch('os.path.exists', return_value=True) + @patch('os.path.isfile', return_value=True) + def test_handle_import_sbom_import_error(self, mock_isfile, mock_exists, mock_validate_sbom, + mock_ensure_compat, mock_print_summary, + mock_workbench, mock_params): + """Tests handling of import_report error.""" + # Configure params + mock_params.command = 'import-sbom' + mock_params.path = "/path/to/sbom.json" + mock_validate_sbom.return_value = ('cyclonedx', '1.5', {}, {}) + mock_workbench.resolve_project.return_value = 'TEST_PROJ_CODE' + mock_workbench.resolve_scan.return_value = ('TEST_SCAN_CODE', 123) + mock_workbench.import_report.side_effect = ApiError("Import failed") + + with pytest.raises(WorkbenchCLIError, match="Failed to start SBOM import"): + handle_import_sbom(mock_workbench, mock_params) + + @patch('workbench_cli.handlers.import_sbom.print_operation_summary') + @patch('workbench_cli.handlers.import_sbom.ensure_scan_compatibility') + @patch('workbench_cli.handlers.import_sbom._validate_sbom_file') + @patch('os.path.exists', return_value=True) + @patch('os.path.isfile', return_value=True) + def test_handle_import_sbom_timeout_error(self, mock_isfile, mock_exists, mock_validate_sbom, + mock_ensure_compat, mock_print_summary, + mock_workbench, mock_params): + """Tests handling of timeout during SBOM import.""" + # Configure params + mock_params.command = 'import-sbom' + mock_params.path = "/path/to/sbom.json" + mock_validate_sbom.return_value = ('cyclonedx', '1.4', {}, {}) + mock_workbench.resolve_project.return_value = 'TEST_PROJ_CODE' + mock_workbench.resolve_scan.return_value = ('TEST_SCAN_CODE', 123) + mock_workbench.wait_for_scan_to_finish.side_effect = ProcessTimeoutError("Timed out") + + with pytest.raises(ProcessTimeoutError, match="Timed out"): + handle_import_sbom(mock_workbench, mock_params) + + +class TestValidateSBOMFile: + """Test cases for the _validate_sbom_file function.""" + + @patch('workbench_cli.handlers.import_sbom.SBOMValidator.validate_sbom_file') + def test_validate_sbom_file_success(self, mock_validator): + """Tests successful SBOM validation.""" + mock_validator.return_value = ('cyclonedx', '1.6', {'components_count': 42}, {'doc': 'content'}) + + result = _validate_sbom_file('/path/to/sbom.json') + + assert result == ('cyclonedx', '1.6', {'components_count': 42}, {'doc': 'content'}) + mock_validator.assert_called_once_with('/path/to/sbom.json') + + @patch('workbench_cli.handlers.import_sbom.SBOMValidator.validate_sbom_file') + def test_validate_sbom_file_validation_error(self, mock_validator): + """Tests SBOM validation error.""" + mock_validator.side_effect = ValidationError("Invalid format") + + with pytest.raises(ValidationError, match="Invalid format"): + _validate_sbom_file('/path/to/invalid.json') + + @patch('workbench_cli.handlers.import_sbom.SBOMValidator.validate_sbom_file') + def test_validate_sbom_file_unexpected_error(self, mock_validator): + """Tests unexpected error during SBOM validation.""" + mock_validator.side_effect = Exception("Unexpected error") + + with pytest.raises(Exception, match="Unexpected error"): + _validate_sbom_file('/path/to/sbom.json') + + +class TestGetProjectAndScanCodes: + """Test cases for the _get_project_and_scan_codes function.""" + + def test_get_project_and_scan_codes_success(self, mock_workbench, mock_params): + """Tests successful project and scan code resolution.""" + mock_params.project_name = "TestProject" + mock_params.scan_name = "TestScan" + + mock_workbench.resolve_project.return_value = 'PROJ_CODE' + mock_workbench.resolve_scan.return_value = ('SCAN_CODE', 123) + + project_code, scan_code = _get_project_and_scan_codes(mock_workbench, mock_params) + + assert project_code == 'PROJ_CODE' + assert scan_code == 'SCAN_CODE' + mock_workbench.resolve_project.assert_called_once_with("TestProject", create_if_missing=True) + mock_workbench.resolve_scan.assert_called_once_with( + "TestScan", "TestProject", create_if_missing=True, + params=mock_params, import_from_report=True + ) + + def test_get_project_and_scan_codes_project_error(self, mock_workbench, mock_params): + """Tests project resolution error.""" + mock_params.project_name = "NonExistent" + mock_workbench.resolve_project.side_effect = ProjectNotFoundError("Project not found") + + with pytest.raises(ProjectNotFoundError): + _get_project_and_scan_codes(mock_workbench, mock_params) + + def test_get_project_and_scan_codes_scan_error(self, mock_workbench, mock_params): + """Tests scan resolution error.""" + mock_params.project_name = "TestProject" + mock_params.scan_name = "TestScan" + + mock_workbench.resolve_project.return_value = 'PROJ_CODE' + mock_workbench.resolve_scan.side_effect = ScanNotFoundError("Scan not found") + + with pytest.raises(ScanNotFoundError): + _get_project_and_scan_codes(mock_workbench, mock_params) \ No newline at end of file diff --git a/tests/unit/handlers/test_scan_git.py b/tests/unit/handlers/test_scan_git.py index 266ab3c..c690f05 100644 --- a/tests/unit/handlers/test_scan_git.py +++ b/tests/unit/handlers/test_scan_git.py @@ -26,9 +26,8 @@ class TestScanGitHandler: @patch('workbench_cli.handlers.scan_git.fetch_display_save_results') @patch('workbench_cli.handlers.scan_git.print_operation_summary') @patch('workbench_cli.handlers.scan_git.determine_scans_to_run') - @patch('workbench_cli.handlers.scan_git.assert_scan_is_idle') @patch('workbench_cli.handlers.scan_git.ensure_scan_compatibility') - def test_handle_scan_git_success_full_scan(self, mock_ensure_compat, mock_assert_idle, + def test_handle_scan_git_success_full_scan(self, mock_ensure_compat, mock_determine_scans, mock_print_summary, mock_fetch, mock_workbench, mock_params): """Tests successful git scan with both KB scan and dependency analysis.""" @@ -76,9 +75,8 @@ def test_handle_scan_git_success_full_scan(self, mock_ensure_compat, mock_assert @patch('workbench_cli.handlers.scan_git.print_operation_summary') @patch('workbench_cli.handlers.scan_git.determine_scans_to_run') - @patch('workbench_cli.handlers.scan_git.assert_scan_is_idle') @patch('workbench_cli.handlers.scan_git.ensure_scan_compatibility') - def test_handle_scan_git_no_wait(self, mock_ensure_compat, mock_assert_idle, + def test_handle_scan_git_no_wait(self, mock_ensure_compat, mock_determine_scans, mock_print_summary, mock_workbench, mock_params): """Tests git scan with no-wait mode.""" @@ -117,9 +115,8 @@ def test_handle_scan_git_no_wait(self, mock_ensure_compat, mock_assert_idle, @patch('workbench_cli.handlers.scan_git.fetch_display_save_results') @patch('workbench_cli.handlers.scan_git.print_operation_summary') @patch('workbench_cli.handlers.scan_git.determine_scans_to_run') - @patch('workbench_cli.handlers.scan_git.assert_scan_is_idle') @patch('workbench_cli.handlers.scan_git.ensure_scan_compatibility') - def test_handle_scan_git_dependency_analysis_only(self, mock_ensure_compat, mock_assert_idle, + def test_handle_scan_git_dependency_analysis_only(self, mock_ensure_compat, mock_determine_scans, mock_print_summary, mock_fetch, mock_workbench, mock_params): """Tests git scan with dependency analysis only.""" @@ -161,9 +158,8 @@ def test_handle_scan_git_dependency_analysis_only(self, mock_ensure_compat, mock @patch('workbench_cli.handlers.scan_git.print_operation_summary') @patch('workbench_cli.handlers.scan_git.determine_scans_to_run') - @patch('workbench_cli.handlers.scan_git.assert_scan_is_idle') @patch('workbench_cli.handlers.scan_git.ensure_scan_compatibility') - def test_handle_scan_git_dependency_analysis_only_no_wait(self, mock_ensure_compat, mock_assert_idle, + def test_handle_scan_git_dependency_analysis_only_no_wait(self, mock_ensure_compat, mock_determine_scans, mock_print_summary, mock_workbench, mock_params): """Tests git scan with dependency analysis only and no-wait mode.""" @@ -201,9 +197,8 @@ def test_handle_scan_git_dependency_analysis_only_no_wait(self, mock_ensure_comp @patch('workbench_cli.handlers.scan_git.validate_reuse_source') @patch('workbench_cli.handlers.scan_git.print_operation_summary') @patch('workbench_cli.handlers.scan_git.determine_scans_to_run') - @patch('workbench_cli.handlers.scan_git.assert_scan_is_idle') @patch('workbench_cli.handlers.scan_git.ensure_scan_compatibility') - def test_handle_scan_git_with_id_reuse(self, mock_ensure_compat, mock_assert_idle, + def test_handle_scan_git_with_id_reuse(self, mock_ensure_compat, mock_determine_scans, mock_print_summary, mock_validate_reuse, mock_workbench, mock_params): """Tests git scan with ID reuse enabled.""" @@ -247,9 +242,8 @@ def test_handle_scan_git_with_id_reuse(self, mock_ensure_compat, mock_assert_idl @patch('workbench_cli.handlers.scan_git.validate_reuse_source') @patch('workbench_cli.handlers.scan_git.determine_scans_to_run') - @patch('workbench_cli.handlers.scan_git.assert_scan_is_idle') @patch('workbench_cli.handlers.scan_git.ensure_scan_compatibility') - def test_handle_scan_git_id_reuse_validation_fails(self, mock_ensure_compat, mock_assert_idle, + def test_handle_scan_git_id_reuse_validation_fails(self, mock_ensure_compat, mock_determine_scans, mock_validate_reuse, mock_workbench, mock_params): """Tests git scan when ID reuse validation fails.""" @@ -288,9 +282,8 @@ def test_handle_scan_git_id_reuse_validation_fails(self, mock_ensure_compat, moc args = call_args[0] assert args[7] is False # ID reuse should be disabled (7th index) - @patch('workbench_cli.handlers.scan_git.assert_scan_is_idle') @patch('workbench_cli.handlers.scan_git.ensure_scan_compatibility') - def test_handle_scan_git_git_clone_fails(self, mock_ensure_compat, mock_assert_idle, + def test_handle_scan_git_git_clone_fails(self, mock_ensure_compat, mock_workbench, mock_params): """Tests git scan when git clone fails.""" # Configure params @@ -310,9 +303,8 @@ def test_handle_scan_git_git_clone_fails(self, mock_ensure_compat, mock_assert_i with pytest.raises(WorkbenchCLIError, match="Failed to clone Git repository"): handle_scan_git(mock_workbench, mock_params) - @patch('workbench_cli.handlers.scan_git.assert_scan_is_idle') @patch('workbench_cli.handlers.scan_git.ensure_scan_compatibility') - def test_handle_scan_git_project_not_found(self, mock_ensure_compat, mock_assert_idle, + def test_handle_scan_git_project_not_found(self, mock_ensure_compat, mock_workbench, mock_params): """Tests git scan when project resolution fails.""" # Configure params @@ -331,9 +323,8 @@ def test_handle_scan_git_project_not_found(self, mock_ensure_compat, mock_assert @patch('workbench_cli.handlers.scan_git.fetch_display_save_results') @patch('workbench_cli.handlers.scan_git.print_operation_summary') @patch('workbench_cli.handlers.scan_git.determine_scans_to_run') - @patch('workbench_cli.handlers.scan_git.assert_scan_is_idle') @patch('workbench_cli.handlers.scan_git.ensure_scan_compatibility') - def test_handle_scan_git_remove_git_dir_fails(self, mock_ensure_compat, mock_assert_idle, + def test_handle_scan_git_remove_git_dir_fails(self, mock_ensure_compat, mock_determine_scans, mock_print_summary, mock_fetch, mock_workbench, mock_params): """Tests git scan when removing .git directory fails.""" @@ -370,9 +361,8 @@ def test_handle_scan_git_remove_git_dir_fails(self, mock_ensure_compat, mock_ass @patch('workbench_cli.handlers.scan_git.fetch_display_save_results') @patch('workbench_cli.handlers.scan_git.print_operation_summary') @patch('workbench_cli.handlers.scan_git.determine_scans_to_run') - @patch('workbench_cli.handlers.scan_git.assert_scan_is_idle') @patch('workbench_cli.handlers.scan_git.ensure_scan_compatibility') - def test_handle_scan_git_kb_scan_timeout(self, mock_ensure_compat, mock_assert_idle, + def test_handle_scan_git_kb_scan_timeout(self, mock_ensure_compat, mock_determine_scans, mock_print_summary, mock_fetch, mock_workbench, mock_params): """Tests git scan when KB scan times out.""" diff --git a/tests/unit/utilities/test_sbom_validator.py b/tests/unit/utilities/test_sbom_validator.py new file mode 100644 index 0000000..36e0788 --- /dev/null +++ b/tests/unit/utilities/test_sbom_validator.py @@ -0,0 +1,339 @@ +# tests/unit/utilities/test_sbom_validator.py + +import pytest +import json +import tempfile +import os +from unittest.mock import patch, MagicMock, mock_open +from pathlib import Path +import importlib +import sys + +from workbench_cli.utilities.sbom_validator import SBOMValidator +from workbench_cli.exceptions import ValidationError, FileSystemError + +# Fixtures to provide paths to test SBOM files +@pytest.fixture +def cyclonedx_sbom_path(): + return os.path.join(os.path.dirname(__file__), '..', '..', 'fixtures', 'cyclonedx-bom.json') + +@pytest.fixture +def spdx_sbom_path(): + return os.path.join(os.path.dirname(__file__), '..', '..', 'fixtures', 'spdx-document.rdf') + + +class TestSBOMValidatorWithFixtures: + """Test cases using real SBOM files.""" + + def test_validate_cyclonedx_from_file(self, cyclonedx_sbom_path): + """Test successful validation of a real CycloneDX file.""" + assert os.path.exists(cyclonedx_sbom_path), "Fixture file is missing" + + format_name, version, metadata, doc = SBOMValidator.validate_sbom_file(cyclonedx_sbom_path) + + assert format_name == 'cyclonedx' + assert version == '1.5' + assert metadata['components_count'] > 0 + assert 'serial_number' in metadata + assert doc is not None + + def test_validate_spdx_from_file(self, spdx_sbom_path): + """Test successful validation of a real SPDX file.""" + assert os.path.exists(spdx_sbom_path), "Fixture file is missing" + + format_name, version, metadata, doc = SBOMValidator.validate_sbom_file(spdx_sbom_path) + + assert format_name == 'spdx' + assert version == '2.3' + assert metadata['packages_count'] > 0 + assert doc is not None + + def test_prepare_cyclonedx_no_conversion(self, cyclonedx_sbom_path): + """CycloneDX should not require conversion.""" + format_name, version, metadata, doc = SBOMValidator.validate_sbom_file(cyclonedx_sbom_path) + + upload_path = SBOMValidator.prepare_sbom_for_upload(cyclonedx_sbom_path, format_name, doc) + + assert upload_path == cyclonedx_sbom_path + + def test_prepare_spdx_rdf_no_conversion(self, spdx_sbom_path): + """SPDX RDF should not require conversion.""" + format_name, version, metadata, doc = SBOMValidator.validate_sbom_file(spdx_sbom_path) + + upload_path = SBOMValidator.prepare_sbom_for_upload(spdx_sbom_path, format_name, doc) + + assert upload_path == spdx_sbom_path + + +class TestFormatDetection: + """Test cases for SBOM format detection.""" + + def test_detect_cyclonedx_from_file(self, cyclonedx_sbom_path): + """Test detection of CycloneDX JSON format from a real file.""" + result = SBOMValidator._detect_sbom_format(cyclonedx_sbom_path) + assert result == "cyclonedx" + + def test_detect_spdx_rdf_from_file(self, spdx_sbom_path): + """Test detection of SPDX RDF format from a real file.""" + result = SBOMValidator._detect_sbom_format(spdx_sbom_path) + assert result == "spdx" + + +class TestCycloneDXValidationErrors: + """Test cases for CycloneDX validation error conditions.""" + + @patch.dict(sys.modules, {'cyclonedx.validation': None, 'cyclonedx.schema': None}) + def test_validate_cyclonedx_missing_library(self): + """Test validation fails when CycloneDX library is missing.""" + with pytest.raises(ValidationError, match="CycloneDX library not available"): + SBOMValidator._validate_cyclonedx("/path/to/file.json") + + def test_validate_cyclonedx_invalid_format(self): + """Test CycloneDX validation fails for invalid format.""" + invalid_json = { + "bomFormat": "InvalidFormat", + "specVersion": "1.6" + } + + json_content = json.dumps(invalid_json) + + with patch('builtins.open', mock_open(read_data=json_content)): + with pytest.raises(ValidationError, match="does not appear to be a CycloneDX BOM"): + SBOMValidator._validate_cyclonedx("/path/to/file.json") + + def test_validate_cyclonedx_missing_spec_version(self): + """Test CycloneDX validation fails for missing spec version.""" + invalid_json = { + "bomFormat": "CycloneDX" + } + + json_content = json.dumps(invalid_json) + + with patch('builtins.open', mock_open(read_data=json_content)): + with pytest.raises(ValidationError, match="missing specVersion field"): + SBOMValidator._validate_cyclonedx("/path/to/file.json") + + def test_validate_cyclonedx_unsupported_version(self): + """Test CycloneDX validation fails for unsupported version.""" + invalid_json = { + "bomFormat": "CycloneDX", + "specVersion": "2.0" # Unsupported version + } + + json_content = json.dumps(invalid_json) + + with patch('builtins.open', mock_open(read_data=json_content)): + with pytest.raises(ValidationError, match="Unknown CycloneDX version"): + SBOMValidator._validate_cyclonedx("/path/to/file.json") + + def test_validate_cyclonedx_unsupported_upload_version(self): + """Test CycloneDX validation fails for versions not supported for upload.""" + invalid_json = { + "bomFormat": "CycloneDX", + "specVersion": "1.3" # Valid but not supported for upload + } + + json_content = json.dumps(invalid_json) + + with patch('builtins.open', mock_open(read_data=json_content)): + with patch('cyclonedx.validation.json.JsonStrictValidator') as mock_validator_class: + mock_validator = MagicMock() + mock_validator.validate_str.return_value = [] + mock_validator_class.return_value = mock_validator + + with pytest.raises(ValidationError, match="only versions 1.4, 1.5, 1.6 are supported for import"): + SBOMValidator._validate_cyclonedx("/path/to/file.json") + + def test_validate_cyclonedx_validation_errors(self): + """Test CycloneDX validation fails with schema errors.""" + valid_cyclonedx = { + "bomFormat": "CycloneDX", + "specVersion": "1.6" + # Missing other required fields + } + json_content = json.dumps(valid_cyclonedx) + with patch('builtins.open', mock_open(read_data=json_content)): + with patch('cyclonedx.validation.json.JsonStrictValidator') as mock_validator_class: + mock_validator = MagicMock() + mock_validator.validate_str.return_value = [MagicMock(message="Validation Error")] + mock_validator_class.return_value = mock_validator + with pytest.raises(ValidationError, match="CycloneDX validation failed"): + SBOMValidator._validate_cyclonedx("/path/to/file.json") + + def test_validate_cyclonedx_invalid_json(self): + """Test CycloneDX validation fails for invalid JSON.""" + with patch('builtins.open', mock_open(read_data="{ 'bad': json }")): + with pytest.raises(ValidationError, match="Invalid JSON format"): + SBOMValidator._validate_cyclonedx("/path/to/file.json") + + def test_validate_cyclonedx_file_not_found(self): + """Test CycloneDX validation fails for non-existent file.""" + with patch('builtins.open', side_effect=FileNotFoundError): + with pytest.raises(FileSystemError, match="SBOM file not found"): + SBOMValidator._validate_cyclonedx("/nonexistent/file.json") + + +class TestSPDXValidationErrors: + """Test cases for SPDX validation error conditions.""" + + @patch.dict(sys.modules, {'spdx_tools.spdx.parser.parse_anything': None}) + def test_validate_spdx_missing_library(self): + """Test validation fails when SPDX library is missing.""" + with pytest.raises(ValidationError, match="SPDX tools library not available"): + SBOMValidator._validate_spdx("/path/to/file.rdf") + + def test_validate_spdx_invalid_document(self): + """Test SPDX validation fails if file is not a valid SPDX document.""" + with patch('spdx_tools.spdx.parser.parse_anything.parse_file', return_value=None): + with pytest.raises(ValidationError, match="does not contain a valid SPDX document"): + SBOMValidator._validate_spdx("/path/to/file.rdf") + + def test_validate_spdx_validation_errors(self): + """Test SPDX validation fails with schema errors.""" + from spdx_tools.spdx.model import Document, SpdxNoAssertion, SpdxNone + from spdx_tools.spdx.validation.validation_message import ValidationMessage + + mock_doc = MagicMock(spec=Document) + mock_doc.creation_info.spdx_version = "SPDX-2.3" + + with patch('spdx_tools.spdx.parser.parse_anything.parse_file', return_value=mock_doc): + with patch('spdx_tools.spdx.validation.document_validator.validate_full_spdx_document') as mock_validate: + mock_validate.return_value = [ValidationMessage("Validation Error", "context")] + + with pytest.raises(ValidationError, match="SPDX document validation failed"): + SBOMValidator._validate_spdx("/path/to/file.rdf") + + def test_validate_spdx_unsupported_version(self): + """Test SPDX validation fails for unsupported version.""" + from spdx_tools.spdx.model import Document + + mock_doc = MagicMock(spec=Document) + mock_doc.creation_info.spdx_version = "SPDX-1.0" # Unsupported + + with patch('spdx_tools.spdx.parser.parse_anything.parse_file', return_value=mock_doc): + with pytest.raises(ValidationError, match="subsequent validation relies on the correct version"): + SBOMValidator._validate_spdx("/path/to/file.rdf") + + def test_validate_spdx_file_not_found(self): + """Test SPDX validation fails for non-existent file.""" + with patch('spdx_tools.spdx.parser.parse_anything.parse_file', side_effect=FileNotFoundError): + with pytest.raises(FileSystemError, match="SBOM file not found"): + SBOMValidator._validate_spdx("/nonexistent/file.rdf") + + +class TestCleanupUtility: + """Test cases for the cleanup utility.""" + + def test_cleanup_temp_file_success(self): + """Test successful cleanup of temporary file.""" + temp_file = "/tmp/spdx_converted_abc123.rdf" + + with patch('os.path.exists', return_value=True): + with patch('os.unlink') as mock_unlink: + with patch('tempfile.gettempdir', return_value="/tmp"): + SBOMValidator.cleanup_temp_file(temp_file) + mock_unlink.assert_called_once_with(temp_file) + + def test_cleanup_temp_file_not_temp(self): + """Test cleanup skips non-temporary files.""" + regular_file = "/home/user/regular_file.rdf" + + with patch('os.path.exists', return_value=True): + with patch('os.unlink') as mock_unlink: + with patch('tempfile.gettempdir', return_value="/tmp"): + SBOMValidator.cleanup_temp_file(regular_file) + mock_unlink.assert_not_called() + + def test_cleanup_temp_file_not_exists(self): + """Test cleanup handles non-existent file gracefully.""" + temp_file = "/tmp/nonexistent.rdf" + + with patch('os.path.exists', return_value=False): + with patch('os.unlink') as mock_unlink: + with patch('tempfile.gettempdir', return_value="/tmp"): + SBOMValidator.cleanup_temp_file(temp_file) + mock_unlink.assert_not_called() + + def test_cleanup_temp_file_failure(self): + """Test cleanup handles unlink failure gracefully.""" + temp_file = "/tmp/spdx_converted_abc123.rdf" + + with patch('os.path.exists', return_value=True): + with patch('os.unlink', side_effect=OSError("Permission denied")): + with patch('tempfile.gettempdir', return_value="/tmp"): + with patch('workbench_cli.utilities.sbom_validator.logger.warning') as mock_warning: + SBOMValidator.cleanup_temp_file(temp_file) + mock_warning.assert_called_once() + + +class TestSupportedFormatsMethod: + """Test cases for get_supported_formats method.""" + + def test_get_supported_formats_structure(self): + """Test that get_supported_formats returns the expected structure.""" + formats = SBOMValidator.get_supported_formats() + + assert isinstance(formats, dict) + assert 'cyclonedx' in formats + assert 'spdx' in formats + + # Check CycloneDX format + cyclonedx_info = formats['cyclonedx'] + assert 'name' in cyclonedx_info + assert 'supported_versions' in cyclonedx_info + assert 'supported_extensions' in cyclonedx_info + assert isinstance(cyclonedx_info['supported_versions'], list) + assert isinstance(cyclonedx_info['supported_extensions'], list) + + # Check SPDX format + spdx_info = formats['spdx'] + assert 'name' in spdx_info + assert 'supported_versions' in spdx_info + assert 'supported_extensions' in spdx_info + assert isinstance(spdx_info['supported_versions'], list) + assert isinstance(spdx_info['supported_extensions'], list) + + # Check that SPDX now includes JSON extension + assert '.json' in spdx_info['supported_extensions'] + + +class TestSBOMPreparation: + """Test cases for SBOM preparation functionality.""" + + def test_prepare_cyclonedx_no_conversion(self): + """Test that CycloneDX files don't need conversion.""" + parsed_bom = {"bomFormat": "CycloneDX", "specVersion": "1.6"} + + result = SBOMValidator.prepare_sbom_for_upload("/path/to/file.json", "cyclonedx", parsed_bom) + + assert result == "/path/to/file.json" # Original file returned + + def test_prepare_spdx_rdf_no_conversion(self): + """Test that SPDX RDF files don't need conversion.""" + from spdx_tools.spdx.model import Document + parsed_document = MagicMock(spec=Document) + + result = SBOMValidator.prepare_sbom_for_upload("/path/to/file.rdf", "spdx", parsed_document) + + assert result == "/path/to/file.rdf" # Original file returned + + def test_prepare_spdx_json_with_conversion(self): + """Test that SPDX JSON files are converted to RDF.""" + from spdx_tools.spdx.model import Document + + with patch('spdx_tools.spdx.writer.write_anything.write_file') as mock_write: + with patch('tempfile.mkstemp') as mock_mkstemp: + with patch('os.close') as mock_close: + parsed_document = MagicMock(spec=Document) + mock_mkstemp.return_value = (123, "/tmp/spdx_converted_abc123.rdf") + + result = SBOMValidator.prepare_sbom_for_upload("/path/to/file.json", "spdx", parsed_document) + + assert result == "/tmp/spdx_converted_abc123.rdf" + mock_write.assert_called_once_with(parsed_document, "/tmp/spdx_converted_abc123.rdf", validate=False) + mock_close.assert_called_once_with(123) + + def test_prepare_unknown_format_error(self): + """Test that unknown formats raise an error.""" + with pytest.raises(ValidationError, match="Unknown SBOM format: unknown"): + SBOMValidator.prepare_sbom_for_upload("/path/to/file.json", "unknown", {}) \ No newline at end of file diff --git a/tests/unit/utilities/test_scan_target_validators.py b/tests/unit/utilities/test_scan_target_validators.py index dd07974..c4aebc7 100644 --- a/tests/unit/utilities/test_scan_target_validators.py +++ b/tests/unit/utilities/test_scan_target_validators.py @@ -207,4 +207,68 @@ def test_validate_reuse_source_missing_source_scan(mock_workbench, mock_params): mock_params.id_reuse_type = "scan" mock_params.id_reuse_source = None with pytest.raises(ConfigurationError, match="Missing scan name"): - validate_reuse_source(mock_workbench, mock_params) \ No newline at end of file + validate_reuse_source(mock_workbench, mock_params) + +# --- Tests for import-sbom compatibility --- +def test_ensure_scan_compatibility_import_sbom_with_report_scan_compatible(mock_workbench, mock_params): + """Test that import-sbom can reuse SBOM import scans.""" + mock_params.command = 'import-sbom' + mock_workbench.get_scan_information.return_value = { + "is_from_report": "1" + } + + ensure_scan_compatibility(mock_workbench, mock_params, "test_scan_code") + +def test_ensure_scan_compatibility_import_sbom_with_code_scan_incompatible(mock_workbench, mock_params): + """Test that import-sbom cannot reuse code upload scans.""" + mock_params.command = 'import-sbom' + mock_workbench.get_scan_information.return_value = { + "is_from_report": "0", + "git_repo_url": None + } + + with pytest.raises(CompatibilityError, match="was not created for SBOM import and cannot be reused for SBOM import"): + ensure_scan_compatibility(mock_workbench, mock_params, "test_scan_code") + +def test_ensure_scan_compatibility_import_sbom_with_git_scan_incompatible(mock_workbench, mock_params): + """Test that import-sbom cannot reuse git scans.""" + mock_params.command = 'import-sbom' + mock_workbench.get_scan_information.return_value = { + "is_from_report": "0", + "git_repo_url": "https://github.com/test/repo.git" + } + + with pytest.raises(CompatibilityError, match="was not created for SBOM import and cannot be reused for SBOM import"): + ensure_scan_compatibility(mock_workbench, mock_params, "test_scan_code") + +def test_ensure_scan_compatibility_scan_with_report_scan_incompatible(mock_workbench, mock_params): + """Test that scan command cannot reuse SBOM import scans.""" + mock_params.command = 'scan' + mock_workbench.get_scan_information.return_value = { + "is_from_report": "1" + } + + with pytest.raises(CompatibilityError, match="was created for SBOM import and cannot be reused for code upload"): + ensure_scan_compatibility(mock_workbench, mock_params, "test_scan_code") + +def test_ensure_scan_compatibility_scan_git_with_report_scan_incompatible(mock_workbench, mock_params): + """Test that scan-git command cannot reuse SBOM import scans.""" + mock_params.command = 'scan-git' + mock_params.git_url = "https://github.com/test/repo.git" + mock_params.git_branch = "main" + mock_workbench.get_scan_information.return_value = { + "is_from_report": "1" + } + + with pytest.raises(CompatibilityError, match="was created for SBOM import and cannot be reused for Git scanning"): + ensure_scan_compatibility(mock_workbench, mock_params, "test_scan_code") + +def test_ensure_scan_compatibility_import_da_with_report_scan_incompatible(mock_workbench, mock_params): + """Test that import-da cannot reuse SBOM import scans.""" + mock_params.command = 'import-da' + mock_workbench.get_scan_information.return_value = { + "is_from_report": "1" + } + + with pytest.raises(CompatibilityError, match="was created for SBOM import and cannot be reused for dependency analysis import"): + ensure_scan_compatibility(mock_workbench, mock_params, "test_scan_code") \ No newline at end of file diff --git a/tests/unit/utilities/test_scan_workflows.py b/tests/unit/utilities/test_scan_workflows.py index 8c7657e..ba374ec 100644 --- a/tests/unit/utilities/test_scan_workflows.py +++ b/tests/unit/utilities/test_scan_workflows.py @@ -13,7 +13,6 @@ from typing import Dict, Any from workbench_cli.utilities.scan_workflows import ( - assert_scan_is_idle, wait_for_scan_completion, determine_scans_to_run, fetch_results, @@ -306,44 +305,6 @@ def test_save_write_failure(self, mock_makedirs, mock_open_file): # SCAN STATUS MANAGEMENT TESTS # ============================================================================ -class TestAssertScanIsIdle: - """Test cases for the assert_scan_is_idle function.""" - - def test_all_processes_idle(self, mock_workbench, mock_params): - """Test when all requested processes are already idle.""" - mock_workbench.check_status_download_content_from_git.return_value = "FINISHED" - mock_workbench.get_scan_status.return_value = create_mock_status_response("FINISHED") - mock_workbench._standard_scan_status_accessor.return_value = "FINISHED" - - # Should complete without raising - assert_scan_is_idle(mock_workbench, TEST_SCAN_CODE, mock_params, ["GIT_CLONE", "SCAN"]) - - # Verify correct API calls - mock_workbench.check_status_download_content_from_git.assert_called_with(TEST_SCAN_CODE) - mock_workbench.get_scan_status.assert_called_with("SCAN", TEST_SCAN_CODE) - - def test_scan_not_found_graceful_handling(self, mock_workbench, mock_params): - """Test graceful handling when scan is not found.""" - mock_workbench.check_status_download_content_from_git.side_effect = ScanNotFoundError("Scan not found") - - # Should not raise exception - assert_scan_is_idle(mock_workbench, TEST_SCAN_CODE, mock_params, ["GIT_CLONE"]) - - def test_api_error_propagation(self, mock_workbench, mock_params): - """Test that API errors are properly propagated.""" - mock_workbench.check_status_download_content_from_git.side_effect = ApiError("API temporarily unavailable") - - with pytest.raises(ProcessError, match="Failed to check status"): - assert_scan_is_idle(mock_workbench, TEST_SCAN_CODE, mock_params, ["GIT_CLONE"]) - - def test_extract_archives_not_supported(self, mock_workbench, mock_params): - """Test handling when EXTRACT_ARCHIVES status checking is not supported.""" - mock_workbench._is_status_check_supported.return_value = False - - # Should complete without errors - assert_scan_is_idle(mock_workbench, TEST_SCAN_CODE, mock_params, ["EXTRACT_ARCHIVES"]) - mock_workbench._is_status_check_supported.assert_called_with(TEST_SCAN_CODE, "EXTRACT_ARCHIVES") - class TestWaitForScanCompletion: """Test cases for the wait_for_scan_completion function."""