diff --git a/.Rbuildignore b/.Rbuildignore index f2ab003..623cdfe 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -3,3 +3,6 @@ ^LICENSE\.md$ ^doc$ ^Meta$ +^_pkgdown\.yml$ +^docs$ +^pkgdown$ diff --git a/.gitignore b/.gitignore index 893813d..fba084b 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,5 @@ po/*~ rsconnect/ inst/doc /Meta/ +/doc/ +# docs diff --git a/DESCRIPTION b/DESCRIPTION index d65ba52..01bbbb4 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -2,7 +2,7 @@ Package: PathwayEmbed Title: Tools for Pathway-Level Embedding and Visualization in Single-Cell Data Version: 0.0.0.9000 Authors@R: - person("Yaqing", "Huang", email = "yaqing.huang@yale.edu", role = c("aut", "cre")) + person("Yaqing", "Huang", email = "hyaqing1023@gmail.com", role = c("aut", "cre")) Description: Provides tools for analyzing and visualizing pathway-level activity in single-cell RNA-seq data. Includes functions for computing cell-wise pathway scores, visualizing transduction states, calculating activation percentages, @@ -10,12 +10,11 @@ Description: Provides tools for analyzing and visualizing pathway-level activity License: MIT + file LICENSE Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.2 +RoxygenNote: 7.3.3 Depends: R (>= 3.5) Imports: readxl, - Seurat, RColorBrewer, ggplot2, cowplot, @@ -26,10 +25,13 @@ Imports: effsize, tidyverse, purrr -Suggests: - knitr, +Suggests: + Seurat, + scales, rmarkdown, + knitr, testthat (>= 3.0.0) Config/testthat/edition: 3 LazyData: true VignetteBuilder: knitr +URL: https://raredonlab.github.io/PathwayEmbed diff --git a/NAMESPACE b/NAMESPACE index 12e3197..15e9781 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -2,24 +2,20 @@ export(CalculatePercentage) export(ComputeCellData) +export(DataPreProcess) +export(ListPathway) export(LoadPathway) export(PathwayMaxMin) export(PlotPathway) export(PreparePlotData) -import(RColorBrewer) -import(Seurat) -import(cowplot) import(ggplot2) -import(matrixStats) -import(readxl) -import(tidyverse) -import(viridis) -importFrom(dplyr,"%>%") importFrom(dplyr,bind_rows) importFrom(effsize,cohen.d) importFrom(matrixStats,rowMaxs) importFrom(matrixStats,rowMins) -importFrom(purrr,map) -importFrom(stats,cmdscale) -importFrom(stats,dist) +importFrom(readxl,excel_sheets) +importFrom(readxl,read_excel) +importFrom(stats,kruskal.test) importFrom(stats,na.omit) +importFrom(stats,pairwise.wilcox.test) +importFrom(stats,wilcox.test) diff --git a/R/CalculatePercentage.R b/R/CalculatePercentage.R index b233435..e820cd1 100644 --- a/R/CalculatePercentage.R +++ b/R/CalculatePercentage.R @@ -1,63 +1,103 @@ #' CalculatePercentage #' -#' This function calculates the percentage of cells in ON (scale > 0) and OFF (scale < 0) -#' activation states within each group defined by `group_var`. If exactly two groups -#' are provided, it also computes Cohen's d effect size between their activation values. +#' Calculates the percentage of cells in ON (\code{scale > 0}) and OFF +#' (\code{scale < 0}) activation states within each group defined by +#' \code{group_var}. +#' +#' If exactly two groups are provided, Cohen's d effect size and a Wilcoxon +#' rank-sum p-value are computed between the two groups. +#' +#' If more than two groups are provided, a Kruskal-Wallis p-value is computed +#' across all groups, and pairwise Wilcoxon p-values (Bonferroni-corrected) are +#' attached as an attribute. +#' +#' @param to.plot A data frame from \code{PreparePlotData()}, containing at +#' least a \code{scale} column and the grouping column specified by +#' \code{group_var}. +#' @param group_var A character string specifying the grouping column in +#' \code{to.plot} (e.g. \code{"genotype"}, \code{"treatment"}). +#' +#' @return A data frame with columns: +#' \describe{ +#' \item{group}{Group label.} +#' \item{percentage_on}{Percentage of cells with \code{scale > 0}.} +#' \item{percentage_off}{Percentage of cells with \code{scale < 0}.} +#' \item{cohens_d}{(2-group only) Cohen's d effect size. Repeated for +#' both group rows as it is a single pairwise estimate.} +#' \item{p_value}{(2-group only) Wilcoxon rank-sum p-value.} +#' \item{kruskal_p}{(3+ groups only) Kruskal-Wallis p-value.} +#' } +#' For 3+ groups, Bonferroni-corrected pairwise Wilcoxon p-values are +#' attached via \code{attr(result, "pairwise_wilcox")}. #' -#' @name CalculatePercentage #' @importFrom dplyr bind_rows #' @importFrom effsize cohen.d -#' @importFrom stats na.omit -#' @param to.plot A data frame containing at least a `scale` column and a grouping column. -#' @param group_var A string specifying the grouping variable (e.g., "genotype", "treatment"). +#' @importFrom stats na.omit wilcox.test kruskal.test pairwise.wilcox.test #' -#' @return A data frame with the percentage of ON/OFF cells and Cohen's d (if applicable). #' @examples +#' \dontrun{ #' data(fake_to_plot) #' CalculatePercentage(fake_to_plot, "genotype") +#' } +#' #' @export -CalculatePercentage <- function(to.plot, group_var){ - # Make sure there is scale data - stopifnot("scale" %in% names(to.plot)) +CalculatePercentage <- function(to.plot, group_var) { - # Make sure no NA - groups <- unique(na.omit(to.plot[[group_var]])) + if (!"scale" %in% names(to.plot)) { + stop("Column 'scale' not found in to.plot. Use PreparePlotData() first.") + } + if (!group_var %in% names(to.plot)) { + stop("Grouping column '", group_var, "' not found in to.plot.") + } + + groups <- unique(na.omit(to.plot[[group_var]])) results <- list() + # --- Per-group ON/OFF percentages --- for (g in groups) { - subset_data <- to.plot[to.plot[[group_var]] == g, ] + subset_data <- to.plot[to.plot[[group_var]] == g & !is.na(to.plot[[group_var]]), ] total <- nrow(subset_data) - - # Calculate how many cells are in on/off status - on <- sum(subset_data[["scale"]] > 0, na.rm = TRUE) + if (total == 0) { + warning("Group '", g, "' has no cells after NA removal; skipping.") + next + } + on <- sum(subset_data[["scale"]] > 0, na.rm = TRUE) off <- sum(subset_data[["scale"]] < 0, na.rm = TRUE) - - # Calculate percentages of on/off cells results[[as.character(g)]] <- list( - percentage_on = round(100 * on / total, 2), + percentage_on = round(100 * on / total, 2), percentage_off = round(100 * off / total, 2) ) } - # When there are two groups in comparison, Cohen's d — a measure of effect size — will be applied for statistic purpose + # --- Statistics --- if (length(groups) == 2) { - g1 <- groups[1] - g2 <- groups[2] + g1 <- groups[1] + g2 <- groups[2] vec1 <- to.plot[to.plot[[group_var]] == g1, "scale"] vec2 <- to.plot[to.plot[[group_var]] == g2, "scale"] - - # Computes Cohen's d between two numeric vectors (vec1 and vec2) and extracts the estimated value of the effect size. cohens_d_val <- cohen.d(vec1, vec2)$estimate - # |d value|: 0 - 0.2, effect size is negligible - # |d value|: 0.2 - 0.5: small effect - # |d value|: 0.5 - 0.8: medium effect - # |d value|: > 0.8: large effect + p_val <- wilcox.test(vec1, vec2)$p.value + for (g in groups) { + results[[as.character(g)]]$cohens_d <- cohens_d_val + results[[as.character(g)]]$p_value <- p_val + } + + } else if (length(groups) > 2) { + kw_p <- kruskal.test(to.plot[["scale"]], to.plot[[group_var]])$p.value + pw <- pairwise.wilcox.test( + to.plot[["scale"]], + to.plot[[group_var]], + p.adjust.method = "bonferroni" + ) + for (g in groups) { + results[[as.character(g)]]$kruskal_p <- kw_p + } - results[[as.character(g1)]]$cohens_d <- cohens_d_val - results[[as.character(g2)]]$cohens_d <- cohens_d_val + # Build output and attach pairwise results in same scope as pw + df <- bind_rows(results, .id = "group") + attr(df, "pairwise_wilcox") <- pw$p.value + return(df) } - # Make a dataframe for the output - df <- bind_rows(results, .id = "group") - return(df) + bind_rows(results, .id = "group") } diff --git a/R/ComputeCellData.R b/R/ComputeCellData.R index 94565ac..4d7efd5 100644 --- a/R/ComputeCellData.R +++ b/R/ComputeCellData.R @@ -1,145 +1,69 @@ #' ComputeCellData #' -#' A function computes cell status for a given pathway in single-cell RNA-seq data, -#' based on the distance between genes in a specified pathway. The distance is computed -#' for each batch of cells, and classical multidimensional scaling (MDS) is used to -#' visualize the pathway expression across cells. +#' Computes a per-cell pathway activation score by measuring each cell's +#' distance to the pathway ON and OFF reference states from +#' \code{PathwayMaxMin()}. Scores are normalized to \[0, 1]\, where 1 indicates +#' proximity to the ON state and 0 indicates proximity to the OFF state. #' -#' @name ComputeCellData -#' @import Seurat -#' @importFrom matrixStats rowMins rowMaxs -#' @importFrom stats dist cmdscale -#' @importFrom dplyr %>% -#' @importFrom purrr map -#' @import tidyverse -#' @import viridis +#' @param expr_data A z-scored gene-by-cell numeric matrix, e.g. from +#' \code{DataPreProcess()}. +#' @param pathway.stat A data frame from \code{PathwayMaxMin()} with columns +#' \code{pathway.on} and \code{pathway.off}. Rownames must be gene symbols. +#' @param distance.method Character string specifying the distance metric. +#' One of \code{"manhattan"} (default) or \code{"euclidean"}. #' -#' @param x A `Seurat` object containing single-cell RNA sequencing data. -#' @param pathway A `character` string specifying the pathway name. This should match a pathway used by `LoadPathway()`. -#' @param distance.method A `character` string specifying the distance metric to use.Default is "manhattan". -#' Options include: `"manhattan"`, `"euclidean"`, `"canberra"`, `"binary"`, `"minkowski"` -#' @param batch.size An `integer` specifying the number of cells to process per batch. Default is 1000. -#' @param scale.data A `logical` indicating whether to use scaled data (`scale.data = TRUE`) or normalized data. Default is `TRUE`. -#' -#' @return A data frame of MDS results with normalized values per cell, suitable for thresholding or visualization. +#' @return A named numeric vector of length equal to the number of cells, +#' with scores in \[0, 1\]. A score near 1 indicates the cell is close to +#' the ON state; a score near 0 indicates proximity to the OFF state. +#' Cells where both distances are 0 return \code{NaN} with a warning. #' #' @examples -#' data(fake_test_object) -#' ComputeCellData(fake_test_object, pathway = "Wnt", distance.method = "manhattan", batch.size = 2000) +#' \dontrun{ +#' pathwaydata <- LoadPathway("Hypoxia_6hr", "human") +#' expr_filtered <- DataPreProcess(norm_matrix, pathwaydata) +#' pathway_stat <- PathwayMaxMin(expr_filtered, pathwaydata) +#' scores <- ComputeCellData(expr_filtered, pathway_stat) +#' } #' #' @export -ComputeCellData <- function(x, pathway, distance.method, batch.size = batch.size, scale.data = TRUE){ - - # Get pathway data - pathwaydata <- LoadPathway(pathway) - names <- c(pathwaydata[[1]]) - - # Use only genes present in Seurat object - valid_names <- intersect(names, rownames(x)) - if (length(valid_names) == 0) { - stop("No valid pathway genes found in the Seurat object.") +ComputeCellData <- function(expr_data, + pathway.stat, + distance.method = "manhattan") { + + # Gene alignment + common_genes <- intersect(rownames(expr_data), rownames(pathway.stat)) + if (length(common_genes) == 0) { + stop("No overlapping genes between expr_data and pathway.stat.") } - x <- ScaleData(x, features = valid_names) - - # Extract expression data from the desired slot - slot_use <- if (scale.data) "scale.data" else "data" - expr_data <- GetAssayData(x, assay = "RNA", slot = slot_use)[valid_names, , drop = FALSE] - - # Pathway max and min - pathway.stat <- PathwayMaxMin(x, pathway) - - # Get cell indices - cell_id <- colnames(expr_data) - - # Shuffle cell indices - shuffled_cell_id <- sample(cell_id) - - # Split shuffled indices into batches - # Check if batch.size is provided; if not, set default and message - if (missing(batch.size) || is.null(batch.size)) { - message("Parameter 'batch.size' is missing or NULL. Setting default batch size to 1000.") - batch.size <- 1000 + if (length(common_genes) < nrow(expr_data)) { + message(length(common_genes), " of ", nrow(expr_data), + " genes used after aligning with pathway.stat.") } - # Define batch size - batch_size <- batch.size - - batches <- split(shuffled_cell_id, ceiling(seq_along(shuffled_cell_id) / batch.size)) - - # Subset expression data into chunks based on sampled indices - expr_chunks <- lapply(batches, function(cols) expr_data[, cols, drop = FALSE]) - - # For each expr_chunks, do distance measuring - # Initialize list to store results - batch_results <- list() - - # Loop through batches of 500 cells - for (i in seq_len(length(batches))) { - - message("Processing batch ", i) - - # Extract and convert expression chunk - expr_data <- expr_chunks[[i]] - temp.data.batch <- as.data.frame(expr_data) - - # Merge along columns - pathwaytempdata <- cbind(pathway.stat, temp.data.batch) - - # Check for enough cells (columns) - if (ncol(pathwaytempdata) < 2) { - warning("Batch ", i, " does not have enough cells for distance calculation. Skipping...") - next - } - - # Check if distance.method is provided; if not, set default and message - if (missing(distance.method) || is.null(distance.method)) { - message("Parameter 'distance.method' is missing or NULL. Setting default distance.method to 'manhattan'.") - distance.method <- "manhattan" - } - - # Distance calculation - message("Computing distance...") - d <- dist(t(pathwaytempdata), method = distance.method) - # "manhattan" is sum of absolute differences (city block distance), good for sparse data (gene expression) - # "euclidean" is stratight-line distance, is useful for PCA clustering - # "canberra" is weighted distance, is also good for sparse data and when values have very different scales - # "binary" is distance based on presence/absence (0/1) - # "minkowski" is generalization of euclidean & manhattan, tunable using p parameter - # choose "manhattan" as it works well for high-dimensional data and less sensitive to large outliers than euclidean distance - - # MDS - message("Running MDS ...") - fit <- cmdscale(d, eig = TRUE, k = 1) - message("MDS finished") - - # Normalize the MDS values - temp.data.mds <- as.data.frame(fit$points) - colnames(temp.data.mds) <- "V1" - V1_min <- min(temp.data.mds$V1, na.rm = TRUE) - V1_max <- max(temp.data.mds$V1, na.rm = TRUE) - - if (V1_max == V1_min) { - temp.data.mds$normalized <- 0 - } else { - temp.data.mds$normalized <- (temp.data.mds$V1 - V1_min) / (V1_max - V1_min) - } - - # Store result - batch_results[[i]] <- temp.data.mds - - # Report - cat("Batch", i, "processed with", ncol(expr_data), "cells\n") + expr_data <- expr_data[common_genes, , drop = FALSE] + pathway.stat <- pathway.stat[common_genes, , drop = FALSE] + + pathway_on <- pathway.stat$pathway.on + pathway_off <- pathway.stat$pathway.off + cell_mat <- t(expr_data) # cells x genes + + message("Computing distance...") + if (distance.method == "manhattan") { + dist_to_on <- rowSums(abs(sweep(cell_mat, 2, pathway_on, "-"))) + dist_to_off <- rowSums(abs(sweep(cell_mat, 2, pathway_off, "-"))) + } else if (distance.method == "euclidean") { + dist_to_on <- sqrt(rowSums(sweep(cell_mat, 2, pathway_on, "-")^2)) + dist_to_off <- sqrt(rowSums(sweep(cell_mat, 2, pathway_off, "-")^2)) + } else { + stop("Unsupported distance method. Use 'manhattan' or 'euclidean'.") } - final_mds <- do.call(rbind, batch_results) # Merge all batch MDS results + # Normalize to [0, 1] + denom <- dist_to_on + dist_to_off + if (any(denom == 0)) { + warning("Some cells have zero total distance; scores will be NaN.") + } + normalized <- dist_to_off / denom - return(final_mds) + return(normalized) } - -# using sample -# barcode list (randomization) -# list of data chunk -# make these list independent -# short loop -# lappy, sapply (list-wide operation) -# https://www.r-bloggers.com/2022/03/complete-tutorial-on-using-apply-functions-in-r/ diff --git a/R/DataPreProcess.R b/R/DataPreProcess.R new file mode 100644 index 0000000..8d3d2bd --- /dev/null +++ b/R/DataPreProcess.R @@ -0,0 +1,86 @@ +#' DataPreProcess +#' +#' Preprocess expression data for pathway analysis. +#' +#' @param x A Seurat object OR a gene-by-cell normalized expression matrix +#' @param pathwaydata Pathway data from the output of LoadPathway() +#' @param Seurat.object Logical; whether x is a Seurat object +#' @param assay Assay to use if x is a Seurat object (default = "RNA") +#' @param slot Slot to extract from Seurat object (default = "data") +#' @param scale.data Logical; whether to apply row-wise z-score scaling +#' (default = TRUE). If FALSE, the filtered expression matrix is returned +#' as-is without any scaling. +#' +#' @return A gene-by-cell expression matrix of pathway genes. If +#' \code{scale.data = TRUE} (default), values are row-wise z-scored; +#' if \code{scale.data = FALSE}, raw input filtered values are returned. +#' +#' @examples +#' \dontrun{ +#' DataPreProcess(seurat_obj, pathwaydata, Seurat.object = TRUE) +#' DataPreProcess(norm_matrix, pathwaydata) +#' DataPreProcess(norm_matrix, pathwaydata, scale.data = FALSE) +#' } +#' +#' @export +DataPreProcess <- function( + x, + pathwaydata, + Seurat.object = FALSE, + assay = "RNA", + slot = "data", + scale.data = TRUE +) { + + #Extract expression matrix from Seurat.object + if (Seurat.object) { + + if (!requireNamespace("Seurat", quietly = TRUE)) { + stop("Seurat.object = TRUE requires the Seurat package.") + } + + expr_mat <- Seurat::GetAssayData( + object = x, + assay = assay, + layer = slot + ) + expr_mat <- as.matrix(expr_mat) # convert sparse dgCMatrix to dense for downstream use + + } else { + + if (!is.matrix(x) && !is.data.frame(x)) { + stop("When Seurat.object = FALSE, x must be a gene-by-cell matrix.") + } + + expr_mat <- as.matrix(x) + } + + + # Get pathway genes + if (!is.data.frame(pathwaydata)) { + stop("pathwaydata must be the output of LoadPathway().") + } + + if (!"Gene_Symbol" %in% colnames(pathwaydata)) { + stop("pathwaydata must contain a 'Gene_Symbol' column.") + } + + pathway_genes <- unique(pathwaydata$Gene_Symbol) + pathway_genes <- pathway_genes[!is.na(pathway_genes)] + + #Filter to valid genes + valid_names <- pathway_genes[pathway_genes %in% rownames(expr_mat)] + if (length(valid_names) == 0) { + stop("No valid pathway genes found in the input.") + } + + expr_data <- expr_mat[valid_names, , drop = FALSE] + + # Row-wise z-score (optional) + if (scale.data) { + expr_data <- t(scale(t(expr_data))) + expr_data[is.na(expr_data)] <- 0 + } + + return(expr_data) +} diff --git a/R/ListPathway.R b/R/ListPathway.R new file mode 100644 index 0000000..6a343e7 --- /dev/null +++ b/R/ListPathway.R @@ -0,0 +1,64 @@ +#' ListPathway +#' List available pathways or pathway metadata +#' +#' @description +#' Reads the "SUMMARY" sheet from Pathway_Database_Combined.xlsx. +#' Behaviour depends on the \code{query} argument: +#' \itemize{ +#' \item \code{NULL}: returns the full summary table as a tibble. +#' \item \code{"Pathway"}: returns a sorted character vector of unique pathway names. +#' \item A valid pathway name (e.g. \code{"WNT"}, \code{"NOTCH"}): returns the +#' subset of rows for that pathway as a tibble. +#' } +#' +#' @param query Optional character string. One of \code{NULL}, \code{"Pathway"}, +#' or a valid pathway name. Default \code{NULL}. +#' @param drop_empty Logical; if \code{TRUE}, removes entries with 0 genes. +#' Default \code{TRUE}. +#' +#' @return A tibble (full table or pathway subset) or a character vector +#' (when \code{query = "Pathway"}). +#' +#' @importFrom readxl read_excel +#' +#' @examples +#' \dontrun{ +#' ListPathway() +#' ListPathway("Pathway") +#' ListPathway("WNT") +#' } +#' +#' @export +ListPathway <- function(query = NULL, drop_empty = TRUE) { + + if (!requireNamespace("readxl", quietly = TRUE)) { + stop("Package 'readxl' is required but not installed.") + } + + file_path <- system.file( + "extdata", + "Pathway_Database_Combined.xlsx", + package = "PathwayEmbed" + ) + if (file_path == "") { + stop("Pathway_Database_Combined.xlsx not found in extdata.") + } + + df <- readxl::read_excel(path = file_path, sheet = "SUMMARY") + + colnames(df) <- make.names(colnames(df)) + gene_col <- grep("^No\\.+Genes$", colnames(df), value = TRUE) + + if (drop_empty && length(gene_col) == 1) { + df <- df[df[[gene_col]] > 0, ] + } + + if (is.null(query)) return(df) + if (query == "Pathway") return(sort(unique(df$Pathway))) + if (query %in% df$Pathway) return(df[df$Pathway == query, ]) + + stop( + "Query not recognized. Use NULL, 'Pathway', or a valid pathway name:\n", + paste(sort(unique(df$Pathway)), collapse = ", ") + ) +} diff --git a/R/LoadPathway.R b/R/LoadPathway.R index 79f51d8..a44256f 100644 --- a/R/LoadPathway.R +++ b/R/LoadPathway.R @@ -1,27 +1,79 @@ #' LoadPathway #' -#' This function reads pathway data from the package's built-in Excel file. +#' Reads pathway gene data from the package's built-in Excel database and +#' returns a two-column data frame with gene symbols and their coefficients +#' for the requested species. +#' +#' @param Sheet.name A character string specifying the sheet name +#' (e.g. \code{"Hypoxia_6hr"}, \code{"HIPPO_heat"}). Use \code{ListPathway()} +#' to see available sheets. +#' @param species A character string specifying the species: either +#' \code{"human"} or \code{"mouse"}. Determines which gene symbol column is +#' used. Default \code{"human"}. +#' +#' @return A data frame with two columns: +#' \describe{ +#' \item{Gene_Symbol}{Gene symbols for the requested species.} +#' \item{Coefficient}{Numeric pathway coefficients.} +#' } +#' Rows with \code{NA} gene symbols are dropped. +#' +#' @importFrom readxl read_excel excel_sheets #' -#' @name LoadPathway -#' @param pathway A `character` string specifying the pathway name. -#' @return A data frame with pathway data. #' @examples -#' LoadPathway("Wnt") -#' @import readxl +#' \dontrun{ +#' LoadPathway("Hypoxia_6hr", "human") +#' LoadPathway("HIPPO_heat", "mouse") +#' } +#' #' @export -LoadPathway <- function(pathway) { - file_path <- system.file("extdata", "Pathway_Embedding.xlsx", package = "PathwayEmbed") +LoadPathway <- function(Sheet.name, species = "human") { + species <- tolower(species) + if (!species %in% c("human", "mouse")) { + stop("'species' must be either \"human\" or \"mouse\".") + } + + file_path <- system.file( + "extdata", "Pathway_Database_Combined.xlsx", + package = "PathwayEmbed" + ) if (file_path == "") { stop("Pathway data file not found. Ensure the package is installed correctly.") } - # Read the specified sheet - data <- readxl::read_excel(file_path, sheet = pathway) - # extract the molecules in the pathway - pathway.molecules <- c(data[["Molecules"]]) - # extract the coefficients of the molecules in the pathway - pathway.coefficients <- as.numeric(c(data[["Coefficients"]])) + sheets <- readxl::excel_sheets(file_path) + if (!Sheet.name %in% sheets) { + stop( + "Sheet '", Sheet.name, "' not found.\nAvailable sheets:\n", + paste(sheets, collapse = ", ") + ) + } + + df <- readxl::read_excel(file_path, sheet = Sheet.name) + + symbol_col <- if (species == "human") "Gene_Symbol_Human" else "Gene_Symbol_Mouse" + + # Check required columns exist + for (col in c(symbol_col, "Coefficient")) { + if (!col %in% colnames(df)) { + stop("Expected column '", col, "' not found in sheet '", Sheet.name, "'.") + } + } + + pathwaydata <- data.frame( + Gene_Symbol = df[[symbol_col]], + Coefficient = df$Coefficient, + stringsAsFactors = FALSE + ) + + # Drop rows with missing gene symbols + n_before <- nrow(pathwaydata) + pathwaydata <- pathwaydata[!is.na(pathwaydata$Gene_Symbol), ] + n_dropped <- n_before - nrow(pathwaydata) + if (n_dropped > 0) { + message(n_dropped, " row(s) with NA gene symbols removed.") + } - return(data) + return(pathwaydata) } diff --git a/R/PathwayMaxMin.R b/R/PathwayMaxMin.R index 71a8bdc..39e43b1 100644 --- a/R/PathwayMaxMin.R +++ b/R/PathwayMaxMin.R @@ -2,83 +2,52 @@ #' #' A function to obtain the hypothetical max and min activation status of selected pathway for a given scRNA seq data set #' -#' @name PathwayMaxMin -#' @import Seurat -#' @import tidyverse -#' @import viridis +#' @param expr_data Pre-processed gene-by-cell matrix (z-scored, pathway-filtered) +#' @param pathwaydata Pathway data outcome from LoadPathway() +#' +#' @return A data.frame with pathway.on and pathway.off values per gene +#' #' @importFrom matrixStats rowMins rowMaxs #' -#' @param x A Seurat Object. -#' @param pathway A `character` string specifying the pathway name. -#' @param scale.data A `logical` indicating whether to use scaled data (`scale.data = TRUE`) or normalized data. Default is `TRUE`. -#' @return The hypothetical value for Pathway on and off (max and min value for features) #' @examples -#' data(fake_test_object) # load the fake test data -#' PathwayMaxMin(fake_test_object, "Wnt") +#' \dontrun{ +#' pathwaydata <- LoadPathway("Hypoxia_6hr", "human") +#' matrix_filtered <- DataPreProcess(expr_data, pathwaydata) +#' PathwayMaxMin(matrix_filtered, pathwaydata) +#' } #' @export -PathwayMaxMin <- function(x, pathway, scale.data = TRUE) { - - # Define pathway parameters using LoadPathway - pathwaydata <- LoadPathway(pathway) # load pathway data - names <- c(pathwaydata[[1]]) # molecule names - pathway.on <- as.numeric(c(pathwaydata[[2]])) # coefficients - names(pathway.on) <- names - pathway.off <- -pathway.on # define off status - - # Use only genes present in Seurat object - valid_names <- intersect(names, rownames(x)) - if (length(valid_names) == 0) { - stop("No valid pathway genes found in the Seurat object.") - } - pathway.on <- pathway.on[valid_names] - pathway.off <- pathway.off[valid_names] - - # Extract expression data from the desired slot - x <- ScaleData(x, features = valid_names) - slot_use <- if (scale.data) "scale.data" else "data" - expr_data <- GetAssayData(x, assay = "RNA", slot = slot_use)[valid_names, , drop = FALSE] +PathwayMaxMin <- function(expr_data, pathwaydata) { - # Ensure it's a data frame - expr_data <- as.data.frame(expr_data) + # Load pathway coefficients + pathway_coef <- as.numeric(pathwaydata$Coefficient) + names(pathway_coef) <- pathwaydata$Gene_Symbol - # Max and min value for genes in the pathway - # Compute row-wise min and max values - ranges <- cbind( - rowMins(as.matrix(expr_data), na.rm = FALSE), - rowMaxs(as.matrix(expr_data), na.rm = FALSE) - ) - - # Scale the ON/OFF states to the extrema of these ranges for each features - for (i in seq_along(pathway.on)) { - feature_name <- names(pathway.on[i]) - - if (!feature_name %in% rownames(ranges)) { - warning(paste("Feature", feature_name, "not found in ranges!")) - next # Skip iteration if feature is missing - } - if (pathway.on[i] < 0) { - pathway.on[i] <- ranges[feature_name, 1] # min for ON - } else { - pathway.on[i] <- ranges[feature_name, 2] # max for ON - } - } - for (i in seq_along(pathway.off)) { # Safer indexing - feature_name <- names(pathway.off[i]) # Get feature name + # Keep only genes present in expr_data (already filtered) + pathway_coef <- pathway_coef[rownames(expr_data)] - if (!feature_name %in% rownames(ranges)) { # Check if feature exists in ranges - warning(paste("Feature", feature_name, "not found in ranges! Skipping...")) - next # Skip to the next iteration if missing - } + # Define ON/OFF + pathway_on <- pathway_coef + pathway_off <- -pathway_coef - # Assign min or max based on value - pathway.off[i] <- ifelse(pathway.off[i] < 0, - ranges[feature_name, 1], # Min for OFF - ranges[feature_name, 2]) # Max for OFF - } + # Compute row-wise min / max across cells + gene_min <- rowMins(expr_data, na.rm = TRUE) + gene_max <- rowMaxs(expr_data, na.rm = TRUE) + # Assign extrema based on coefficient sign + pathway_on <- ifelse(pathway_on < 0, gene_min, gene_max) + pathway_off <- ifelse(pathway_off < 0, gene_min, gene_max) - # Bind on and off states - pathway.stat <- data.frame(pathway.on,pathway.off) + # Combine results + pathway_stat <- data.frame( + pathway.on = pathway_on, + pathway.off = pathway_off + ) - return(pathway.stat) + return(pathway_stat) } + +# For negative coefficient genes, when pathway activation means a decrease in transcription, the pathway ON state should take the minimum gene expression value in the entire dataset, for each pathway feature. +# For positive coefficient genes, when pathway activation means n increase in transcription, the pathway ON state should take the maximum gene expression value in the entire dataset, for each pathway feature. +# For negative coefficient genes, when pathway activation means a decrease in transcription, the pathway OFF state should take the maximum gene expression value in the entire dataset, for each pathway feature. +# For positive coefficient genes, when pathway activation means an increase in transcription, the pathway OFF state should take the minimum gene expression value in the entire dataset, for each pathway feature. +# Finally, because pathway ON/OFF could embedded in the positive OR negative direction, when you pull out V1_max and V1_min, which should represent the ON and OFF states in some order, you should identify what that order is, and flips it as necessary (multiply by -1?) so that V1_max == pathway ON, and then normalize between pathway OFF/ON as 0->1 diff --git a/R/PlotPathway.R b/R/PlotPathway.R index d72d7f1..58ecc23 100644 --- a/R/PlotPathway.R +++ b/R/PlotPathway.R @@ -1,36 +1,61 @@ #' PlotPathway #' -#' A function to plot the Pathway activation status +#' Plot the activation status of a pathway across cell populations. +#' Creates a density plot of pathway activation (z-scored) for each group. +#' +#' @param to.plot A dataframe returned by PreparePlotData, containing at least: +#' \describe{ +#' \item{scale}{Z-scored pathway activation values.} +#' \item{group}{Grouping variable for coloring (e.g., genotype).} +#' } +#' @param pathway Character string indicating the pathway name (used in plot title). +#' @param group Column name in `to.plot` to group and color the plot by (e.g., "genotype"). +#' @param color Character vector of colors for each group (fill and outline). Length must match number of unique groups. +#' +#' @return A ggplot2 object showing density distributions of pathway activity per group. #' -#' @name PlotPathway -#' @param to.plot A data frame with pathway activation values genereated by PreparePlotData -#' @param pathway A character string indicating the pathway name. -#' @param group Column name to group and color by (e.g., genotype). -#' @param color A character vector of colors to use for fill and outline. -#' @return A ggplot object. #' @examples +#' \dontrun{ #' data(fake_to_plot) -#' PlotPathway(to.plot = fake_to_plot,"Wnt","genotype",color = c("#ae282c", "#2066a8")) +#' PlotPathway(to.plot = fake_to_plot, +#' pathway = "Wnt", +#' group = "genotype", +#' color = c("#ae282c", "#2066a8")) +#' } +#' @import ggplot2 #' @export -PlotPathway <- function (to.plot, pathway, group, color){ +PlotPathway <- function(to.plot, pathway, group, color) { - #color has to be assigned - plot.total <- ggplot(data=to.plot, - aes(x=scale, - group = .data[[group]], - fill= .data[[group]], - color= .data[[group]]))+ + # Safety checks + if (!group %in% colnames(to.plot)) { + stop(paste("Grouping column", group, "not found in to.plot")) + } + if (!"scale" %in% colnames(to.plot)) { + stop("Column 'scale' not found in to.plot. Make sure to use PreparePlotData() first.") + } + if (length(color) < length(unique(to.plot[[group]]))) { + warning("Length of 'color' vector is shorter than the number of groups. Some groups may not be colored correctly.") + } - geom_density(alpha = 0.5) + # Example: Density plot + # Create density plot + plot.total <- ggplot(data = to.plot, + aes(x = scale, + group = .data[[group]], + fill = .data[[group]], + color = .data[[group]])) + + geom_density(alpha = 0.5) + # Semi-transparent density per group labs(title = paste(pathway, "Pathway"), - x = "Relative Transduction State", + x = "Relative Transduction State (z-score)", y = "Population Density") + - scale_fill_manual(values = color) + # Set fixed colors - scale_color_manual(values = color) + - theme_classic() + - geom_vline(xintercept=0, linetype="dotted", - color = "black", size=0.5) + scale_fill_manual(values = color) + # Assign fixed fill colors + scale_color_manual(values = color) + # Assign fixed outline colors + theme_classic() + # Clean theme + geom_vline(xintercept = 0, # Reference line at z-score 0 + linetype = "dotted", + color = "black", + size = 0.5) + # Return the ggplot object return(plot.total) } diff --git a/R/PreparePlotData.R b/R/PreparePlotData.R index 05e877c..87be723 100644 --- a/R/PreparePlotData.R +++ b/R/PreparePlotData.R @@ -1,44 +1,74 @@ -#' A function to prepare the signal transduction dataframe for plotting -#' @name PreparePlotData -#' @import Seurat -#' @import RColorBrewer -#' @import ggplot2 -#' @import cowplot -#' @import tidyverse -#' @import viridis -#' @import matrixStats +#' PreparePlotData +#' +#' Prepares a tidy data frame of pathway activity scores per cell for +#' downstream plotting with \code{PlotPathway()} or \code{CalculatePercentage()}. +#' Accepts either a plain metadata data frame or a Seurat object. +#' +#' @param x A metadata data frame (rows = cells, columns = metadata fields) +#' or a Seurat object. Must contain the column specified by \code{group}. +#' @param score A named numeric vector of per-cell scores from +#' \code{ComputeCellData()}. Names must be cell IDs matching rownames of \code{x}. +#' @param group A character string giving the column name in \code{x} metadata +#' to use for grouping (e.g. \code{"genotype"}, \code{"Age"}). +#' @param Seurat.object Logical; set \code{TRUE} if \code{x} is a Seurat object. +#' Default \code{FALSE}. +#' +#' @return A data frame with one row per cell and three columns: +#' \describe{ +#' \item{normalized}{Normalized pathway activity score in \[0, 1]\ from +#' \code{ComputeCellData()}.} +#' \item{scale}{Z-scored pathway activity across all cells.} +#' \item{}{The grouping variable, named after the \code{group} argument.} +#' } #' -#' @param x A `Seurat` object containing single-cell RNA sequencing data. -#' @param final_mds A 'dataframe' output from ComputeCellData. -#' @param group group for the comparision -#' @return data for plotting #' @examples -#' data(fake_test_object) -#' data(fake_final_mds) -#' PreparePlotData(fake_test_object, fake_final_mds, "genotype") +#' \dontrun{ +#' # Using a plain metadata data frame +#' plotdata <- PreparePlotData(metadata_df, scores, "genotype") +#' +#' # Using a Seurat object +#' plotdata <- PreparePlotData(seurat_obj, scores, "orig.ident", Seurat.object = TRUE) +#' } +#' #' @export -PreparePlotData <- function(x, final_mds, group){ +PreparePlotData <- function(x, score, group, Seurat.object = FALSE) { - # Make a data frame from final_mds - to.plot <- as.data.frame(final_mds) + # Build score data frame with explicit column name + to.plot <- data.frame(normalized = as.numeric(score), + row.names = names(score)) - # Sometimes, the rownames changed in last step, to make them consistent with meta.data - rownames(to.plot) <- gsub("\\.", "-", rownames(to.plot)) + # Extract metadata + if (Seurat.object) { + if (!requireNamespace("Seurat", quietly = TRUE)) { + stop("Seurat.object = TRUE requires the Seurat package.") + } + meta.data <- x@meta.data + } else if (is.data.frame(x)) { + meta.data <- x + } else { + stop("x must be a data frame or a Seurat object.") + } - # Add group into the dataframe and assign group - to.plot[[group]] <- NA - meta.data <- x@meta.data - to.plot[rownames(meta.data),][[group]] <- as.character(meta.data[[group]]) + # Validate group column exists + if (!group %in% colnames(meta.data)) { + stop("Column '", group, "' not found in metadata.") + } - # Get ride of non-cell rows - to.plot <- to.plot[!is.na(to.plot[[group]]), ] + # Match cell IDs + matched <- intersect(rownames(to.plot), rownames(meta.data)) + if (length(matched) == 0) { + stop("No overlapping cell IDs between score and metadata.") + } + if (length(matched) < nrow(to.plot)) { + message(nrow(to.plot) - length(matched), " cell(s) in score not found ", + "in metadata and will be dropped.") + } - # Scale - to.plot$scale <- scale(to.plot$normalized,center = T)[,1] + to.plot <- to.plot[matched, , drop = FALSE] + to.plot[[group]] <- as.character(meta.data[matched, group]) + # Z-score the normalized scores + to.plot$scale <- as.numeric(scale(to.plot$normalized, center = TRUE)) return(to.plot) } - - - diff --git a/R/data_documentation.R b/R/data_documentation.R index e5f14f9..4502a7b 100644 --- a/R/data_documentation.R +++ b/R/data_documentation.R @@ -1,6 +1,6 @@ #' Example Seurat Object for Testing #' -#' A simulated Seurat object with fake gene expression data for the Wnt signaling pathway. +#' A simulated Seurat object with synthetic gene expression data for the Wnt signaling pathway. #' This Seurat object contains gene expression data from simulated cells with Wnt positive #' and negative gene expression values. #' @@ -12,44 +12,138 @@ #' \item{cells}{Cell names, labeled as Cell1, Cell2, ..., CellN.} #' } #' @source Simulated for demonstration purposes. -#' @usage data(fake_test_object) -"fake_test_object" +#' @usage data(synthetic_test_object) +"synthetic_test_object" +#' Example Matrix for Testing +#' +#' A numeric matrix containing single-cell gene expression data for demonstration purposes in the PathwayEmbed package. +#' Rows correspond to genes and columns correspond to individual cells. +#' +#' @format A numeric matrix with genes (rows) and cells (columns). +#' \describe{ +#' \item{Rows}{18 genes (e.g. "Lgr5", "Rnf43", "Lrp5", "Fzd6" ...)} +#' \item{Columns}{2000 cells (named "Cell1", "Cell2", ...)} +#' \item{Values}{35830 nonzero entries, representing expression values (numeric)} +#' } +#' @source Simulated for demonstration purposes. +#' @details +#' This is a synthetic dataset created for testing and demonstration purposes. +#' It mimics the structure of a gene-by-cell expression matrix used in single-cell +#' RNA sequencing analysis. +#' +#' @examples +#' data(synthetic_test_matrix) +"synthetic_test_matrix" + +#' synthetic metadata for test cells +#' +#' A toy metadata table corresponding to the columns of `synthetic_test_matrix`. +#' Each row represents a single cell with associated metadata. +#' +#' @format A data frame with 2000 rows and 4 variables: +#' \describe{ +#' \item{orig.ident}{Character, project identifier} +#' \item{nCount_RNA}{Integer, total RNA counts per cell} +#' \item{nFeature_RNA}{Integer, number of detected features (genes) per cell} +#' \item{genotype}{Factor/character, cell genotype (e.g., "WT", "Mutant")} +#' } +#' +#' @details +#' This dataset provides toy cell-level metadata designed to accompany +#' `synthetic_test_matrix`. It mimics the structure of single-cell +#' experiment metadata used in analysis frameworks such as Seurat. +#' +#' @examples +#' data(synthetic_test_metadata) +"synthetic_test_metadata" -#' Example Cell Status and Normalized Data + +#' Expanded Example Matrix for Testing (100 genes) #' -#' A dataset generated by `ComputeCellData` applied to `fake_test_object`. -#' Contains cell status and normalized values. +#' A numeric matrix containing single-cell gene expression data for +#' demonstration and testing in the PathwayEmbed package. +#' This expanded version contains 100 genes: the original 18 Wnt-pathway +#' genes from \code{synthetic_test_matrix} (rows 1–18, values preserved +#' exactly) plus 82 additional randomly expressed genes drawn from +#' housekeeping, cell-cycle, transcription-factor, Notch, MAPK/ERK, +#' TGF-β/BMP, and adhesion gene sets. #' -#' @format A data frame with the following columns: +#' @format A numeric matrix with 100 rows (genes) and 2000 columns (cells): #' \describe{ -#' \item{V1}{A numerical value presenting the status of the cell} -#' \item{normalized}{Numerical value representing normalized data} +#' \item{Rows}{100 genes. Rows 1–18 are the original Wnt pathway genes +#' with their original expression values unchanged. Rows 19–100 are randomly expressed genes from +#' housekeeping, cell-cycle, TF, Notch, MAPK/ERK, TGF-β/BMP, and +#' adhesion panels.} +#' \item{Columns}{2000 cells named \code{"Cell1"} through +#' \code{"Cell2000"}, matching \code{synthetic_test_matrix}.} +#' \item{Values}{Non-negative integer expression counts. Rows 1–18 are +#' taken directly from \code{synthetic_test_matrix}. Rows 19–100 are +#' simulated via a zero-inflated negative-binomial distribution +#' (mu = 2.5, size = 0.8, ~35 \% non-zero density).} #' } -#' @usage data(fake_final_mds) +#' +#' @source Simulated for demonstration purposes, expanded from +#' \code{synthetic_test_object}. +#' +#' @details +#' Because the first 18 rows are byte-for-byte identical to +#' \code{synthetic_test_matrix}, any existing code that subsets to the +#' Wnt gene panel will return the same results as before. The 82 extra +#' genes carry no planted biological signal; they are intended for +#' testing functions that operate on larger or multi-pathway gene panels, +#' such as dimensionality reduction, clustering, or multi-pathway scoring. +#' +#' @seealso \code{\link{synthetic_test_matrix}}, +#' \code{\link{synthetic_test_object_100}} +#' #' @examples -#' data(fake_final_mds) -#' head(fake_final_mds) -#' @keywords datasets -"fake_final_mds" +#' data(synthetic_test_matrix_100) +#' dim(synthetic_test_matrix_100) # 100 x 2000 +#' rownames(synthetic_test_matrix_100)[1:18] # original Wnt genes +#' mean(synthetic_test_matrix_100 > 0) # ~0.35 non-zero density +"synthetic_test_matrix_100" -#' Example Processed Data for Plotting + +#' Expanded Example Seurat Object for Testing (100 genes) #' -#' A dataset generated by running `PreparePlotData` on `fake_test_object` and `fake_final_mds`. -#' Contains processed data ready for visualization, with the following features: +#' A simulated Seurat object built from \code{synthetic_test_matrix_100} +#' and \code{synthetic_test_metadata}. It is the 100-gene counterpart +#' of \code{synthetic_test_object} and is structurally identical except +#' for the larger gene panel. The original 18 Wnt genes and their +#' expression values are fully preserved. #' -#' @format A data frame with the following columns: +#' @format A Seurat object containing: #' \describe{ -#' \item{V1}{A numerical or categorical value depending on the specific analysis} -#' \item{normalized}{Normalized numerical value representing the cell's data} -#' \item{genotype}{Group classification of the cell (e.g., "WT", "Mutant")} -#' \item{scale}{Scaled data for visualization purposes} +#' \item{assays}{A single \code{RNA} assay storing the 100 × 2000 +#' count matrix (\code{synthetic_test_matrix_100}).} +#' \item{meta.data}{Cell-level metadata with four columns: +#' \code{orig.ident}, \code{nCount_RNA}, \code{nFeature_RNA}, and +#' \code{genotype} (WT vs. Mutant). See +#' \code{\link{synthetic_test_metadata}}.} +#' \item{features}{100 genes: 18 original Wnt genes (rows 1–18) plus +#' 82 randomly expressed genes from housekeeping, cell-cycle, TF, +#' Notch, MAPK/ERK, TGF-β/BMP, and adhesion panels (rows 19–100).} +#' \item{cells}{2000 cells named \code{"Cell1"} … \code{"Cell2000"}.} #' } -#' @usage data(fake_to_plot) +#' +#' @source Expanded from \code{synthetic_test_object} for demonstration +#' purposes. +#' +#' @details +#' Created with \code{CreateSeuratObject(min.cells = 0, min.features = 0)} +#' so every gene and cell in the underlying matrix is retained. +#' Compatible with Seurat v4 and v5 (\code{SeuratObject} >= 4.1). +#' +#' @seealso \code{\link{synthetic_test_object}}, +#' \code{\link{synthetic_test_matrix_100}}, +#' #' @examples -#' data(fake_to_plot) -#' head(fake_to_plot) -#' @keywords datasets -"fake_to_plot" +#' data(synthetic_test_object_100) +#' synthetic_test_object_100 +#' Seurat::Idents(synthetic_test_object_100) <- "genotype" +#' table(Seurat::Idents(synthetic_test_object_100)) # 1000 WT, 1000 Mutant +"synthetic_test_object_100" + diff --git a/README.md b/README.md index 6cc0937..c8301a2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # PathwayEmbed -## We are focusing on 1-D embeddings of pathway state. +## We are focusing on estimating intracellular signal transduction states vis distance embedding # PathwayEmbed @@ -33,18 +33,33 @@ remotes::install_github("RaredonLab/PathwayEmbed") library(PathwayEmbed) # Load example data included with the package -data(fake_test_object) +data("synthetic_test_object_100") +data("synthetic_test_metadata") + +# Check what pathways are availabel in the pre-constructed table +ListPathway() # summary page +ListPathway("Pathway") # what pathways are available +ListPathway("WNT") # what coefficient tables are available + +# Load pre-constructed pathway coefficient tables +Wnt_12h <- LoadPathway("WNT3A_12H_ACTIVATION", "mouse") + +# Input data preprocess +matrix_12h <- DataPreProcess(synthetic_test_object_100, Wnt_12h, Seurat.object = TRUE) + +# Determine the global reference (ON and OFF) +pathwaystat_12h <- PathwayMaxMin(matrix_12h, Wnt_12h) # Compute pathway data -mds_results <- ComputeCellData(fake_test_object, pathway = "Wnt", distance.method = "manhattan", batch.size = 100) +score_12h <- ComputeCellData(matrix_12h, pathwaystat_12h) # Prepare data for plotting -plot_data <- PreparePlotData(fake_test_object, mds_results, group = "genotype") +plot_data_12h <- PreparePlotData(synthetic_test_metadata, score_12h, group = "genotype") # Plot pathway activation -PlotPathway(to.plot = plot_data, pathway = "Wnt", group = "genotype", color = c("#ae282c", "#2066a8")) +PlotPathway(plot_data_12h, "12hr Wnt", "genotype", c("#ae282c", "#2066a8")) # Calculate percentage and do comparison between two groups (optional) -CalculatePercentage(to.plot = plot_data, group_var = "genotype") + CalculatePercentage(to.plot = plot_data_12h, group_var = "genotype") ``` diff --git a/_pkgdown.yml b/_pkgdown.yml new file mode 100644 index 0000000..4abba9d --- /dev/null +++ b/_pkgdown.yml @@ -0,0 +1,10 @@ +url: https://raredonlab.github.io/PathwayEmbed/ + +home: + title: "PathwayEmbed" + description: "Quantifying and visualizing intracellular signaling pathway activation from transcriptomic data." + +template: + bootstrap: 5 + bootswatch: flatly # optional but adds a nice theme + diff --git a/data-raw/Generate expanded synthetic data.R b/data-raw/Generate expanded synthetic data.R new file mode 100644 index 0000000..a057515 --- /dev/null +++ b/data-raw/Generate expanded synthetic data.R @@ -0,0 +1,170 @@ +# data-raw/generate_expanded_synthetic_data.R +# +# Expands the existing synthetic_test_object (18 Wnt genes × 2000 cells) +# to a 100-gene version by appending 82 additional randomly expressed genes. + +set.seed(42) + +library(SeuratObject) # CreateSeuratObject, GetAssayData +# Seurat v5: replace with library(Seurat) + +# ============================================================================= +# 1. Load the existing object +# ============================================================================= + +load("data/synthetic_test_object.rda") # loads: synthetic_test_object + +# Extract the original count matrix and metadata +orig_counts <- as.matrix(GetAssayData(synthetic_test_object, assay = "RNA", layer = "counts")) +orig_meta <- synthetic_test_object@meta.data + +n_cells <- ncol(orig_counts) # 2000 +orig_genes <- rownames(orig_counts) # 18 actual Wnt genes confirmed from object: +# Lgr5, Rnf43, Lrp5, Lrp6, Fzd6, +# Ctnnb1, Gsk3b, Ccnd1, Axin2, Myc, +# Lef1, Tcf7, Tcf7l1, Tcf7l2, Tle1, +# Apc, Csnk1a1, Dvl1 +cell_names <- colnames(orig_counts) # Cell1 … Cell2000 + + +# ============================================================================= +# 2. Define 82 additional genes (no pathway preference, random expression) +# ============================================================================= + +extra_genes <- c( + # Housekeeping / metabolic (20) + "Actb", "Gapdh", "Hsp90ab1","Eef1a1", "Rpl13a", + "Rps18", "Npm1", "Hspa8", "Pkm", "Ldha", + "Eno1", "Pgk1", "Tpi1", "Aldoa", "Tubb4b", + "Vim", "Anxa2", "S100a6", "Ftl1", "Hnrnpa1", + + # Cell cycle / proliferation (15) + "Mki67", "Top2a", "Pcna", "Cdk1", "Ccne1", + "Cdc20", "Bub1", "Aurka", "Ccnb1", "E2f1", + "Mcm2", "Mcm6", "Rrm2", "Cdk4", "Cdk6", + + # Transcription factors / signalling (15) + "Stat3", "Nfkb1", "Jun", "Fos", "Egr1", + "Klf4", "Sox2", "Nanog", "Pou5f1", "Runx1", + "Twist1", "Snai1", "Zeb1", "Smad2", "Smad4", + + # Notch pathway (10) + "Notch1", "Notch2", "Dll1", "Dll4", "Jag1", + "Hes1", "Hey1", "Nrarp", "Maml1", "Rbpj", + + # MAPK / ERK (10) + "Kras", "Braf", "Map2k1", "Mapk1", "Mapk3", + "Dusp6", "Spry2", "Egfr", "Grb2", "Sos1", + + # TGF-b / BMP (7) + "Tgfb1", "Tgfb2", "Bmp2", "Bmp4", "Bmpr2", + "Smad1", "Id1", + + # Adhesion / ECM (5) + "Cdh1", "Cdh2", "Fn1", "Itgb1", "Vcam1" +) + +stopifnot(length(extra_genes) == 82) +stopifnot(length(unique(c(orig_genes, extra_genes))) == 100) # no overlaps + +# ============================================================================= +# 3. Simulate expression for the 82 new genes (fully random, no structure) +# Negative-binomial counts, zero-inflated to ~35 % non-zero density, +# matching realistic scRNA-seq dropout for a broader gene panel. +# ============================================================================= + +extra_counts <- matrix( + rnbinom(82 * n_cells, mu = 2.5, size = 0.8), + nrow = 82, + ncol = n_cells, + dimnames = list(extra_genes, cell_names) +) + +# Zero-inflate: silence 65 % of currently non-zero entries +nz_idx <- which(extra_counts > 0) +silence_idx <- sample(nz_idx, size = round(0.65 * length(nz_idx))) +extra_counts[silence_idx] <- 0L + +cat(sprintf( + "Extra genes matrix: %d genes x %d cells | %.1f %% non-zero\n", + nrow(extra_counts), ncol(extra_counts), + 100 * mean(extra_counts > 0) +)) + +# ============================================================================= +# 4. Stack: original 18 rows (exact values) on top + 82 new rows below +# ============================================================================= + +synthetic_test_matrix_100 <- rbind(orig_counts, extra_counts) + +stopifnot(nrow(synthetic_test_matrix_100) == 100) +stopifnot(ncol(synthetic_test_matrix_100) == 2000) +# Sanity check: original rows are untouched +stopifnot(identical(synthetic_test_matrix_100[orig_genes, ], orig_counts)) + +cat(sprintf( + "Final matrix: %d genes x %d cells | %d non-zero entries (%.1f %%)\n", + nrow(synthetic_test_matrix_100), + ncol(synthetic_test_matrix_100), + sum(synthetic_test_matrix_100 > 0), + 100 * mean(synthetic_test_matrix_100 > 0) +)) + +# ============================================================================= +# 5. Metadata — reuse original, update nCount/nFeature to reflect new matrix +# ============================================================================= + +synthetic_test_metadata_100 <- orig_meta +synthetic_test_metadata_100$nCount_RNA <- colSums(synthetic_test_matrix_100) +synthetic_test_metadata_100$nFeature_RNA <- colSums(synthetic_test_matrix_100 > 0) + +cat("Metadata head:\n") +print(head(synthetic_test_metadata_100)) +cat(sprintf("Genotype: WT=%d Mutant=%d\n", + sum(synthetic_test_metadata_100$genotype == "WT"), + sum(synthetic_test_metadata_100$genotype == "Mutant"))) + +# ============================================================================= +# 6. Seurat object +# ============================================================================= + +synthetic_test_object_100 <- CreateSeuratObject( + counts = synthetic_test_matrix_100, + meta.data = synthetic_test_metadata_100, + project = "SyntheticProject100", + min.cells = 0, + min.features = 0 +) + +# Normalize: log-normalize to total counts per 10,000 (Seurat default) +synthetic_test_object_100 <- NormalizeData( + synthetic_test_object_100, + normalization.method = "LogNormalize", + scale.factor = 10000, + assay = "RNA" +) + +# Scale: z-score all genes, stored in the "scale.data" slot +synthetic_test_object_100 <- ScaleData( + synthetic_test_object_100, + features = rownames(synthetic_test_object_100), # all 100 genes + assay = "RNA" +) + + +cat("\nSeurat object:\n") +print(synthetic_test_object_100) + +# ============================================================================= +# 7. Save to data/ +# ============================================================================= + +usethis::use_data( + synthetic_test_matrix_100, + synthetic_test_metadata_100, + synthetic_test_object_100, + overwrite = TRUE, + compress = "xz" +) + +message("\nDone — 3 objects saved to data/") diff --git a/data/fake_final_mds.rda b/data/fake_final_mds.rda deleted file mode 100644 index cf60cc5..0000000 Binary files a/data/fake_final_mds.rda and /dev/null differ diff --git a/data/fake_test_object.rda b/data/fake_test_object.rda deleted file mode 100644 index 34fd240..0000000 Binary files a/data/fake_test_object.rda and /dev/null differ diff --git a/data/fake_to_plot.rda b/data/fake_to_plot.rda deleted file mode 100644 index 73c3e8a..0000000 Binary files a/data/fake_to_plot.rda and /dev/null differ diff --git a/data/synthetic_test_matrix.rda b/data/synthetic_test_matrix.rda new file mode 100644 index 0000000..3f15d00 Binary files /dev/null and b/data/synthetic_test_matrix.rda differ diff --git a/data/synthetic_test_matrix_100.rda b/data/synthetic_test_matrix_100.rda new file mode 100644 index 0000000..e60220a Binary files /dev/null and b/data/synthetic_test_matrix_100.rda differ diff --git a/data/synthetic_test_metadata.rda b/data/synthetic_test_metadata.rda new file mode 100644 index 0000000..16eee77 Binary files /dev/null and b/data/synthetic_test_metadata.rda differ diff --git a/data/synthetic_test_object.rda b/data/synthetic_test_object.rda new file mode 100644 index 0000000..6690485 Binary files /dev/null and b/data/synthetic_test_object.rda differ diff --git a/data/synthetic_test_object_100.rda b/data/synthetic_test_object_100.rda new file mode 100644 index 0000000..2230819 Binary files /dev/null and b/data/synthetic_test_object_100.rda differ diff --git a/doc/beta_catenin_ko.R b/doc/beta_catenin_ko.R index ed0607c..2caebf8 100644 --- a/doc/beta_catenin_ko.R +++ b/doc/beta_catenin_ko.R @@ -53,12 +53,19 @@ merged <- ScaleData( features = VariableFeatures(object = merged) ) +# Get genes x cell matrix +merged_data <- as.matrix(GetAssayData(merged, assay = "RNA", slot = "data")) + +# Get metadata matrix +merged_metadata <- merged@meta.data + + ## ----------------------------------------------------------------------------- # Compute Wnt pathway score -wnt_scores <- ComputeCellData(merged, "Wnt", distance.method = "manhattan", batch.size = 1000) +wnt_scores <- ComputeCellData(merged_data, "Wnt", distance.method = "manhattan", batch.size = 1000) # Prepare for plotting -plot_data <- PreparePlotData(merged, wnt_scores, group = "sample") +plot_data <- PreparePlotData(merged_metadata, wnt_scores, group = "sample") # Plot PlotPathway(plot_data, pathway = "Wnt", group = "sample", c("#f4a4a4", "#6baed6")) diff --git a/doc/beta_catenin_ko.Rmd b/doc/beta_catenin_ko.Rmd index 865a162..07b4d24 100644 --- a/doc/beta_catenin_ko.Rmd +++ b/doc/beta_catenin_ko.Rmd @@ -15,6 +15,9 @@ knitr::opts_chunk$set( ) ``` +## Overview +This vignette shows the application of PathwayEmbed in a beta-catenin perturbed system where Ctnnb1 upstream enhancer is depleted in instestinal epithelia. Refinements of coefficients is flexible and should be case-depedent. +References: Hua et al. A Ctnnb1 enhancer transcriptionally regulates Wnt signaling dosage to balance homeostasis and tumorigenesis of intestinal epithelia. Elife. 2024 Sep 25;13:RP98238. doi: 10.7554/eLife.98238. PMID: 39320349; PMCID: PMC11424096. ## Load Packages and Download Data from Online Source ```{r setup} @@ -51,7 +54,7 @@ merged[["RNA"]] <- JoinLayers(merged[["RNA"]]) ``` ## Preprocessing -Get normalized and scaled data +Get normalized and scaled data and convert them to matrix format ```{r} # Normalize and scale merged <- NormalizeData( @@ -70,15 +73,22 @@ merged <- ScaleData( object = merged, features = VariableFeatures(object = merged) ) + +# Get genes x cell matrix +merged_data <- as.matrix(GetAssayData(merged, assay = "RNA", slot = "data")) + +# Get metadata matrix +merged_metadata <- merged@meta.data + ``` ## Wnt Pathway Scoring and Visualization Using Pathway Embed ```{r} # Compute Wnt pathway score -wnt_scores <- ComputeCellData(merged, "Wnt", distance.method = "manhattan", batch.size = 1000) +wnt_scores <- ComputeCellData(merged_data, "Wnt", distance.method = "manhattan", batch.size = 1000) # Prepare for plotting -plot_data <- PreparePlotData(merged, wnt_scores, group = "sample") +plot_data <- PreparePlotData(merged_metadata, wnt_scores, group = "sample") # Plot PlotPathway(plot_data, pathway = "Wnt", group = "sample", c("#f4a4a4", "#6baed6")) diff --git a/doc/beta_catenin_ko.html b/doc/beta_catenin_ko.html index 5ffceee..3a9d65c 100644 --- a/doc/beta_catenin_ko.html +++ b/doc/beta_catenin_ko.html @@ -341,6 +341,17 @@

Beta-Catenin Knockout Analysis with +
+

Overview

+

This vignette shows the application of PathwayEmbed in a beta-catenin +perturbed system where Ctnnb1 upstream enhancer is depleted in +instestinal epithelia. Refinements of coefficients is flexible and +should be case-depedent. References: Hua et al. A Ctnnb1 enhancer +transcriptionally regulates Wnt signaling dosage to balance homeostasis +and tumorigenesis of intestinal epithelia. Elife. 2024 Sep +25;13:RP98238. doi: 10.7554/eLife.98238. PMID: 39320349; PMCID: +PMC11424096.

+

Load Packages and Download Data from Online Source

library(PathwayEmbed)
@@ -387,7 +398,7 @@ 

Data Preparation

Preprocessing

-

Get normalized and scaled data

+

Get normalized and scaled data and convert them to matrix format

# Normalize and scale
 merged <- NormalizeData(
   object = merged,
@@ -407,178 +418,180 @@ 

Preprocessing

object = merged, features = VariableFeatures(object = merged) ) -#> Centering and scaling data matrix
+#> Centering and scaling data matrix + +# Get genes x cell matrix +merged_data <- as.matrix(GetAssayData(merged, assay = "RNA", slot = "data")) +#> Warning: The `slot` argument of `GetAssayData()` is deprecated as of SeuratObject 5.0.0. +#> ℹ Please use the `layer` argument instead. +#> This warning is displayed once every 8 hours. +#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was +#> generated. +#> Warning in asMethod(object): sparse->dense coercion: allocating vector of size +#> 3.3 GiB + +# Get metadata matrix +merged_metadata <- merged@meta.data

Wnt Pathway Scoring and Visualization Using Pathway Embed

# Compute Wnt pathway score
-wnt_scores <- ComputeCellData(merged, "Wnt", distance.method = "manhattan", batch.size = 1000)
-#> Centering and scaling data matrix
-#> Warning: Different features in new layer data than already exists for
-#> scale.data
-#> Warning: The `slot` argument of `GetAssayData()` is deprecated as of SeuratObject 5.0.0.
-#> ℹ Please use the `layer` argument instead.
-#> ℹ The deprecated feature was likely used in the PathwayEmbed package.
-#>   Please report the issue to the authors.
-#> This warning is displayed once every 8 hours.
-#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
-#> generated.
-#> Centering and scaling data matrix
-#> Processing batch 1
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 1 processed with 1000 cells
-#> Processing batch 2
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 2 processed with 1000 cells
-#> Processing batch 3
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 3 processed with 1000 cells
-#> Processing batch 4
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 4 processed with 1000 cells
-#> Processing batch 5
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 5 processed with 1000 cells
-#> Processing batch 6
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 6 processed with 1000 cells
-#> Processing batch 7
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 7 processed with 1000 cells
-#> Processing batch 8
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 8 processed with 1000 cells
-#> Processing batch 9
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 9 processed with 1000 cells
-#> Processing batch 10
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 10 processed with 1000 cells
-#> Processing batch 11
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 11 processed with 1000 cells
-#> Processing batch 12
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 12 processed with 1000 cells
-#> Processing batch 13
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 13 processed with 1000 cells
-#> Processing batch 14
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 14 processed with 1000 cells
-#> Processing batch 15
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 15 processed with 1000 cells
-#> Processing batch 16
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 16 processed with 1000 cells
-#> Processing batch 17
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 17 processed with 1000 cells
-#> Processing batch 18
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 18 processed with 1000 cells
-#> Processing batch 19
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 19 processed with 1000 cells
-#> Processing batch 20
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 20 processed with 1000 cells
-#> Processing batch 21
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 21 processed with 1000 cells
-#> Processing batch 22
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 22 processed with 1000 cells
-#> Processing batch 23
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 23 processed with 1000 cells
-#> Processing batch 24
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 24 processed with 1000 cells
-#> Processing batch 25
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 25 processed with 1000 cells
-#> Processing batch 26
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 26 processed with 1000 cells
-#> Processing batch 27
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 27 processed with 1000 cells
-#> Processing batch 28
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 28 processed with 735 cells
-
-# Prepare for plotting
-plot_data <- PreparePlotData(merged, wnt_scores, group = "sample")
-
-# Plot
-PlotPathway(plot_data, pathway = "Wnt", group = "sample", c("#f4a4a4", "#6baed6"))
-

+wnt_scores <- ComputeCellData(merged_data, "Wnt", distance.method = "manhattan", batch.size = 1000) +#> Processing batch 1 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 1 processed with 1000 cells +#> Processing batch 2 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 2 processed with 1000 cells +#> Processing batch 3 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 3 processed with 1000 cells +#> Processing batch 4 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 4 processed with 1000 cells +#> Processing batch 5 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 5 processed with 1000 cells +#> Processing batch 6 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 6 processed with 1000 cells +#> Processing batch 7 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 7 processed with 1000 cells +#> Processing batch 8 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 8 processed with 1000 cells +#> Processing batch 9 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 9 processed with 1000 cells +#> Processing batch 10 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 10 processed with 1000 cells +#> Processing batch 11 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 11 processed with 1000 cells +#> Processing batch 12 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 12 processed with 1000 cells +#> Processing batch 13 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 13 processed with 1000 cells +#> Processing batch 14 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 14 processed with 1000 cells +#> Processing batch 15 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 15 processed with 1000 cells +#> Processing batch 16 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 16 processed with 1000 cells +#> Processing batch 17 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 17 processed with 1000 cells +#> Processing batch 18 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 18 processed with 1000 cells +#> Processing batch 19 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 19 processed with 1000 cells +#> Processing batch 20 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 20 processed with 1000 cells +#> Processing batch 21 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 21 processed with 1000 cells +#> Processing batch 22 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 22 processed with 1000 cells +#> Processing batch 23 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 23 processed with 1000 cells +#> Processing batch 24 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 24 processed with 1000 cells +#> Processing batch 25 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 25 processed with 1000 cells +#> Processing batch 26 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 26 processed with 1000 cells +#> Processing batch 27 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 27 processed with 1000 cells +#> Processing batch 28 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 28 processed with 735 cells + +# Prepare for plotting +plot_data <- PreparePlotData(merged_metadata, wnt_scores, group = "sample") + +# Plot +PlotPathway(plot_data, pathway = "Wnt", group = "sample", c("#f4a4a4", "#6baed6"))
+


 # Show percentage of high-scoring cells (optional)
 CalculatePercentage(plot_data, "sample")
 #> # A tibble: 2 × 4
 #>   group percentage_on percentage_off cohens_d
 #>   <chr>         <dbl>          <dbl>    <dbl>
-#> 1 KO             31.9           68.1   -0.447
-#> 2 WT             47.0           53.0   -0.447
+#> 1 KO 32.8 67.2 -0.460 +#> 2 WT 48.6 51.4 -0.460 diff --git a/doc/examples.R b/doc/examples.R index 19d3317..02e1e3c 100644 --- a/doc/examples.R +++ b/doc/examples.R @@ -6,22 +6,23 @@ knitr::opts_chunk$set( ## ----setup-------------------------------------------------------------------- library(PathwayEmbed) -# Load the example Seurat object included in the package -data(fake_test_object) +# Load the example gene expression matrix included in the package +data(fake_test_matrix) ## ----------------------------------------------------------------------------- # Calculate pathway activation using MDS # Default batch.size is set to 1000 mds_results <- ComputeCellData( - fake_test_object, + fake_test_matrix, pathway = "Wnt", - distance.method = "manhattan" + distance.method = "manhattan", + scale.data = TRUE ) ## ----------------------------------------------------------------------------- # Format MDS results and metadata for plotting plot_data <- PreparePlotData( - fake_test_object, + fake_test_metadata, mds_results, group = "genotype" ) diff --git a/doc/examples.Rmd b/doc/examples.Rmd index c906b4b..d9910ab 100644 --- a/doc/examples.Rmd +++ b/doc/examples.Rmd @@ -20,8 +20,8 @@ This vignette demonstrates how to use the PathwayEmbed package to compute and vi ## Load Package and Example Data ```{r setup} library(PathwayEmbed) -# Load the example Seurat object included in the package -data(fake_test_object) +# Load the example gene expression matrix included in the package +data(fake_test_matrix) ``` ## Compute Pathway Activation @@ -29,9 +29,10 @@ data(fake_test_object) # Calculate pathway activation using MDS # Default batch.size is set to 1000 mds_results <- ComputeCellData( - fake_test_object, + fake_test_matrix, pathway = "Wnt", - distance.method = "manhattan" + distance.method = "manhattan", + scale.data = TRUE ) ``` @@ -39,7 +40,7 @@ mds_results <- ComputeCellData( ```{r} # Format MDS results and metadata for plotting plot_data <- PreparePlotData( - fake_test_object, + fake_test_metadata, mds_results, group = "genotype" ) diff --git a/doc/examples.html b/doc/examples.html index 67b9172..6158e6a 100644 --- a/doc/examples.html +++ b/doc/examples.html @@ -350,37 +350,36 @@

Overview

Load Package and Example Data

library(PathwayEmbed)
-# Load the example Seurat object included in the package
-data(fake_test_object)
+# Load the example gene expression matrix included in the package +data(fake_test_matrix)

Compute Pathway Activation

# Calculate pathway activation using MDS
 # Default batch.size is set to 1000
 mds_results <- ComputeCellData(
-  fake_test_object,
+  fake_test_matrix,
   pathway = "Wnt",
-  distance.method = "manhattan"
-)
-#> Centering and scaling data matrix
-#> Centering and scaling data matrix
-#> Parameter 'batch.size' is missing or NULL. Setting default batch size to 1000.
-#> Processing batch 1
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 1 processed with 1000 cells
-#> Processing batch 2
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 2 processed with 1000 cells
+ distance.method = "manhattan", + scale.data = TRUE +) +#> Parameter 'batch.size' is missing or NULL. Setting default batch size to 1000. +#> Processing batch 1 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 1 processed with 1000 cells +#> Processing batch 2 +#> Computing distance... +#> Running MDS ... +#> MDS finished +#> Batch 2 processed with 1000 cells

Prepare Data for Plotting

# Format MDS results and metadata for plotting
 plot_data <- PreparePlotData(
-  fake_test_object,
+  fake_test_metadata,
   mds_results,
   group = "genotype"
 )
@@ -394,7 +393,7 @@

Visualize Pathway Activation

group = "genotype", color = c("#ae282c", "#2066a8") )
-

+

Calculate Group-wise Activation Percentage (Optional)

@@ -406,8 +405,8 @@

Calculate Group-wise Activation Percentage (Optional)

#> # A tibble: 2 × 4 #> group percentage_on percentage_off cohens_d #> <chr> <dbl> <dbl> <dbl> -#> 1 WT 17.9 82.1 -1.97 -#> 2 Mutant 94.9 5.1 -1.97
+#> 1 Mutant 95.4 4.6 1.99 +#> 2 WT 16.7 83.3 1.99
diff --git a/doc/spatial_pathway.R b/doc/spatial_pathway.R index a815875..54968f9 100644 --- a/doc/spatial_pathway.R +++ b/doc/spatial_pathway.R @@ -22,22 +22,28 @@ library(cowplot) # # # Set Default Assay to be "RNA" # DefaultAssay(merged_spatial) <- "RNA" +# +# # Get genes x cell matrix +# merged_spatial_matrix <- as.matrix(GetAssayData(merged_spatial, assay = "RNA", slot = "data")) +# +# # Get metadata matrix +# merged_spatial_metadata <- merged_spatial@meta.data ## ----score compute, eval=FALSE------------------------------------------------ # # # Compute the score for each pathway -# Wnt_mds <- ComputeCellData(merged_spatial, "Wnt", "manhattan", batch.size = 1000) -# Notch_mds <- ComputeCellData(merged_spatial, "Notch", "manhattan", batch.size = 1000) -# Hippo_mds <- ComputeCellData(merged_spatial, "Hippo", "manhattan", batch.size = 1000) -# Tgfb_mds <- ComputeCellData(merged_spatial, "Tgfb", "manhattan", batch.size = 1000) -# HIF1a_mds <- ComputeCellData(merged_spatial, "HIF-1a", "manhattan", batch.size = 1000) +# Wnt_mds <- ComputeCellData(merged_spatial_matrix, "Wnt", "manhattan", batch.size = 1000) +# Notch_mds <- ComputeCellData(merged_spatial_matrix, "Notch", "manhattan", batch.size = 1000) +# Hippo_mds <- ComputeCellData(merged_spatial_matrix, "Hippo", "manhattan", batch.size = 1000) +# Tgfb_mds <- ComputeCellData(merged_spatial_matrix, "Tgfb", "manhattan", batch.size = 1000) +# HIF1a_mds <- ComputeCellData(merged_spatial_matrix, "HIF-1a", "manhattan", batch.size = 1000) # # # Process the mds -# Wnt_to.plot <- PreparePlotData(merged_spatial, Wnt_mds, "timepoint") -# Notch_to.plot <- PreparePlotData(merged_spatial, Notch_mds, "timepoint") -# Hippo_to.plot <- PreparePlotData(merged_spatial, Hippo_mds, "timepoint") -# Tgfb_to.plot <- PreparePlotData(merged_spatial, Tgfb_mds, "timepoint") -# HIF1a_to.plot <- PreparePlotData(merged_spatial, HIF1a_mds, "timepoint") +# Wnt_to.plot <- PreparePlotData(merged_spatial_metadata, Wnt_mds, "timepoint") +# Notch_to.plot <- PreparePlotData(merged_spatial_metadata, Notch_mds, "timepoint") +# Hippo_to.plot <- PreparePlotData(merged_spatial_metadata, Hippo_mds, "timepoint") +# Tgfb_to.plot <- PreparePlotData(merged_spatial_metadata, Tgfb_mds, "timepoint") +# HIF1a_to.plot <- PreparePlotData(merged_spatial_metadata, HIF1a_mds, "timepoint") # # # Combine to list # pathway_list <- list( diff --git a/doc/spatial_pathway.Rmd b/doc/spatial_pathway.Rmd index b0bfb2b..6e4f1b5 100644 --- a/doc/spatial_pathway.Rmd +++ b/doc/spatial_pathway.Rmd @@ -7,6 +7,11 @@ vignette: > %\VignetteEncoding{UTF-8} --- +## Overview +This vignette demonstrates the application of PathwayEmbed in mouse embryo spatial data (E9.5 - E12.5). With curated pathway database, we examined and compared Wnt, Notch, TGFb, Hippo, and HIF-1a signaling transduction states across spatial and temporal development. +Reference for the initial data: Chen et al. Spatiotemporal transcriptomic atlas of mouse organogenesis using DNA nanoball-patterned arrays, Cell, Volume 185, Issue 10, 2022, Pages 1777-1792.e21. + + ```{r setup} knitr::opts_chunk$set(echo = TRUE) @@ -44,6 +49,12 @@ merged_spatial <- merge( # Set Default Assay to be "RNA" DefaultAssay(merged_spatial) <- "RNA" + +# Get genes x cell matrix +merged_spatial_matrix <- as.matrix(GetAssayData(merged_spatial, assay = "RNA", slot = "data")) + +# Get metadata matrix +merged_spatial_metadata <- merged_spatial@meta.data ``` ## Compute pathway score @@ -53,18 +64,18 @@ Compute score for Wnt, Notch, Hippo, Tgfb, and HIF-1a pathways for the merged su ```{r score compute, eval=FALSE} # Compute the score for each pathway -Wnt_mds <- ComputeCellData(merged_spatial, "Wnt", "manhattan", batch.size = 1000) -Notch_mds <- ComputeCellData(merged_spatial, "Notch", "manhattan", batch.size = 1000) -Hippo_mds <- ComputeCellData(merged_spatial, "Hippo", "manhattan", batch.size = 1000) -Tgfb_mds <- ComputeCellData(merged_spatial, "Tgfb", "manhattan", batch.size = 1000) -HIF1a_mds <- ComputeCellData(merged_spatial, "HIF-1a", "manhattan", batch.size = 1000) +Wnt_mds <- ComputeCellData(merged_spatial_matrix, "Wnt", "manhattan", batch.size = 1000) +Notch_mds <- ComputeCellData(merged_spatial_matrix, "Notch", "manhattan", batch.size = 1000) +Hippo_mds <- ComputeCellData(merged_spatial_matrix, "Hippo", "manhattan", batch.size = 1000) +Tgfb_mds <- ComputeCellData(merged_spatial_matrix, "Tgfb", "manhattan", batch.size = 1000) +HIF1a_mds <- ComputeCellData(merged_spatial_matrix, "HIF-1a", "manhattan", batch.size = 1000) # Process the mds -Wnt_to.plot <- PreparePlotData(merged_spatial, Wnt_mds, "timepoint") -Notch_to.plot <- PreparePlotData(merged_spatial, Notch_mds, "timepoint") -Hippo_to.plot <- PreparePlotData(merged_spatial, Hippo_mds, "timepoint") -Tgfb_to.plot <- PreparePlotData(merged_spatial, Tgfb_mds, "timepoint") -HIF1a_to.plot <- PreparePlotData(merged_spatial, HIF1a_mds, "timepoint") +Wnt_to.plot <- PreparePlotData(merged_spatial_metadata, Wnt_mds, "timepoint") +Notch_to.plot <- PreparePlotData(merged_spatial_metadata, Notch_mds, "timepoint") +Hippo_to.plot <- PreparePlotData(merged_spatial_metadata, Hippo_mds, "timepoint") +Tgfb_to.plot <- PreparePlotData(merged_spatial_metadata, Tgfb_mds, "timepoint") +HIF1a_to.plot <- PreparePlotData(merged_spatial_metadata, HIF1a_mds, "timepoint") # Combine to list pathway_list <- list( diff --git a/doc/spatial_pathway.html b/doc/spatial_pathway.html index 54eb130..de3dbb4 100644 --- a/doc/spatial_pathway.html +++ b/doc/spatial_pathway.html @@ -340,6 +340,15 @@

Spatial Pathway Visualization

+
+

Overview

+

This vignette demonstrates the application of PathwayEmbed in mouse +embryo spatial data (E9.5 - E12.5). With curated pathway database, we +examined and compared Wnt, Notch, TGFb, Hippo, and HIF-1a signaling +transduction states across spatial and temporal development. Reference +for the initial data: Chen et al. Spatiotemporal transcriptomic atlas of +mouse organogenesis using DNA nanoball-patterned arrays, Cell, Volume +185, Issue 10, 2022, Pages 1777-1792.e21.

knitr::opts_chunk$set(echo = TRUE)
 
 # load library
@@ -349,6 +358,7 @@ 

Spatial Pathway Visualization

library(viridis)
## Loading required package: viridisLite
library(cowplot)
+

Spatial data load and process

The files can be downloaded from figshare via below link:

@@ -371,25 +381,31 @@

Spatial data load and process

dat1, y = c(dat2, dat3, dat4)) # Set Default Assay to be "RNA" -DefaultAssay(merged_spatial) <- "RNA"
+DefaultAssay(merged_spatial) <- "RNA" + +# Get genes x cell matrix +merged_spatial_matrix <- as.matrix(GetAssayData(merged_spatial, assay = "RNA", slot = "data")) + +# Get metadata matrix +merged_spatial_metadata <- merged_spatial@meta.data

Compute pathway score

Compute score for Wnt, Notch, Hippo, Tgfb, and HIF-1a pathways for the merged subject using ‘ComputeCellData’ in PathwayEmbed

# Compute the score for each pathway
-Wnt_mds <- ComputeCellData(merged_spatial, "Wnt", "manhattan", batch.size = 1000)
-Notch_mds <- ComputeCellData(merged_spatial, "Notch", "manhattan", batch.size = 1000)
-Hippo_mds <- ComputeCellData(merged_spatial, "Hippo", "manhattan", batch.size = 1000)
-Tgfb_mds <- ComputeCellData(merged_spatial, "Tgfb", "manhattan", batch.size = 1000)
-HIF1a_mds <- ComputeCellData(merged_spatial, "HIF-1a", "manhattan", batch.size = 1000)
+Wnt_mds <- ComputeCellData(merged_spatial_matrix, "Wnt", "manhattan", batch.size = 1000)
+Notch_mds <- ComputeCellData(merged_spatial_matrix, "Notch", "manhattan", batch.size = 1000)
+Hippo_mds <- ComputeCellData(merged_spatial_matrix, "Hippo", "manhattan", batch.size = 1000)
+Tgfb_mds <- ComputeCellData(merged_spatial_matrix, "Tgfb", "manhattan", batch.size = 1000)
+HIF1a_mds <- ComputeCellData(merged_spatial_matrix, "HIF-1a", "manhattan", batch.size = 1000)
 
 # Process the mds
-Wnt_to.plot <- PreparePlotData(merged_spatial, Wnt_mds, "timepoint")
-Notch_to.plot <- PreparePlotData(merged_spatial, Notch_mds, "timepoint")
-Hippo_to.plot <- PreparePlotData(merged_spatial, Hippo_mds, "timepoint")
-Tgfb_to.plot <- PreparePlotData(merged_spatial, Tgfb_mds, "timepoint")
-HIF1a_to.plot <- PreparePlotData(merged_spatial, HIF1a_mds, "timepoint")
+Wnt_to.plot <- PreparePlotData(merged_spatial_metadata, Wnt_mds, "timepoint")
+Notch_to.plot <- PreparePlotData(merged_spatial_metadata, Notch_mds, "timepoint")
+Hippo_to.plot <- PreparePlotData(merged_spatial_metadata, Hippo_mds, "timepoint")
+Tgfb_to.plot <- PreparePlotData(merged_spatial_metadata, Tgfb_mds, "timepoint")
+HIF1a_to.plot <- PreparePlotData(merged_spatial_metadata, HIF1a_mds, "timepoint")
 
 # Combine to list
 pathway_list <- list(
diff --git a/docs/404.html b/docs/404.html
index 77f6d5d..4962d65 100644
--- a/docs/404.html
+++ b/docs/404.html
@@ -4,108 +4,80 @@
 
 
 
-
+
 Page not found (404) • PathwayEmbed
-
-
-
-
-
-
-
+
+
+
+
+
 
-
-
-
-    
-
-
- Content not found. Please use links in the navbar. -
- - - +
- -
- diff --git a/docs/404.md b/docs/404.md new file mode 100644 index 0000000..5107f89 --- /dev/null +++ b/docs/404.md @@ -0,0 +1,3 @@ +Content not found. Please use links in the navbar. + +# Page not found (404) diff --git a/docs/LICENSE-text.html b/docs/LICENSE-text.html index 0c5b1ea..d334dc1 100644 --- a/docs/LICENSE-text.html +++ b/docs/LICENSE-text.html @@ -1,82 +1,59 @@ -License • PathwayEmbed - - -
-
+
+
+
-
-
YEAR: 2025
 COPYRIGHT HOLDER: Raredon Lab
 
-
+
- +
- - -
- +
diff --git a/docs/LICENSE-text.md b/docs/LICENSE-text.md new file mode 100644 index 0000000..e199af5 --- /dev/null +++ b/docs/LICENSE-text.md @@ -0,0 +1,4 @@ +# License + + YEAR: 2025 + COPYRIGHT HOLDER: Raredon Lab diff --git a/docs/LICENSE.html b/docs/LICENSE.html index 5fa5c1e..8e21092 100644 --- a/docs/LICENSE.html +++ b/docs/LICENSE.html @@ -1,56 +1,41 @@ -MIT License • PathwayEmbed - - -
-
+
+
+
-
-
@@ -61,26 +46,18 @@

MIT License

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

-
+
- +
- - -
- +
diff --git a/docs/LICENSE.md b/docs/LICENSE.md new file mode 100644 index 0000000..cc59629 --- /dev/null +++ b/docs/LICENSE.md @@ -0,0 +1,22 @@ +# MIT License + +Copyright (c) 2025 Raredon Lab + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +“Software”), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/docs/articles/Notch_Analysis_updated.html b/docs/articles/Notch_Analysis_updated.html new file mode 100644 index 0000000..3e81f15 --- /dev/null +++ b/docs/articles/Notch_Analysis_updated.html @@ -0,0 +1,744 @@ + + + + + + + +Notch_Analysis • PathwayEmbed + + + + + + + + Skip to contents + + +
+ + + + +
+
+ + + +
+

Overview +

+

This vignette demonstrates the application of PathwayEmbed in a +Notch-perturbed system (Ncstn fl/fl cKO bone marrow) and in aging +SSPCs.
+Reference: Remark et al., Bone Res 11, 50 (2023). https://doi.org/10.1038/s41413-023-00283-8

+
+
+ +
+

Helper: Annotation Label Builder +

+
+make_label <- function(stats, group1, group2) {
+  d    <- round(stats$cohens_d[1], 3)
+  p    <- formatC(stats$p_value[1], format = "e", digits = 2)
+  on1  <- stats$percentage_on[stats$group  == group1]
+  off1 <- stats$percentage_off[stats$group == group1]
+  on2  <- stats$percentage_on[stats$group  == group2]
+  off2 <- stats$percentage_off[stats$group == group2]
+  paste0(
+    group1, ": ON=", on1,  "%, OFF=", off1, "%\n",
+    group2, ": ON=", on2,  "%, OFF=", off2, "%\n",
+    "Cohen's d = ", d, "\n",
+    "p = ", p
+  )
+}
+
+
+
+

Data Preprocessing — WT vs. KO (Ncstn cKO) +

+

The block below is eval=FALSE because the raw 10X data +are large. The pre-processed SSPC subset (COI_2) is loaded +directly from the package in the next chunk.

+
+wt_data <- Read10X(data.dir = "path/to/WT", gene.column = 2)
+ko_data <- Read10X(data.dir = "path/to/KO", gene.column = 2)
+
+wt_seurat <- CreateSeuratObject(counts = wt_data, project = "WT")
+ko_seurat <- CreateSeuratObject(counts = ko_data, project = "KO")
+wt_seurat$condition <- "WT"
+ko_seurat$condition <- "KO"
+
+combined          <- merge(wt_seurat, y = ko_seurat,
+                           add.cell.ids = c("WT", "KO"), project = "WT_vs_KO")
+combined[["RNA"]] <- JoinLayers(combined[["RNA"]])
+
+combined[["percent.mt"]] <- PercentageFeatureSet(combined, pattern = "^mt-")
+combined <- subset(combined,
+                   subset = nFeature_RNA > 200 &
+                            nFeature_RNA < 2000 &
+                            percent.mt  < 10)
+
+combined <- NormalizeData(combined, normalization.method = "LogNormalize",
+                          scale.factor = 10000)
+combined <- FindVariableFeatures(combined, selection.method = "vst",
+                                 nfeatures = 2000)
+combined <- ScaleData(combined)
+combined <- RunPCA(combined)
+ElbowPlot(combined, ndims = 50)
+combined <- FindNeighbors(combined, dims = 1:20)
+combined <- FindClusters(combined, resolution = 1)
+combined <- RunUMAP(combined, dims = 1:20)
+
+DimPlot(combined, label = TRUE)
+FeaturePlot(combined, "Cxcl12")
+FeaturePlot(combined, "Kitl")
+
+COI_2 <- subset(combined, subset = seurat_clusters %in% c("23", "25"))
+
+
+
+

Notch Signaling in Ncstn KO vs. WT SSPCs +

+
+COI_2_matrix   <- as.matrix(GetAssayData(COI_2, assay = "RNA", layer = "data"))
+COI_2_metadata <- COI_2@meta.data
+
+# Load both Notch databases
+ListPathway("NOTCH")
+#> # A tibble: 6 × 8
+#>   Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes
+#>   <chr>   <chr>      <chr>         <chr>     <chr>       <chr>       <dbl> <chr>
+#> 1 NOTCH   NOTCH_JAG1 GSE223734     rJAG1 li… Mouse embr… Mouse           5 NA   
+#> 2 NOTCH   NOTCH_CB1… GSE221577     CB-103 N… RPMI-8402 … Human          46 NA   
+#> 3 NOTCH   NOTCH_LY_… GSE221577     LY411575… RPMI-8402 … Human          46 NA   
+#> 4 NOTCH   NOTCH_JAG… GSE235637     JAG1 sti… SVG-A cells Human          11 NA   
+#> 5 NOTCH   NOTCH_JAG… GSE235637     JAG1 sti… SVG-A cells Human          11 NA   
+#> 6 NOTCH   NOTCH_JAG… GSE235637     JAG1 sti… SVG-A cells Human          11 NA
+pathwaydata_mus  <- LoadPathway("NOTCH_JAG1",     "mouse")  # mouse perturbation data
+pathwaydata_24hr <- LoadPathway("NOTCH_JAG1_24H", "mouse")  # human 24hr (cross-species)
+
+matrix_mus  <- DataPreProcess(COI_2_matrix, pathwaydata_mus,  Seurat.object = FALSE)
+matrix_24hr <- DataPreProcess(COI_2_matrix, pathwaydata_24hr, Seurat.object = FALSE)
+
+pathwaystat_mus  <- PathwayMaxMin(matrix_mus,  pathwaydata_mus)
+pathwaystat_24hr <- PathwayMaxMin(matrix_24hr, pathwaydata_24hr)
+
+Notch_score_mus  <- ComputeCellData(matrix_mus,  pathwaystat_mus)
+Notch_score_24hr <- ComputeCellData(matrix_24hr, pathwaystat_24hr)
+
+to_plot_1 <- PreparePlotData(COI_2_metadata, Notch_score_mus,  "condition")
+to_plot_2 <- PreparePlotData(COI_2_metadata, Notch_score_24hr, "condition")
+
+pct_1 <- CalculatePercentage(to_plot_1, "condition")
+pct_2 <- CalculatePercentage(to_plot_2, "condition")
+pct_1; pct_2
+#> # A tibble: 2 × 5
+#>   group percentage_on percentage_off cohens_d p_value
+#>   <chr>         <dbl>          <dbl>    <dbl>   <dbl>
+#> 1 WT             46             54      0.369   0.141
+#> 2 KO             35.4           64.6    0.369   0.141
+#> # A tibble: 2 × 5
+#>   group percentage_on percentage_off cohens_d p_value
+#>   <chr>         <dbl>          <dbl>    <dbl>   <dbl>
+#> 1 WT             52             48      0.553 0.00519
+#> 2 KO             34.5           65.5    0.553 0.00519
+
+# Database comparison: gene overlap and coefficient agreement
+genes_mus  <- pathwaydata_mus$Gene_Symbol
+genes_24hr <- pathwaydata_24hr$Gene_Symbol
+shared     <- intersect(genes_mus, genes_24hr)
+
+cat("Genes in mouse database:      ", length(genes_mus),  "\n")
+#> Genes in mouse database:       5
+cat("Genes in human 24hr database: ", length(genes_24hr), "\n")
+#> Genes in human 24hr database:  9
+cat("Shared genes:                 ", length(shared),     "\n")
+#> Shared genes:                  4
+cat("Unique to mouse database:     ", length(setdiff(genes_mus, genes_24hr)), "\n")
+#> Unique to mouse database:      1
+cat("Unique to 24hr database:      ", length(setdiff(genes_24hr, genes_mus)), "\n")
+#> Unique to 24hr database:       5
+
+coef_mus   <- setNames(pathwaydata_mus$Coefficient,  pathwaydata_mus$Gene_Symbol)
+coef_24hr  <- setNames(pathwaydata_24hr$Coefficient, pathwaydata_24hr$Gene_Symbol)
+coef_agree <- mean(sign(coef_mus[shared]) == sign(coef_24hr[shared]), na.rm = TRUE)
+cat(sprintf("Coefficient direction agreement (shared genes): %.1f%%\n", coef_agree * 100))
+#> Coefficient direction agreement (shared genes): 100.0%
+
+PlotPathway(to_plot_1, "Notch (mouse database)", "condition",
+            c("#FFDAB9", "#A3BFD9")) +
+  annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5,
+           label = make_label(pct_1, "WT", "KO"), size = 3.5, color = "black")
+

+
+
+PlotPathway(to_plot_2, "Notch (human 24hr database)", "condition",
+            c("#FFDAB9", "#A3BFD9")) +
+  annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5,
+           label = make_label(pct_2, "WT", "KO"), size = 3.5, color = "black")
+

+
+
+
+

Benchmark — Ncstn KO vs. WT +

+
+common_genes         <- intersect(rownames(COI_2_matrix), pathwaydata_24hr$Gene_Symbol)
+gene_matrix          <- as.matrix(COI_2_matrix[common_genes, ])
+mean_expr            <- colMeans(gene_matrix, na.rm = TRUE)
+zscore_mean_per_cell <- colMeans(t(scale(t(gene_matrix))), na.rm = TRUE)
+
+Notch_features <- rownames(matrix_24hr)
+COI_2 <- AddModuleScore(
+  object   = COI_2,
+  features = list(Notch_features),
+  name     = "Notch_ModuleScore",
+  ctrl     = 5,
+  nbin     = 10
+)
+module_score <- setNames(
+  COI_2@meta.data$Notch_ModuleScore1,
+  rownames(COI_2@meta.data)
+)
+
+cells <- names(Notch_score_24hr)
+benchmark_df <- data.frame(
+  PathwayEmbed   = as.numeric(Notch_score_24hr),
+  AddModuleScore = as.numeric(module_score[cells]),
+  mean_expr      = as.numeric(mean_expr[cells]),
+  zscore_expr    = as.numeric(zscore_mean_per_cell[cells]),
+  row.names      = cells
+)
+
+benchmark_cor <- cor(benchmark_df, method = "spearman",
+                     use = "pairwise.complete.obs")
+print(round(benchmark_cor, 3))
+#>                PathwayEmbed AddModuleScore mean_expr zscore_expr
+#> PathwayEmbed          1.000          0.645     0.730       0.690
+#> AddModuleScore        0.645          1.000     0.899       0.848
+#> mean_expr             0.730          0.899     1.000       0.954
+#> zscore_expr           0.690          0.848     0.954       1.000
+
+p_cor <- pheatmap(
+  benchmark_cor,
+  color           = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100),
+  breaks          = seq(-1, 1, length.out = 101),
+  display_numbers = TRUE, number_format = "%.2f",
+  fontsize_number = 9,
+  main            = "Method Benchmark — Spearman Correlation (Ncstn KO dataset)"
+)
+p_cor
+

+
+
+ko_label <- ifelse(COI_2@meta.data[cells, "condition"] == "KO", 1L, 0L)
+
+compute_auroc <- function(scores, labels) {
+  r       <- roc(labels, scores, quiet = TRUE)
+  auc_val <- as.numeric(auc(r))
+  if (auc_val < 0.5) auc_val <- 1 - auc_val
+  auc_val
+}
+
+auroc_results <- data.frame(
+  Method = colnames(benchmark_df),
+  AUROC  = sapply(benchmark_df, compute_auroc, labels = ko_label)
+)
+auroc_results <- auroc_results[order(-auroc_results$AUROC), ]
+print(auroc_results)
+#>                        Method     AUROC
+#> PathwayEmbed     PathwayEmbed 0.6288496
+#> mean_expr           mean_expr 0.6224779
+#> zscore_expr       zscore_expr 0.6175221
+#> AddModuleScore AddModuleScore 0.5929204
+
+compute_cohens_d_method <- function(scores_vec, seurat_obj, group_col) {
+  pd  <- PreparePlotData(seurat_obj, scores_vec, group_col, Seurat.object = TRUE)
+  pct <- CalculatePercentage(pd, group_var = group_col)
+  abs(pct$cohens_d[1])
+}
+
+cohens_d_results <- data.frame(
+  Method   = colnames(benchmark_df),
+  Cohens_d = sapply(
+    colnames(benchmark_df),
+    function(m) {
+      sv <- setNames(benchmark_df[[m]], rownames(benchmark_df))
+      compute_cohens_d_method(sv, COI_2, "condition")
+    }
+  )
+)
+cohens_d_results <- cohens_d_results[order(-cohens_d_results$Cohens_d), ]
+print(cohens_d_results)
+#>                        Method  Cohens_d
+#> mean_expr           mean_expr 0.5751355
+#> PathwayEmbed     PathwayEmbed 0.5534599
+#> zscore_expr       zscore_expr 0.5397190
+#> AddModuleScore AddModuleScore 0.4965140
+
+method_colors <- c(
+  "PathwayEmbed"   = "#534AB7",
+  "zscore_expr"    = "#E24B4A",
+  "AddModuleScore" = "#EF9F27",
+  "mean_expr"      = "#888780"
+)
+
+p_cd <- ggplot(cohens_d_results,
+       aes(x = reorder(Method, Cohens_d), y = Cohens_d, fill = Method)) +
+  geom_bar(stat = "identity", width = 0.6) +
+  coord_flip() +
+  scale_fill_manual(values = method_colors) +
+  labs(title = "Effect size (Cohen's d): KO vs. WT",
+       x = NULL, y = "Cohen's d (absolute)") +
+  theme_classic() +
+  theme(legend.position = "none")
+p_cd
+

+
+
+p_auroc <- ggplot(auroc_results,
+       aes(x = reorder(Method, AUROC), y = AUROC, fill = Method)) +
+  geom_bar(stat = "identity", width = 0.6) +
+  geom_hline(yintercept = 0.5, linetype = "dashed", color = "black") +
+  coord_flip() +
+  scale_fill_manual(values = method_colors) +
+  labs(title = "AUROC: KO vs. WT separation (Ncstn KO dataset)",
+       x = NULL, y = "AUROC") +
+  ylim(0, 1) +
+  theme_classic() +
+  theme(legend.position = "none")
+p_auroc
+

+
+
+roc_list <- lapply(colnames(benchmark_df), function(m) {
+  roc(ko_label, benchmark_df[[m]], quiet = TRUE)
+})
+names(roc_list) <- colnames(benchmark_df)
+
+roc_df <- do.call(rbind, lapply(names(roc_list), function(m) {
+  r <- roc_list[[m]]
+  data.frame(Method = m, FPR = 1 - r$specificities, TPR = r$sensitivities)
+}))
+
+p_roc <- ggplot(roc_df, aes(x = FPR, y = TPR, color = Method)) +
+  geom_line(linewidth = 0.9) +
+  geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "grey60") +
+  scale_color_manual(values = method_colors) +
+  labs(title = "ROC curves: KO vs. WT (Ncstn KO dataset)",
+       x = "False positive rate", y = "True positive rate") +
+  theme_classic()
+p_roc
+

+
+
+
+

Data Preprocessing — Middle-Age vs. Young SSPCs +

+
+wt_data    <- Read10X("path/to/WT",    gene.column = 2)
+young_data <- Read10X("path/to/Young", gene.column = 2)
+
+WT_object    <- CreateSeuratObject(counts = wt_data)
+Young_object <- CreateSeuratObject(counts = young_data)
+WT_object$Age    <- "MiddleAge"
+Young_object$Age <- "Young"
+
+WT_object[["percent.mt"]]    <- PercentageFeatureSet(WT_object,    pattern = "^mt-")
+Young_object[["percent.mt"]] <- PercentageFeatureSet(Young_object, pattern = "^mt-")
+
+# NOTE: 30% threshold is intentionally permissive — skeletal stem cells retain
+# higher baseline mitochondrial content; tighter thresholds remove genuine SSPCs.
+WT_object_filtered    <- subset(WT_object,    subset = nFeature_RNA >= 100 & percent.mt < 30)
+Young_object_filtered <- subset(Young_object, subset = nFeature_RNA >= 100 & percent.mt < 30)
+
+merge_object          <- merge(WT_object_filtered, Young_object_filtered,
+                                add.cell.ids = c("WT", "Young"))
+merge_object[["RNA"]] <- JoinLayers(merge_object[["RNA"]])
+
+merge_object <- NormalizeData(merge_object)
+merge_object <- subset(
+  merge_object,
+  features = rownames(merge_object)[
+    Matrix::rowSums(GetAssayData(merge_object, slot = "counts") > 0) > 5]
+)
+merge_object <- FindVariableFeatures(merge_object, selection.method = "vst",
+                                      nfeatures = 3000)
+merge_object <- ScaleData(merge_object)
+merge_object <- RunPCA(merge_object)
+ElbowPlot(merge_object)
+merge_object <- FindNeighbors(merge_object, dims = 1:10)
+merge_object <- FindClusters(merge_object, resolution = 1)
+merge_object <- RunUMAP(merge_object, dims = 1:10)
+
+DimPlot(merge_object, reduction = "umap", group.by = "Age", label = TRUE)
+FeaturePlot(merge_object, reduction = "umap", features = "Cxcl12", order = TRUE)
+
+cluster_of_interest <- subset(merge_object, subset = seurat_clusters == 11)
+saveRDS(cluster_of_interest, file = "Middle_age_object.rds")
+
+
+
+

Notch Signaling in Middle-Age vs. Young SSPCs +

+
+# Re-use the human 24hr database loaded earlier
+matrix_notch      <- DataPreProcess(cluster_of_interest, pathwaydata_24hr,
+                                     Seurat.object = TRUE)
+pathwaystat_notch <- PathwayMaxMin(matrix_notch, pathwaydata_24hr)
+Notch_score       <- ComputeCellData(matrix_notch, pathwaystat_notch)
+
+to_plot   <- PreparePlotData(cluster_of_interest, Notch_score, "Age",
+                              Seurat.object = TRUE)
+age_stats <- CalculatePercentage(to_plot, "Age")
+age_stats
+#> # A tibble: 2 × 5
+#>   group     percentage_on percentage_off cohens_d    p_value
+#>   <chr>             <dbl>          <dbl>    <dbl>      <dbl>
+#> 1 MiddleAge          55.8           44.2    0.605 0.00000455
+#> 2 Young              26.1           73.9    0.605 0.00000455
+
+PlotPathway(to_plot, "Notch", "Age", c("orange", "#6baed6")) +
+  annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5,
+           label = make_label(age_stats, "MiddleAge", "Young"),
+           size = 3.5, color = "black")
+

+
+
+
+

Multi-Pathway Analysis — Middle-Age vs. Young SSPCs +

+
+HIf1a_pathwaydata <- LoadPathway("Hypoxia_24hr",          "mouse")
+Hippo_pathwaydata <- LoadPathway("HIPPO_heat",             "mouse")
+TGFb_pathwaydata  <- LoadPathway("TGFB_Mouse",             "mouse")
+Wnt_pathwaydata   <- LoadPathway("WNT3A_SLOPE_ACTIVATION", "mouse")
+
+pathway_list <- list(
+  HIF1a = HIf1a_pathwaydata,
+  Hippo = Hippo_pathwaydata,
+  TGFb  = TGFb_pathwaydata,
+  Wnt   = Wnt_pathwaydata
+)
+
+score_list    <- list()
+cohens_d_list <- list()
+
+for (pathway_name in names(pathway_list)) {
+  pathway_data <- pathway_list[[pathway_name]]
+  matrix_data  <- DataPreProcess(cluster_of_interest, pathway_data,
+                                  Seurat.object = TRUE)
+  pathway_stat <- PathwayMaxMin(matrix_data, pathway_data)
+  score        <- ComputeCellData(matrix_data, pathway_stat)
+  score_list[[pathway_name]] <- score
+
+  to_plot_p   <- PreparePlotData(cluster_of_interest, score, "Age",
+                                  Seurat.object = TRUE)
+  age_stats_p <- CalculatePercentage(to_plot_p, "Age")
+  cohens_d_list[[pathway_name]] <- abs(age_stats_p$cohens_d[1])
+
+  p <- PlotPathway(to_plot_p, pathway_name, "Age", c("orange", "#6baed6")) +
+    annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5,
+             label = make_label(age_stats_p, "MiddleAge", "Young"),
+             size = 3.5, color = "black")
+
+  print(p)
+  ggsave(
+    filename = paste0("figs/", gsub("[^A-Za-z0-9_]", "_", pathway_name), "_age.png"),
+    plot     = p, width = 5, height = 4, dpi = 300
+  )
+}
+

+
+
+
+

Cross-Pathway Comparison +

+
+# Add Notch to score list (computed in notch-aging chunk)
+score_list[["Notch"]] <- Notch_score
+cohens_d_list[["Notch"]] <- abs(age_stats$cohens_d[1])
+
+# Build score data frame aligned to metadata
+score_df      <- as.data.frame(score_list)
+score_df$cell <- rownames(score_df)
+
+meta_df      <- cluster_of_interest@meta.data
+meta_df$cell <- rownames(meta_df)
+
+score_df$Age        <- meta_df$Age[match(score_df$cell, meta_df$cell)]
+score_df$Age_binary <- ifelse(score_df$Age == "MiddleAge", 1, 0)
+
+pathway_cols <- c("HIF1a", "Hippo", "TGFb", "Wnt", "Notch")
+pathway_mat  <- score_df[, pathway_cols]
+
+# Spearman correlation heatmap
+pathway_cor <- cor(pathway_mat, method = "spearman", use = "pairwise.complete.obs")
+print(round(pathway_cor, 3))
+#>        HIF1a  Hippo   TGFb    Wnt  Notch
+#> HIF1a  1.000 -0.016  0.097  0.039  0.118
+#> Hippo -0.016  1.000 -0.025 -0.097 -0.042
+#> TGFb   0.097 -0.025  1.000  0.020  0.050
+#> Wnt    0.039 -0.097  0.020  1.000  0.080
+#> Notch  0.118 -0.042  0.050  0.080  1.000
+
+pheatmap(
+  pathway_cor,
+  color           = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100),
+  breaks          = seq(-1, 1, length.out = 101),
+  display_numbers = TRUE, number_format = "%.2f",
+  fontsize_number = 10,
+  main            = "Spearman Correlation Between Pathways"
+)
+

+
+
+# PCA of pathway activity space
+pca   <- prcomp(pathway_mat, scale. = TRUE)
+p_pca <- data.frame(pca$x, Age = score_df$Age)
+
+ggplot(p_pca, aes(PC1, PC2, color = Age)) +
+  geom_point(alpha = 0.6) +
+  theme_classic() +
+  labs(title = "PCA of pathway activity space")
+

+
+
+# AUROC per pathway
+compute_auroc_safe <- function(scores, labels) {
+  valid  <- !is.na(scores) & !is.na(labels)
+  if (length(unique(labels[valid])) < 2) return(NA)
+  r <- roc(labels[valid], scores[valid], quiet = TRUE)
+  a <- as.numeric(auc(r))
+  if (a < 0.5) a <- 1 - a
+  a
+}
+
+auroc_df <- data.frame(
+  Pathway = pathway_cols,
+  AUROC   = sapply(pathway_cols, function(pw) {
+    compute_auroc_safe(score_df[[pw]], score_df$Age_binary)
+  })
+)
+auroc_df <- auroc_df[order(-auroc_df$AUROC), ]
+print(auroc_df)
+#>       Pathway     AUROC
+#> Notch   Notch 0.6560963
+#> Hippo   Hippo 0.5862802
+#> HIF1a   HIF1a 0.5615532
+#> Wnt       Wnt 0.5368016
+#> TGFb     TGFb 0.5026313
+
+p_auroc_age <- ggplot(auroc_df,
+       aes(x = reorder(Pathway, AUROC), y = AUROC, fill = Pathway)) +
+  geom_col(width = 0.6) +
+  coord_flip() +
+  geom_hline(yintercept = 0.5, linetype = "dashed") +
+  geom_text(aes(label = sprintf("%.2f", AUROC)), hjust = -0.1, size = 3) +
+  ylim(0, 1.05) +
+  labs(title = "AUROC comparison across pathways", x = NULL, y = "AUROC") +
+  theme_classic() +
+  theme(legend.position = "none")
+p_auroc_age
+

+
+
+# Cohen's d per pathway
+cohens_d_df <- data.frame(
+  Pathway  = names(cohens_d_list),
+  Cohens_d = unlist(cohens_d_list)
+)
+cohens_d_df <- cohens_d_df[order(-cohens_d_df$Cohens_d), ]
+print(cohens_d_df)
+#>       Pathway   Cohens_d
+#> Notch   Notch 0.60484360
+#> Hippo   Hippo 0.37912152
+#> HIF1a   HIF1a 0.17792267
+#> Wnt       Wnt 0.14897250
+#> TGFb     TGFb 0.08659418
+
+p_cd <- ggplot(cohens_d_df,
+       aes(x = reorder(Pathway, Cohens_d), y = Cohens_d, fill = Pathway)) +
+  geom_col(width = 0.6) +
+  coord_flip() +
+  geom_text(aes(label = sprintf("%.2f", Cohens_d)), hjust = -0.1, size = 3) +
+  ylim(0, max(cohens_d_df$Cohens_d) * 1.1) +
+  labs(title = "Effect size (Cohen's d) across pathways", x = NULL, y = "Cohen's d (absolute)") +
+  theme_classic() +
+  theme(legend.position = "none")
+p_cd
+

+
+
+
+

Technical Confounders +

+
+cc_genes  <- Seurat::cc.genes.updated.2019
+cluster_of_interest <- CellCycleScoring(
+  cluster_of_interest,
+  s.features   = cc_genes$s.genes,
+  g2m.features = cc_genes$g2m.genes,
+  set.ident    = FALSE
+)
+
+stress_genes <- c(
+  "Fos", "Jun", "Junb", "Atf3", "Egr1",
+  "Ddit3", "Atf4", "Xbp1", "Hspa5",
+  "Hspa1a", "Hspa1b", "Hsp90aa1",
+  "Gadd45a", "Gadd45b", "Gadd45g"
+)
+cluster_of_interest <- AddModuleScore(
+  cluster_of_interest,
+  features = list(stress_genes),
+  name     = "StressScore",
+  ctrl     = 25,
+  nbin     = 24
+)
+
+meta_cc <- cluster_of_interest@meta.data
+
+# Merge scores with metadata
+score_df_full <- score_df
+score_df_full$S_score   <- meta_cc$S.Score[  match(score_df_full$cell, rownames(meta_cc))]
+score_df_full$G2M_score <- meta_cc$G2M.Score[match(score_df_full$cell, rownames(meta_cc))]
+score_df_full$Stress    <- cluster_of_interest$StressScore1[
+                             match(score_df_full$cell, rownames(meta_cc))]
+score_df_full$nCount_RNA   <- meta_cc$nCount_RNA[  match(score_df_full$cell, rownames(meta_cc))]
+score_df_full$nFeature_RNA <- meta_cc$nFeature_RNA[match(score_df_full$cell, rownames(meta_cc))]
+score_df_full$percent.mt   <- meta_cc$percent.mt[  match(score_df_full$cell, rownames(meta_cc))]
+
+covariates <- c("nCount_RNA", "nFeature_RNA", "percent.mt",
+                "Stress", "S_score", "G2M_score")
+
+cor_mat <- sapply(covariates, function(cov) {
+  sapply(pathway_cols, function(pw) {
+    cor(score_df_full[[pw]], score_df_full[[cov]],
+        method = "spearman", use = "complete.obs")
+  })
+})
+rownames(cor_mat) <- pathway_cols
+colnames(cor_mat) <- covariates
+print(round(cor_mat, 3))
+#>       nCount_RNA nFeature_RNA percent.mt Stress S_score G2M_score
+#> HIF1a      0.315        0.286     -0.148  0.190  -0.031    -0.018
+#> Hippo     -0.140       -0.140     -0.048  0.028   0.051     0.055
+#> TGFb       0.149        0.152     -0.017  0.002   0.016    -0.002
+#> Wnt        0.116        0.136     -0.004  0.051  -0.003     0.001
+#> Notch      0.181        0.204      0.019  0.161  -0.057    -0.062
+
+pheatmap(cor_mat,
+         color           = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100),
+         breaks          = seq(-1, 1, length.out = 101),
+         display_numbers = TRUE, number_format = "%.2f",
+         fontsize_number = 10,
+         main            = "Pathway vs. covariate correlations (Spearman)")
+

+
+
+# Scatter: each pathway vs. stress score
+plot_df_long <- pivot_longer(
+  score_df_full[, c("Stress", pathway_cols)],
+  cols      = all_of(pathway_cols),
+  names_to  = "Pathway",
+  values_to = "Score"
+)
+
+cor_df_stress <- plot_df_long %>%
+  group_by(Pathway) %>%
+  summarise(cor = cor(Stress, Score, method = "spearman", use = "complete.obs"),
+            .groups = "drop")
+
+ggplot(plot_df_long, aes(x = Stress, y = Score)) +
+  geom_point(alpha = 0.4, size = 1.2) +
+  geom_smooth(method = "lm", se = FALSE, linetype = "dashed", color = "#E24B4A") +
+  facet_wrap(~ Pathway, scales = "free_y") +
+  geom_text(data = cor_df_stress,
+            aes(x = Inf, y = Inf,
+                label = paste0("\u03c1 = ", round(cor, 2))),
+            hjust = 1.2, vjust = 1.5, inherit.aes = FALSE) +
+  theme_classic() +
+  labs(title = "Pathway scores vs. stress score (Spearman)",
+       x = "Stress score", y = "Pathway score")
+

+
+
+
+ + + +
+ + + +
+
+ + + + + + + diff --git a/docs/articles/Notch_Analysis_updated.md b/docs/articles/Notch_Analysis_updated.md new file mode 100644 index 0000000..c1d5627 --- /dev/null +++ b/docs/articles/Notch_Analysis_updated.md @@ -0,0 +1,694 @@ +# Notch_Analysis + +## Overview + +This vignette demonstrates the application of PathwayEmbed in a +Notch-perturbed system (Ncstn fl/fl cKO bone marrow) and in aging +SSPCs. +Reference: Remark et al., *Bone Res* 11, 50 (2023). + + +------------------------------------------------------------------------ + +## Load Packages + +``` r +library(Seurat) +library(PathwayEmbed) +library(ggplot2) +library(dplyr) +library(patchwork) +library(pheatmap) +library(tidyr) +library(pROC) +``` + +------------------------------------------------------------------------ + +## Helper: Annotation Label Builder + +``` r +make_label <- function(stats, group1, group2) { + d <- round(stats$cohens_d[1], 3) + p <- formatC(stats$p_value[1], format = "e", digits = 2) + on1 <- stats$percentage_on[stats$group == group1] + off1 <- stats$percentage_off[stats$group == group1] + on2 <- stats$percentage_on[stats$group == group2] + off2 <- stats$percentage_off[stats$group == group2] + paste0( + group1, ": ON=", on1, "%, OFF=", off1, "%\n", + group2, ": ON=", on2, "%, OFF=", off2, "%\n", + "Cohen's d = ", d, "\n", + "p = ", p + ) +} +``` + +------------------------------------------------------------------------ + +## Data Preprocessing — WT vs. KO (Ncstn cKO) + +The block below is `eval=FALSE` because the raw 10X data are large. The +pre-processed SSPC subset (`COI_2`) is loaded directly from the package +in the next chunk. + +``` r +wt_data <- Read10X(data.dir = "path/to/WT", gene.column = 2) +ko_data <- Read10X(data.dir = "path/to/KO", gene.column = 2) + +wt_seurat <- CreateSeuratObject(counts = wt_data, project = "WT") +ko_seurat <- CreateSeuratObject(counts = ko_data, project = "KO") +wt_seurat$condition <- "WT" +ko_seurat$condition <- "KO" + +combined <- merge(wt_seurat, y = ko_seurat, + add.cell.ids = c("WT", "KO"), project = "WT_vs_KO") +combined[["RNA"]] <- JoinLayers(combined[["RNA"]]) + +combined[["percent.mt"]] <- PercentageFeatureSet(combined, pattern = "^mt-") +combined <- subset(combined, + subset = nFeature_RNA > 200 & + nFeature_RNA < 2000 & + percent.mt < 10) + +combined <- NormalizeData(combined, normalization.method = "LogNormalize", + scale.factor = 10000) +combined <- FindVariableFeatures(combined, selection.method = "vst", + nfeatures = 2000) +combined <- ScaleData(combined) +combined <- RunPCA(combined) +ElbowPlot(combined, ndims = 50) +combined <- FindNeighbors(combined, dims = 1:20) +combined <- FindClusters(combined, resolution = 1) +combined <- RunUMAP(combined, dims = 1:20) + +DimPlot(combined, label = TRUE) +FeaturePlot(combined, "Cxcl12") +FeaturePlot(combined, "Kitl") + +COI_2 <- subset(combined, subset = seurat_clusters %in% c("23", "25")) +``` + +------------------------------------------------------------------------ + +## Notch Signaling in Ncstn KO vs. WT SSPCs + +``` r +COI_2_matrix <- as.matrix(GetAssayData(COI_2, assay = "RNA", layer = "data")) +COI_2_metadata <- COI_2@meta.data + +# Load both Notch databases +ListPathway("NOTCH") +#> # A tibble: 6 × 8 +#> Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes +#> +#> 1 NOTCH NOTCH_JAG1 GSE223734 rJAG1 li… Mouse embr… Mouse 5 NA +#> 2 NOTCH NOTCH_CB1… GSE221577 CB-103 N… RPMI-8402 … Human 46 NA +#> 3 NOTCH NOTCH_LY_… GSE221577 LY411575… RPMI-8402 … Human 46 NA +#> 4 NOTCH NOTCH_JAG… GSE235637 JAG1 sti… SVG-A cells Human 11 NA +#> 5 NOTCH NOTCH_JAG… GSE235637 JAG1 sti… SVG-A cells Human 11 NA +#> 6 NOTCH NOTCH_JAG… GSE235637 JAG1 sti… SVG-A cells Human 11 NA +pathwaydata_mus <- LoadPathway("NOTCH_JAG1", "mouse") # mouse perturbation data +pathwaydata_24hr <- LoadPathway("NOTCH_JAG1_24H", "mouse") # human 24hr (cross-species) + +matrix_mus <- DataPreProcess(COI_2_matrix, pathwaydata_mus, Seurat.object = FALSE) +matrix_24hr <- DataPreProcess(COI_2_matrix, pathwaydata_24hr, Seurat.object = FALSE) + +pathwaystat_mus <- PathwayMaxMin(matrix_mus, pathwaydata_mus) +pathwaystat_24hr <- PathwayMaxMin(matrix_24hr, pathwaydata_24hr) + +Notch_score_mus <- ComputeCellData(matrix_mus, pathwaystat_mus) +Notch_score_24hr <- ComputeCellData(matrix_24hr, pathwaystat_24hr) + +to_plot_1 <- PreparePlotData(COI_2_metadata, Notch_score_mus, "condition") +to_plot_2 <- PreparePlotData(COI_2_metadata, Notch_score_24hr, "condition") + +pct_1 <- CalculatePercentage(to_plot_1, "condition") +pct_2 <- CalculatePercentage(to_plot_2, "condition") +pct_1; pct_2 +#> # A tibble: 2 × 5 +#> group percentage_on percentage_off cohens_d p_value +#> +#> 1 WT 46 54 0.369 0.141 +#> 2 KO 35.4 64.6 0.369 0.141 +#> # A tibble: 2 × 5 +#> group percentage_on percentage_off cohens_d p_value +#> +#> 1 WT 52 48 0.553 0.00519 +#> 2 KO 34.5 65.5 0.553 0.00519 + +# Database comparison: gene overlap and coefficient agreement +genes_mus <- pathwaydata_mus$Gene_Symbol +genes_24hr <- pathwaydata_24hr$Gene_Symbol +shared <- intersect(genes_mus, genes_24hr) + +cat("Genes in mouse database: ", length(genes_mus), "\n") +#> Genes in mouse database: 5 +cat("Genes in human 24hr database: ", length(genes_24hr), "\n") +#> Genes in human 24hr database: 9 +cat("Shared genes: ", length(shared), "\n") +#> Shared genes: 4 +cat("Unique to mouse database: ", length(setdiff(genes_mus, genes_24hr)), "\n") +#> Unique to mouse database: 1 +cat("Unique to 24hr database: ", length(setdiff(genes_24hr, genes_mus)), "\n") +#> Unique to 24hr database: 5 + +coef_mus <- setNames(pathwaydata_mus$Coefficient, pathwaydata_mus$Gene_Symbol) +coef_24hr <- setNames(pathwaydata_24hr$Coefficient, pathwaydata_24hr$Gene_Symbol) +coef_agree <- mean(sign(coef_mus[shared]) == sign(coef_24hr[shared]), na.rm = TRUE) +cat(sprintf("Coefficient direction agreement (shared genes): %.1f%%\n", coef_agree * 100)) +#> Coefficient direction agreement (shared genes): 100.0% + +PlotPathway(to_plot_1, "Notch (mouse database)", "condition", + c("#FFDAB9", "#A3BFD9")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_1, "WT", "KO"), size = 3.5, color = "black") +``` + +![](Notch_Analysis_updated_files/figure-html/notch-ko-1.png) + +``` r + +PlotPathway(to_plot_2, "Notch (human 24hr database)", "condition", + c("#FFDAB9", "#A3BFD9")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_2, "WT", "KO"), size = 3.5, color = "black") +``` + +![](Notch_Analysis_updated_files/figure-html/notch-ko-2.png) + +------------------------------------------------------------------------ + +## Benchmark — Ncstn KO vs. WT + +``` r +common_genes <- intersect(rownames(COI_2_matrix), pathwaydata_24hr$Gene_Symbol) +gene_matrix <- as.matrix(COI_2_matrix[common_genes, ]) +mean_expr <- colMeans(gene_matrix, na.rm = TRUE) +zscore_mean_per_cell <- colMeans(t(scale(t(gene_matrix))), na.rm = TRUE) + +Notch_features <- rownames(matrix_24hr) +COI_2 <- AddModuleScore( + object = COI_2, + features = list(Notch_features), + name = "Notch_ModuleScore", + ctrl = 5, + nbin = 10 +) +module_score <- setNames( + COI_2@meta.data$Notch_ModuleScore1, + rownames(COI_2@meta.data) +) + +cells <- names(Notch_score_24hr) +benchmark_df <- data.frame( + PathwayEmbed = as.numeric(Notch_score_24hr), + AddModuleScore = as.numeric(module_score[cells]), + mean_expr = as.numeric(mean_expr[cells]), + zscore_expr = as.numeric(zscore_mean_per_cell[cells]), + row.names = cells +) + +benchmark_cor <- cor(benchmark_df, method = "spearman", + use = "pairwise.complete.obs") +print(round(benchmark_cor, 3)) +#> PathwayEmbed AddModuleScore mean_expr zscore_expr +#> PathwayEmbed 1.000 0.645 0.730 0.690 +#> AddModuleScore 0.645 1.000 0.899 0.848 +#> mean_expr 0.730 0.899 1.000 0.954 +#> zscore_expr 0.690 0.848 0.954 1.000 + +p_cor <- pheatmap( + benchmark_cor, + color = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100), + breaks = seq(-1, 1, length.out = 101), + display_numbers = TRUE, number_format = "%.2f", + fontsize_number = 9, + main = "Method Benchmark — Spearman Correlation (Ncstn KO dataset)" +) +p_cor +``` + +![](Notch_Analysis_updated_files/figure-html/benchmark-ko-1.png) + +``` r + +ko_label <- ifelse(COI_2@meta.data[cells, "condition"] == "KO", 1L, 0L) + +compute_auroc <- function(scores, labels) { + r <- roc(labels, scores, quiet = TRUE) + auc_val <- as.numeric(auc(r)) + if (auc_val < 0.5) auc_val <- 1 - auc_val + auc_val +} + +auroc_results <- data.frame( + Method = colnames(benchmark_df), + AUROC = sapply(benchmark_df, compute_auroc, labels = ko_label) +) +auroc_results <- auroc_results[order(-auroc_results$AUROC), ] +print(auroc_results) +#> Method AUROC +#> PathwayEmbed PathwayEmbed 0.6288496 +#> mean_expr mean_expr 0.6224779 +#> zscore_expr zscore_expr 0.6175221 +#> AddModuleScore AddModuleScore 0.5929204 + +compute_cohens_d_method <- function(scores_vec, seurat_obj, group_col) { + pd <- PreparePlotData(seurat_obj, scores_vec, group_col, Seurat.object = TRUE) + pct <- CalculatePercentage(pd, group_var = group_col) + abs(pct$cohens_d[1]) +} + +cohens_d_results <- data.frame( + Method = colnames(benchmark_df), + Cohens_d = sapply( + colnames(benchmark_df), + function(m) { + sv <- setNames(benchmark_df[[m]], rownames(benchmark_df)) + compute_cohens_d_method(sv, COI_2, "condition") + } + ) +) +cohens_d_results <- cohens_d_results[order(-cohens_d_results$Cohens_d), ] +print(cohens_d_results) +#> Method Cohens_d +#> mean_expr mean_expr 0.5751355 +#> PathwayEmbed PathwayEmbed 0.5534599 +#> zscore_expr zscore_expr 0.5397190 +#> AddModuleScore AddModuleScore 0.4965140 + +method_colors <- c( + "PathwayEmbed" = "#534AB7", + "zscore_expr" = "#E24B4A", + "AddModuleScore" = "#EF9F27", + "mean_expr" = "#888780" +) + +p_cd <- ggplot(cohens_d_results, + aes(x = reorder(Method, Cohens_d), y = Cohens_d, fill = Method)) + + geom_bar(stat = "identity", width = 0.6) + + coord_flip() + + scale_fill_manual(values = method_colors) + + labs(title = "Effect size (Cohen's d): KO vs. WT", + x = NULL, y = "Cohen's d (absolute)") + + theme_classic() + + theme(legend.position = "none") +p_cd +``` + +![](Notch_Analysis_updated_files/figure-html/benchmark-ko-2.png) + +``` r + +p_auroc <- ggplot(auroc_results, + aes(x = reorder(Method, AUROC), y = AUROC, fill = Method)) + + geom_bar(stat = "identity", width = 0.6) + + geom_hline(yintercept = 0.5, linetype = "dashed", color = "black") + + coord_flip() + + scale_fill_manual(values = method_colors) + + labs(title = "AUROC: KO vs. WT separation (Ncstn KO dataset)", + x = NULL, y = "AUROC") + + ylim(0, 1) + + theme_classic() + + theme(legend.position = "none") +p_auroc +``` + +![](Notch_Analysis_updated_files/figure-html/benchmark-ko-3.png) + +``` r + +roc_list <- lapply(colnames(benchmark_df), function(m) { + roc(ko_label, benchmark_df[[m]], quiet = TRUE) +}) +names(roc_list) <- colnames(benchmark_df) + +roc_df <- do.call(rbind, lapply(names(roc_list), function(m) { + r <- roc_list[[m]] + data.frame(Method = m, FPR = 1 - r$specificities, TPR = r$sensitivities) +})) + +p_roc <- ggplot(roc_df, aes(x = FPR, y = TPR, color = Method)) + + geom_line(linewidth = 0.9) + + geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "grey60") + + scale_color_manual(values = method_colors) + + labs(title = "ROC curves: KO vs. WT (Ncstn KO dataset)", + x = "False positive rate", y = "True positive rate") + + theme_classic() +p_roc +``` + +![](Notch_Analysis_updated_files/figure-html/benchmark-ko-4.png) + +------------------------------------------------------------------------ + +## Data Preprocessing — Middle-Age vs. Young SSPCs + +``` r +wt_data <- Read10X("path/to/WT", gene.column = 2) +young_data <- Read10X("path/to/Young", gene.column = 2) + +WT_object <- CreateSeuratObject(counts = wt_data) +Young_object <- CreateSeuratObject(counts = young_data) +WT_object$Age <- "MiddleAge" +Young_object$Age <- "Young" + +WT_object[["percent.mt"]] <- PercentageFeatureSet(WT_object, pattern = "^mt-") +Young_object[["percent.mt"]] <- PercentageFeatureSet(Young_object, pattern = "^mt-") + +# NOTE: 30% threshold is intentionally permissive — skeletal stem cells retain +# higher baseline mitochondrial content; tighter thresholds remove genuine SSPCs. +WT_object_filtered <- subset(WT_object, subset = nFeature_RNA >= 100 & percent.mt < 30) +Young_object_filtered <- subset(Young_object, subset = nFeature_RNA >= 100 & percent.mt < 30) + +merge_object <- merge(WT_object_filtered, Young_object_filtered, + add.cell.ids = c("WT", "Young")) +merge_object[["RNA"]] <- JoinLayers(merge_object[["RNA"]]) + +merge_object <- NormalizeData(merge_object) +merge_object <- subset( + merge_object, + features = rownames(merge_object)[ + Matrix::rowSums(GetAssayData(merge_object, slot = "counts") > 0) > 5] +) +merge_object <- FindVariableFeatures(merge_object, selection.method = "vst", + nfeatures = 3000) +merge_object <- ScaleData(merge_object) +merge_object <- RunPCA(merge_object) +ElbowPlot(merge_object) +merge_object <- FindNeighbors(merge_object, dims = 1:10) +merge_object <- FindClusters(merge_object, resolution = 1) +merge_object <- RunUMAP(merge_object, dims = 1:10) + +DimPlot(merge_object, reduction = "umap", group.by = "Age", label = TRUE) +FeaturePlot(merge_object, reduction = "umap", features = "Cxcl12", order = TRUE) + +cluster_of_interest <- subset(merge_object, subset = seurat_clusters == 11) +saveRDS(cluster_of_interest, file = "Middle_age_object.rds") +``` + +------------------------------------------------------------------------ + +## Notch Signaling in Middle-Age vs. Young SSPCs + +``` r +# Re-use the human 24hr database loaded earlier +matrix_notch <- DataPreProcess(cluster_of_interest, pathwaydata_24hr, + Seurat.object = TRUE) +pathwaystat_notch <- PathwayMaxMin(matrix_notch, pathwaydata_24hr) +Notch_score <- ComputeCellData(matrix_notch, pathwaystat_notch) + +to_plot <- PreparePlotData(cluster_of_interest, Notch_score, "Age", + Seurat.object = TRUE) +age_stats <- CalculatePercentage(to_plot, "Age") +age_stats +#> # A tibble: 2 × 5 +#> group percentage_on percentage_off cohens_d p_value +#> +#> 1 MiddleAge 55.8 44.2 0.605 0.00000455 +#> 2 Young 26.1 73.9 0.605 0.00000455 + +PlotPathway(to_plot, "Notch", "Age", c("orange", "#6baed6")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(age_stats, "MiddleAge", "Young"), + size = 3.5, color = "black") +``` + +![](Notch_Analysis_updated_files/figure-html/notch-aging-1.png) + +------------------------------------------------------------------------ + +## Multi-Pathway Analysis — Middle-Age vs. Young SSPCs + +``` r +HIf1a_pathwaydata <- LoadPathway("Hypoxia_24hr", "mouse") +Hippo_pathwaydata <- LoadPathway("HIPPO_heat", "mouse") +TGFb_pathwaydata <- LoadPathway("TGFB_Mouse", "mouse") +Wnt_pathwaydata <- LoadPathway("WNT3A_SLOPE_ACTIVATION", "mouse") + +pathway_list <- list( + HIF1a = HIf1a_pathwaydata, + Hippo = Hippo_pathwaydata, + TGFb = TGFb_pathwaydata, + Wnt = Wnt_pathwaydata +) + +score_list <- list() +cohens_d_list <- list() + +for (pathway_name in names(pathway_list)) { + pathway_data <- pathway_list[[pathway_name]] + matrix_data <- DataPreProcess(cluster_of_interest, pathway_data, + Seurat.object = TRUE) + pathway_stat <- PathwayMaxMin(matrix_data, pathway_data) + score <- ComputeCellData(matrix_data, pathway_stat) + score_list[[pathway_name]] <- score + + to_plot_p <- PreparePlotData(cluster_of_interest, score, "Age", + Seurat.object = TRUE) + age_stats_p <- CalculatePercentage(to_plot_p, "Age") + cohens_d_list[[pathway_name]] <- abs(age_stats_p$cohens_d[1]) + + p <- PlotPathway(to_plot_p, pathway_name, "Age", c("orange", "#6baed6")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(age_stats_p, "MiddleAge", "Young"), + size = 3.5, color = "black") + + print(p) + ggsave( + filename = paste0("figs/", gsub("[^A-Za-z0-9_]", "_", pathway_name), "_age.png"), + plot = p, width = 5, height = 4, dpi = 300 + ) +} +``` + +![](Notch_Analysis_updated_files/figure-html/multi-pathway-1.png)![](Notch_Analysis_updated_files/figure-html/multi-pathway-2.png)![](Notch_Analysis_updated_files/figure-html/multi-pathway-3.png)![](Notch_Analysis_updated_files/figure-html/multi-pathway-4.png) + +------------------------------------------------------------------------ + +## Cross-Pathway Comparison + +``` r +# Add Notch to score list (computed in notch-aging chunk) +score_list[["Notch"]] <- Notch_score +cohens_d_list[["Notch"]] <- abs(age_stats$cohens_d[1]) + +# Build score data frame aligned to metadata +score_df <- as.data.frame(score_list) +score_df$cell <- rownames(score_df) + +meta_df <- cluster_of_interest@meta.data +meta_df$cell <- rownames(meta_df) + +score_df$Age <- meta_df$Age[match(score_df$cell, meta_df$cell)] +score_df$Age_binary <- ifelse(score_df$Age == "MiddleAge", 1, 0) + +pathway_cols <- c("HIF1a", "Hippo", "TGFb", "Wnt", "Notch") +pathway_mat <- score_df[, pathway_cols] + +# Spearman correlation heatmap +pathway_cor <- cor(pathway_mat, method = "spearman", use = "pairwise.complete.obs") +print(round(pathway_cor, 3)) +#> HIF1a Hippo TGFb Wnt Notch +#> HIF1a 1.000 -0.016 0.097 0.039 0.118 +#> Hippo -0.016 1.000 -0.025 -0.097 -0.042 +#> TGFb 0.097 -0.025 1.000 0.020 0.050 +#> Wnt 0.039 -0.097 0.020 1.000 0.080 +#> Notch 0.118 -0.042 0.050 0.080 1.000 + +pheatmap( + pathway_cor, + color = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100), + breaks = seq(-1, 1, length.out = 101), + display_numbers = TRUE, number_format = "%.2f", + fontsize_number = 10, + main = "Spearman Correlation Between Pathways" +) +``` + +![](Notch_Analysis_updated_files/figure-html/cross-pathway-1.png) + +``` r + +# PCA of pathway activity space +pca <- prcomp(pathway_mat, scale. = TRUE) +p_pca <- data.frame(pca$x, Age = score_df$Age) + +ggplot(p_pca, aes(PC1, PC2, color = Age)) + + geom_point(alpha = 0.6) + + theme_classic() + + labs(title = "PCA of pathway activity space") +``` + +![](Notch_Analysis_updated_files/figure-html/cross-pathway-2.png) + +``` r + +# AUROC per pathway +compute_auroc_safe <- function(scores, labels) { + valid <- !is.na(scores) & !is.na(labels) + if (length(unique(labels[valid])) < 2) return(NA) + r <- roc(labels[valid], scores[valid], quiet = TRUE) + a <- as.numeric(auc(r)) + if (a < 0.5) a <- 1 - a + a +} + +auroc_df <- data.frame( + Pathway = pathway_cols, + AUROC = sapply(pathway_cols, function(pw) { + compute_auroc_safe(score_df[[pw]], score_df$Age_binary) + }) +) +auroc_df <- auroc_df[order(-auroc_df$AUROC), ] +print(auroc_df) +#> Pathway AUROC +#> Notch Notch 0.6560963 +#> Hippo Hippo 0.5862802 +#> HIF1a HIF1a 0.5615532 +#> Wnt Wnt 0.5368016 +#> TGFb TGFb 0.5026313 + +p_auroc_age <- ggplot(auroc_df, + aes(x = reorder(Pathway, AUROC), y = AUROC, fill = Pathway)) + + geom_col(width = 0.6) + + coord_flip() + + geom_hline(yintercept = 0.5, linetype = "dashed") + + geom_text(aes(label = sprintf("%.2f", AUROC)), hjust = -0.1, size = 3) + + ylim(0, 1.05) + + labs(title = "AUROC comparison across pathways", x = NULL, y = "AUROC") + + theme_classic() + + theme(legend.position = "none") +p_auroc_age +``` + +![](Notch_Analysis_updated_files/figure-html/cross-pathway-3.png) + +``` r + +# Cohen's d per pathway +cohens_d_df <- data.frame( + Pathway = names(cohens_d_list), + Cohens_d = unlist(cohens_d_list) +) +cohens_d_df <- cohens_d_df[order(-cohens_d_df$Cohens_d), ] +print(cohens_d_df) +#> Pathway Cohens_d +#> Notch Notch 0.60484360 +#> Hippo Hippo 0.37912152 +#> HIF1a HIF1a 0.17792267 +#> Wnt Wnt 0.14897250 +#> TGFb TGFb 0.08659418 + +p_cd <- ggplot(cohens_d_df, + aes(x = reorder(Pathway, Cohens_d), y = Cohens_d, fill = Pathway)) + + geom_col(width = 0.6) + + coord_flip() + + geom_text(aes(label = sprintf("%.2f", Cohens_d)), hjust = -0.1, size = 3) + + ylim(0, max(cohens_d_df$Cohens_d) * 1.1) + + labs(title = "Effect size (Cohen's d) across pathways", x = NULL, y = "Cohen's d (absolute)") + + theme_classic() + + theme(legend.position = "none") +p_cd +``` + +![](Notch_Analysis_updated_files/figure-html/cross-pathway-4.png) + +------------------------------------------------------------------------ + +## Technical Confounders + +``` r +cc_genes <- Seurat::cc.genes.updated.2019 +cluster_of_interest <- CellCycleScoring( + cluster_of_interest, + s.features = cc_genes$s.genes, + g2m.features = cc_genes$g2m.genes, + set.ident = FALSE +) + +stress_genes <- c( + "Fos", "Jun", "Junb", "Atf3", "Egr1", + "Ddit3", "Atf4", "Xbp1", "Hspa5", + "Hspa1a", "Hspa1b", "Hsp90aa1", + "Gadd45a", "Gadd45b", "Gadd45g" +) +cluster_of_interest <- AddModuleScore( + cluster_of_interest, + features = list(stress_genes), + name = "StressScore", + ctrl = 25, + nbin = 24 +) + +meta_cc <- cluster_of_interest@meta.data + +# Merge scores with metadata +score_df_full <- score_df +score_df_full$S_score <- meta_cc$S.Score[ match(score_df_full$cell, rownames(meta_cc))] +score_df_full$G2M_score <- meta_cc$G2M.Score[match(score_df_full$cell, rownames(meta_cc))] +score_df_full$Stress <- cluster_of_interest$StressScore1[ + match(score_df_full$cell, rownames(meta_cc))] +score_df_full$nCount_RNA <- meta_cc$nCount_RNA[ match(score_df_full$cell, rownames(meta_cc))] +score_df_full$nFeature_RNA <- meta_cc$nFeature_RNA[match(score_df_full$cell, rownames(meta_cc))] +score_df_full$percent.mt <- meta_cc$percent.mt[ match(score_df_full$cell, rownames(meta_cc))] + +covariates <- c("nCount_RNA", "nFeature_RNA", "percent.mt", + "Stress", "S_score", "G2M_score") + +cor_mat <- sapply(covariates, function(cov) { + sapply(pathway_cols, function(pw) { + cor(score_df_full[[pw]], score_df_full[[cov]], + method = "spearman", use = "complete.obs") + }) +}) +rownames(cor_mat) <- pathway_cols +colnames(cor_mat) <- covariates +print(round(cor_mat, 3)) +#> nCount_RNA nFeature_RNA percent.mt Stress S_score G2M_score +#> HIF1a 0.315 0.286 -0.148 0.190 -0.031 -0.018 +#> Hippo -0.140 -0.140 -0.048 0.028 0.051 0.055 +#> TGFb 0.149 0.152 -0.017 0.002 0.016 -0.002 +#> Wnt 0.116 0.136 -0.004 0.051 -0.003 0.001 +#> Notch 0.181 0.204 0.019 0.161 -0.057 -0.062 + +pheatmap(cor_mat, + color = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100), + breaks = seq(-1, 1, length.out = 101), + display_numbers = TRUE, number_format = "%.2f", + fontsize_number = 10, + main = "Pathway vs. covariate correlations (Spearman)") +``` + +![](Notch_Analysis_updated_files/figure-html/confounders-1.png) + +``` r + +# Scatter: each pathway vs. stress score +plot_df_long <- pivot_longer( + score_df_full[, c("Stress", pathway_cols)], + cols = all_of(pathway_cols), + names_to = "Pathway", + values_to = "Score" +) + +cor_df_stress <- plot_df_long %>% + group_by(Pathway) %>% + summarise(cor = cor(Stress, Score, method = "spearman", use = "complete.obs"), + .groups = "drop") + +ggplot(plot_df_long, aes(x = Stress, y = Score)) + + geom_point(alpha = 0.4, size = 1.2) + + geom_smooth(method = "lm", se = FALSE, linetype = "dashed", color = "#E24B4A") + + facet_wrap(~ Pathway, scales = "free_y") + + geom_text(data = cor_df_stress, + aes(x = Inf, y = Inf, + label = paste0("\u03c1 = ", round(cor, 2))), + hjust = 1.2, vjust = 1.5, inherit.aes = FALSE) + + theme_classic() + + labs(title = "Pathway scores vs. stress score (Spearman)", + x = "Stress score", y = "Pathway score") +``` + +![](Notch_Analysis_updated_files/figure-html/confounders-2.png) diff --git a/docs/articles/Notch_Analysis_updated_files/figure-html/benchmark-ko-1.png b/docs/articles/Notch_Analysis_updated_files/figure-html/benchmark-ko-1.png new file mode 100644 index 0000000..8207959 Binary files /dev/null and b/docs/articles/Notch_Analysis_updated_files/figure-html/benchmark-ko-1.png differ diff --git a/docs/articles/Notch_Analysis_updated_files/figure-html/benchmark-ko-2.png b/docs/articles/Notch_Analysis_updated_files/figure-html/benchmark-ko-2.png new file mode 100644 index 0000000..bf68da8 Binary files /dev/null and b/docs/articles/Notch_Analysis_updated_files/figure-html/benchmark-ko-2.png differ diff --git a/docs/articles/Notch_Analysis_updated_files/figure-html/benchmark-ko-3.png b/docs/articles/Notch_Analysis_updated_files/figure-html/benchmark-ko-3.png new file mode 100644 index 0000000..d930448 Binary files /dev/null and b/docs/articles/Notch_Analysis_updated_files/figure-html/benchmark-ko-3.png differ diff --git a/docs/articles/Notch_Analysis_updated_files/figure-html/benchmark-ko-4.png b/docs/articles/Notch_Analysis_updated_files/figure-html/benchmark-ko-4.png new file mode 100644 index 0000000..f3f9268 Binary files /dev/null and b/docs/articles/Notch_Analysis_updated_files/figure-html/benchmark-ko-4.png differ diff --git a/docs/articles/Notch_Analysis_updated_files/figure-html/confounders-1.png b/docs/articles/Notch_Analysis_updated_files/figure-html/confounders-1.png new file mode 100644 index 0000000..e26e159 Binary files /dev/null and b/docs/articles/Notch_Analysis_updated_files/figure-html/confounders-1.png differ diff --git a/docs/articles/Notch_Analysis_updated_files/figure-html/confounders-2.png b/docs/articles/Notch_Analysis_updated_files/figure-html/confounders-2.png new file mode 100644 index 0000000..9ba4be4 Binary files /dev/null and b/docs/articles/Notch_Analysis_updated_files/figure-html/confounders-2.png differ diff --git a/docs/articles/Notch_Analysis_updated_files/figure-html/cross-pathway-1.png b/docs/articles/Notch_Analysis_updated_files/figure-html/cross-pathway-1.png new file mode 100644 index 0000000..b955545 Binary files /dev/null and b/docs/articles/Notch_Analysis_updated_files/figure-html/cross-pathway-1.png differ diff --git a/docs/articles/Notch_Analysis_updated_files/figure-html/cross-pathway-2.png b/docs/articles/Notch_Analysis_updated_files/figure-html/cross-pathway-2.png new file mode 100644 index 0000000..c4ec10c Binary files /dev/null and b/docs/articles/Notch_Analysis_updated_files/figure-html/cross-pathway-2.png differ diff --git a/docs/articles/Notch_Analysis_updated_files/figure-html/cross-pathway-3.png b/docs/articles/Notch_Analysis_updated_files/figure-html/cross-pathway-3.png new file mode 100644 index 0000000..636e75f Binary files /dev/null and b/docs/articles/Notch_Analysis_updated_files/figure-html/cross-pathway-3.png differ diff --git a/docs/articles/Notch_Analysis_updated_files/figure-html/cross-pathway-4.png b/docs/articles/Notch_Analysis_updated_files/figure-html/cross-pathway-4.png new file mode 100644 index 0000000..e7bd8ba Binary files /dev/null and b/docs/articles/Notch_Analysis_updated_files/figure-html/cross-pathway-4.png differ diff --git a/docs/articles/Notch_Analysis_updated_files/figure-html/multi-pathway-1.png b/docs/articles/Notch_Analysis_updated_files/figure-html/multi-pathway-1.png new file mode 100644 index 0000000..67f510b Binary files /dev/null and b/docs/articles/Notch_Analysis_updated_files/figure-html/multi-pathway-1.png differ diff --git a/docs/articles/Notch_Analysis_updated_files/figure-html/multi-pathway-2.png b/docs/articles/Notch_Analysis_updated_files/figure-html/multi-pathway-2.png new file mode 100644 index 0000000..33dec68 Binary files /dev/null and b/docs/articles/Notch_Analysis_updated_files/figure-html/multi-pathway-2.png differ diff --git a/docs/articles/Notch_Analysis_updated_files/figure-html/multi-pathway-3.png b/docs/articles/Notch_Analysis_updated_files/figure-html/multi-pathway-3.png new file mode 100644 index 0000000..3cde018 Binary files /dev/null and b/docs/articles/Notch_Analysis_updated_files/figure-html/multi-pathway-3.png differ diff --git a/docs/articles/Notch_Analysis_updated_files/figure-html/multi-pathway-4.png b/docs/articles/Notch_Analysis_updated_files/figure-html/multi-pathway-4.png new file mode 100644 index 0000000..c9d141c Binary files /dev/null and b/docs/articles/Notch_Analysis_updated_files/figure-html/multi-pathway-4.png differ diff --git a/docs/articles/Notch_Analysis_updated_files/figure-html/notch-aging-1.png b/docs/articles/Notch_Analysis_updated_files/figure-html/notch-aging-1.png new file mode 100644 index 0000000..ea91fbe Binary files /dev/null and b/docs/articles/Notch_Analysis_updated_files/figure-html/notch-aging-1.png differ diff --git a/docs/articles/Notch_Analysis_updated_files/figure-html/notch-ko-1.png b/docs/articles/Notch_Analysis_updated_files/figure-html/notch-ko-1.png new file mode 100644 index 0000000..269853e Binary files /dev/null and b/docs/articles/Notch_Analysis_updated_files/figure-html/notch-ko-1.png differ diff --git a/docs/articles/Notch_Analysis_updated_files/figure-html/notch-ko-2.png b/docs/articles/Notch_Analysis_updated_files/figure-html/notch-ko-2.png new file mode 100644 index 0000000..e2c488b Binary files /dev/null and b/docs/articles/Notch_Analysis_updated_files/figure-html/notch-ko-2.png differ diff --git a/docs/articles/TGFB_database_construction.html b/docs/articles/TGFB_database_construction.html new file mode 100644 index 0000000..0ea141e --- /dev/null +++ b/docs/articles/TGFB_database_construction.html @@ -0,0 +1,834 @@ + + + + + + + +TGF-β Pathway Database Construction • PathwayEmbed + + + + + + + + Skip to contents + + +
+ + + + +
+
+ + + +
+
+

Overview +

+

This vignette documents the construction of the TGF-β +signaling pathway database used by PathwayEmbed +for downstream pathway activity scoring and embedding. The same +construction workflow is applied to all pathway databases in the package +(e.g., WNT, NOTCH, YAP); the TGF-β pathway is used here as the worked +example.

+

The database integrates:

+
    +
  1. A manually curated pathway gene list organized by functional +category (KEGG hsa04350 )
  2. +
  3. Separately curated mouse ortholog lists, with attention to symbols +that differ substantially between species
  4. +
  5. Differential expression results from two independent bulk RNA-seq +datasets covering multiple species and contexts
  6. +
  7. Per-gene activity coefficients (+1 / −1) derived +from the direction of regulation under TGF-β stimulation
  8. +
+

The final output is a formatted Excel workbook +(TGFB_Pathway_Database.xlsx) with three sheets: human Day +1, human Day 20, and mouse.

+

Datasets used:

+ ++++++ + + + + + + + + + + + + + + + + + + + + +
GEO AccessionSpeciesModelComparison
GSE110021HumanLung fibroblastsTGFβ1 vs. no TGFβ at Day 1 and Day 20
GSE246932MouseT cellsTGFβ vs. none (2h)
+
+
+
+

Step 1: Curate the Pathway Gene List +

+
+

Human Gene List +

+

TGF-β pathway genes were curated from KEGG hsa04350 +and organized into 20 functional categories spanning canonical SMAD +signaling, non-canonical branches (MAPK, PI3K/AKT, RHO), and the +extracellular ligand/antagonist landscape.

+
+tgfb_genes_human <- list(
+
+  Ligands_TGFB = c("TGFB1", "TGFB2", "TGFB3"),
+
+  Ligands_BMP = c("BMP2", "BMP4", "BMP5", "BMP6", "BMP7", "BMP8A", "BMP8B",
+                  "BMP10", "BMP15", "GDF5", "GDF6", "GDF7"),
+
+  # NOTE: INHBC and INHBE have no mouse orthologs (see mouse section)
+  Ligands_Activin_GDF = c("INHBA", "INHBB", "INHBC", "INHBE",
+                          "GDF1", "GDF2", "GDF3", "GDF8", "GDF9", "GDF10",
+                          "GDF11", "GDF15", "AMH", "NODAL"),
+
+  Receptors_TypeI   = c("TGFBR1", "ACVR1", "ACVR1B", "ACVR1C",
+                        "BMPR1A", "BMPR1B", "ACVRL1"),
+
+  Receptors_TypeII  = c("TGFBR2", "ACVR2A", "ACVR2B", "BMPR2", "AMHR2"),
+
+  # Type III receptors act as co-receptors/presenters
+  Receptors_TypeIII = c("TGFBR3", "ENG"),
+
+  # R-SMADs: phosphorylated by type I receptors; SMAD1/5/9 for BMP arm,
+  # SMAD2/3 for TGF-β/Activin arm
+  SMAD_Regulated  = c("SMAD1", "SMAD2", "SMAD3", "SMAD5", "SMAD9"),
+  SMAD_Common     = c("SMAD4"),
+  SMAD_Inhibitory = c("SMAD6", "SMAD7"),
+
+  # SARA (ZFYVE9) anchors SMAD2/3 at the receptor membrane
+  SMAD_Anchors = c("SARA", "ZFYVE9"),
+
+  Coactivators = c("CREBBP", "EP300", "SKI", "SKIL", "CITED1", "CITED2",
+                   "FOXH1", "FOXO1", "FOXO3", "RUNX1", "RUNX2", "RUNX3",
+                   "SP1", "JUN", "FOS", "ATF2"),
+
+  Corepressors = c("TGIF1", "TGIF2", "SKI", "SKIL", "SIN3A", "NCOR1",
+                   "NCOR2", "HDAC1", "HDAC2", "HDAC3"),
+
+  E3_Ligases = c("SMURF1", "SMURF2", "NEDD4L", "WWP1", "WWP2",
+                 "RNF12", "STUB1", "TRIM33"),
+
+  Transcriptional_Targets = c(
+    "SERPINE1", "SMAD7", "CDKN1A", "CDKN2B",
+    "MYC", "SNAI1", "SNAI2", "TWIST1", "ZEB1", "ZEB2",
+    "VIM", "CDH1", "CDH2", "MMP2", "MMP9",
+    "COL1A1", "COL1A2", "COL3A1", "FN1", "ACTA2",
+    "CTGF", "TGFB1", "ID1", "ID2", "ID3"
+  ),
+
+  Secreted_Antagonists = c(
+    "FST", "FSTL1", "FSTL3", "CHRD", "CHRDL1", "CHRDL2",
+    "NOG", "GREM1", "GREM2", "NBL1", "BAMBI",
+    "LTBP1", "LTBP2", "LTBP3", "LTBP4", "THBS1", "THBS2",
+    "DCN", "BGN", "ASPN"
+  ),
+
+  MAPK_Pathway = c(
+    "MAP3K7", "TAB1", "TAB2", "TAB3",
+    "MAP2K3", "MAP2K4", "MAP2K6", "MAP2K7",
+    "MAPK1", "MAPK3", "MAPK8", "MAPK9", "MAPK10",
+    "MAPK11", "MAPK12", "MAPK13", "MAPK14"
+  ),
+
+  PI3K_AKT_Pathway = c("PIK3CA", "PIK3CB", "PIK3CD", "PIK3R1", "PIK3R2",
+                       "AKT1", "AKT2", "AKT3", "MTOR", "RHEB"),
+
+  RHO_Pathway = c("RHOA", "RAC1", "CDC42", "ROCK1", "ROCK2",
+                  "TGFBR1", "PAK1", "PAK2", "LIMK1", "LIMK2"),
+
+  Latency_Activation = c(
+    "LTBP1", "LTBP2", "LTBP3", "LTBP4",
+    "LRRC32", "LRRC33", "THBS1", "ITGAV", "ITGB1",
+    "ITGB3", "ITGB5", "ITGB6", "ITGB8", "MMP2", "MMP9"
+  ),
+
+  Phosphatases = c("PPM1A", "PPP1CA", "PPP1CB", "PPP1CC", "MTMR4"),
+
+  Nuclear_Transport = c("IMPORTIN7", "IMPORTIN8", "XPO1", "RAN"),
+
+  Other_Regulators = c(
+    "DAXX", "FNTA", "FKBP1A", "ELF", "YAP1", "TAZ",
+    "PMEPA1", "TRIM33", "EVI1", "BCOR", "DRAP1", "MAML1",
+    "PPP2CA", "PPP2R1A", "STRAP", "CDKN1B", "CDKN1C",
+    "RBL1", "RBL2", "E2F4", "E2F5", "COPS5"
+  )
+)
+
+# Genes per category
+sapply(tgfb_genes_human, length)
+#>            Ligands_TGFB             Ligands_BMP     Ligands_Activin_GDF 
+#>                       3                      12                      14 
+#>         Receptors_TypeI        Receptors_TypeII       Receptors_TypeIII 
+#>                       7                       5                       2 
+#>          SMAD_Regulated             SMAD_Common         SMAD_Inhibitory 
+#>                       5                       1                       2 
+#>            SMAD_Anchors            Coactivators            Corepressors 
+#>                       2                      16                      10 
+#>              E3_Ligases Transcriptional_Targets    Secreted_Antagonists 
+#>                       8                      25                      20 
+#>            MAPK_Pathway        PI3K_AKT_Pathway             RHO_Pathway 
+#>                      17                      10                      10 
+#>      Latency_Activation            Phosphatases       Nuclear_Transport 
+#>                      15                       5                       4 
+#>        Other_Regulators 
+#>                      22
+cat("Total unique human TGF-β genes:", length(unique(unlist(tgfb_genes_human))), "\n")
+#> Total unique human TGF-β genes: 202
+
+
+

Mouse Gene List +

+
+

⚠️ Mouse symbols are NOT simply lowercased human +symbols. The mouse list was curated manually with special +attention to genes that have completely different symbols between +species. Key differences are highlighted below.

+
+
+# Critical human → mouse symbol differences:
+# RNF12       → Rlim          (E3_Ligases)
+# IMPORTIN7   → Ipo7          (Nuclear_Transport)
+# IMPORTIN8   → Ipo8          (Nuclear_Transport)
+# TAZ (WWTR1) → Wwtr1         (Other_Regulators)
+# EVI1 (MECOM)→ Mecom         (Other_Regulators)
+# SARA        → removed (protein name, not gene; gene is Zfyve9)
+# INHBC, INHBE→ removed (no mouse ortholog)
+# ELF         → removed (ambiguous; could be Elf1–5)
+
+tgfb_genes_mouse <- list(
+
+  Ligands_TGFB        = c("Tgfb1", "Tgfb2", "Tgfb3"),
+
+  Ligands_BMP         = c("Bmp2", "Bmp4", "Bmp5", "Bmp6", "Bmp7", "Bmp8a", "Bmp8b",
+                          "Bmp10", "Bmp15", "Gdf5", "Gdf6", "Gdf7"),
+
+  # INHBC and INHBE have no mouse orthologs and are excluded
+  Ligands_Activin_GDF = c("Inhba", "Inhbb",
+                          "Gdf1", "Gdf2", "Gdf3", "Gdf8", "Gdf9", "Gdf10",
+                          "Gdf11", "Gdf15", "Amh", "Nodal"),
+
+  Receptors_TypeI     = c("Tgfbr1", "Acvr1", "Acvr1b", "Acvr1c",
+                          "Bmpr1a", "Bmpr1b", "Acvrl1"),
+
+  Receptors_TypeII    = c("Tgfbr2", "Acvr2a", "Acvr2b", "Bmpr2", "Amhr2"),
+
+  Receptors_TypeIII   = c("Tgfbr3", "Eng"),
+
+  SMAD_Regulated      = c("Smad1", "Smad2", "Smad3", "Smad5", "Smad9"),
+  SMAD_Common         = c("Smad4"),
+  SMAD_Inhibitory     = c("Smad6", "Smad7"),
+
+  # SARA is a protein name for ZFYVE9; only the gene symbol is used
+  SMAD_Anchors        = c("Zfyve9"),
+
+  Coactivators        = c("Crebbp", "Ep300", "Ski", "Skil", "Cited1", "Cited2",
+                          "Foxh1", "Foxo1", "Foxo3", "Runx1", "Runx2", "Runx3",
+                          "Sp1", "Jun", "Fos", "Atf2"),
+
+  Corepressors        = c("Tgif1", "Tgif2", "Ski", "Skil", "Sin3a", "Ncor1",
+                          "Ncor2", "Hdac1", "Hdac2", "Hdac3"),
+
+  # RNF12 (human) = Rlim (mouse) — different symbol!
+  E3_Ligases          = c("Smurf1", "Smurf2", "Nedd4l", "Wwp1", "Wwp2",
+                          "Rlim", "Stub1", "Trim33"),
+
+  Transcriptional_Targets = c(
+    "Serpine1", "Smad7", "Cdkn1a", "Cdkn2b",
+    "Myc", "Snai1", "Snai2", "Twist1", "Zeb1", "Zeb2",
+    "Vim", "Cdh1", "Cdh2", "Mmp2", "Mmp9",
+    "Col1a1", "Col1a2", "Col3a1", "Fn1", "Acta2",
+    "Ctgf", "Tgfb1", "Id1", "Id2", "Id3"
+  ),
+
+  Secreted_Antagonists = c(
+    "Fst", "Fstl1", "Fstl3", "Chrd", "Chrdl1", "Chrdl2",
+    "Nog", "Grem1", "Grem2", "Nbl1", "Bambi",
+    "Ltbp1", "Ltbp2", "Ltbp3", "Ltbp4", "Thbs1", "Thbs2",
+    "Dcn", "Bgn", "Aspn"
+  ),
+
+  MAPK_Pathway        = c("Map3k7", "Tab1", "Tab2", "Tab3",
+                          "Map2k3", "Map2k4", "Map2k6", "Map2k7",
+                          "Mapk1", "Mapk3", "Mapk8", "Mapk9", "Mapk10",
+                          "Mapk11", "Mapk12", "Mapk13", "Mapk14"),
+
+  PI3K_AKT_Pathway    = c("Pik3ca", "Pik3cb", "Pik3cd", "Pik3r1", "Pik3r2",
+                          "Akt1", "Akt2", "Akt3", "Mtor", "Rheb"),
+
+  RHO_Pathway         = c("Rhoa", "Rac1", "Cdc42", "Rock1", "Rock2",
+                          "Tgfbr1", "Pak1", "Pak2", "Limk1", "Limk2"),
+
+  Latency_Activation  = c("Ltbp1", "Ltbp2", "Ltbp3", "Ltbp4",
+                          "Lrrc32", "Lrrc33", "Thbs1", "Itgav", "Itgb1",
+                          "Itgb3", "Itgb5", "Itgb6", "Itgb8", "Mmp2", "Mmp9"),
+
+  Phosphatases        = c("Ppm1a", "Ppp1ca", "Ppp1cb", "Ppp1cc", "Mtmr4"),
+
+  # IMPORTIN7 = Ipo7, IMPORTIN8 = Ipo8 in mouse
+  Nuclear_Transport   = c("Ipo7", "Ipo8", "Xpo1", "Ran"),
+
+  # TAZ = Wwtr1 (mouse), EVI1 = Mecom (mouse)
+  Other_Regulators    = c("Daxx", "Fnta", "Fkbp1a",
+                          "Yap1", "Wwtr1", "Pmepa1", "Trim33",
+                          "Mecom", "Bcor", "Drap1", "Maml1",
+                          "Ppp2ca", "Ppp2r1a", "Strap", "Cdkn1b", "Cdkn1c",
+                          "Rbl1", "Rbl2", "E2f4", "E2f5", "Cops5")
+)
+
+cat("Total unique mouse TGF-β genes:", length(unique(unlist(tgfb_genes_mouse))), "\n")
+#> Total unique mouse TGF-β genes: 198
+
+
+

Flatten to Data Frames +

+

Both lists are converted to flat two-column data frames +(gene, category) for downstream joining +operations.

+
+flatten_gene_list <- function(gene_list) {
+  do.call(rbind, lapply(names(gene_list), function(cat) {
+    data.frame(gene = gene_list[[cat]], category = cat, stringsAsFactors = FALSE)
+  }))
+}
+
+tgfb_genes_human_flat <- flatten_gene_list(tgfb_genes_human)
+tgfb_genes_mouse_flat <- flatten_gene_list(tgfb_genes_mouse)
+
+head(tgfb_genes_human_flat)
+#>    gene     category
+#> 1 TGFB1 Ligands_TGFB
+#> 2 TGFB2 Ligands_TGFB
+#> 3 TGFB3 Ligands_TGFB
+#> 4  BMP2  Ligands_BMP
+#> 5  BMP4  Ligands_BMP
+#> 6  BMP5  Ligands_BMP
+
+
+
+
+

Step 2: Bulk RNA-seq Differential Expression +

+
+

Human — Lung Fibroblasts (GSE110021) +

+

Human WI-38 fibroblasts were treated with TGFβ1 and profiled at +Day 1 (acute response) and Day 20 +(chronic/fibrotic response). The dataset provides voom-normalized +log-counts, so limma is applied directly without further +normalization.

+
+library(limma)
+
+# Load voom-normalized expression matrix
+data_fibroblasts <- read.table(
+  "GSE110021_counts.voom.annot.txt.gz",
+  header = TRUE, sep = "\t", row.names = 1
+)
+
+# Separate expression values from annotation columns
+expr <- as.matrix(data_fibroblasts[, -(1:2)])
+rownames(expr) <- data_fibroblasts$GeneSymbol
+
+# Sample metadata: 24 samples total, 12 per treatment, 6 per timepoint per treatment
+sample_info <- data.frame(
+  sample    = colnames(expr),
+  treatment = rep(c("noTGFb", "TGFb"), each = 12),
+  timepoint = rep(c("D1", "D20"), each = 6, times = 2)
+)
+
+# Design matrix with all four groups
+design <- model.matrix(~ 0 + treatment:timepoint, data = sample_info)
+colnames(design) <- c("D1_noTGFb", "D1_TGFb", "D20_noTGFb", "D20_TGFb")
+
+fit <- lmFit(expr, design)
+
+# Contrasts: TGFb vs. control at each timepoint
+contrast_matrix <- makeContrasts(
+  D1_TGFb_vs_noTGFb  = D1_TGFb  - D1_noTGFb,
+  D20_TGFb_vs_noTGFb = D20_TGFb - D20_noTGFb,
+  levels = design
+)
+
+fit2 <- contrasts.fit(fit, contrast_matrix)
+fit2 <- eBayes(fit2)
+
+# Extract full results tables
+res_D1  <- topTable(fit2, coef = "D1_TGFb_vs_noTGFb",  number = Inf, sort.by = "p")
+res_D20 <- topTable(fit2, coef = "D20_TGFb_vs_noTGFb", number = Inf, sort.by = "p")
+
+# Add gene descriptions
+res_D1$Description  <- data_fibroblasts$Description[match(rownames(res_D1),  data_fibroblasts$GeneSymbol)]
+res_D20$Description <- data_fibroblasts$Description[match(rownames(res_D20), data_fibroblasts$GeneSymbol)]
+
+write.csv(res_D1,  "DEG_D1_TGFb_vs_noTGFb.csv",  row.names = TRUE)
+write.csv(res_D20, "DEG_D20_TGFb_vs_noTGFb.csv", row.names = TRUE)
+
+
+

Mouse — T Cells (GSE246932) +

+

Mouse CD8+ T cells were treated with TGFβ for 2 hours. Raw count data +required DESeq2 for normalization and differential testing.

+
+library(DESeq2)
+library(dplyr)
+
+# Load raw counts
+counts_data <- read.csv(
+  "GSE246932_220809-P490-1_RawGeneCounts.csv.gz",
+  header = TRUE, check.names = FALSE
+)
+
+# Remove SIINFEKL peptide-treated samples (not relevant to TGFb comparison)
+counts_data <- counts_data[, !grepl("SIINFEKL", colnames(counts_data))]
+
+# Separate gene annotation from count columns
+gene_anno  <- counts_data[, 1:4]
+counts_only <- counts_data[, -(1:4)]
+
+# Collapse duplicate gene IDs by summing
+counts_collapsed <- counts_only %>%
+  mutate(geneId = gene_anno$geneId) %>%
+  group_by(geneId) %>%
+  summarise(across(where(is.numeric), sum), .groups = "drop")
+
+counts_mat <- as.matrix(counts_collapsed[, -1])
+rownames(counts_mat) <- counts_collapsed$geneId
+
+# Build DESeq2 object
+sample_names <- colnames(counts_mat)
+coldata <- data.frame(
+  treatment = factor(
+    ifelse(grepl("TGFb", sample_names), "TGFb", "none"),
+    levels = c("none", "TGFb")
+  ),
+  row.names = sample_names
+)
+
+dds <- DESeqDataSetFromMatrix(
+  countData = counts_mat,
+  colData   = coldata,
+  design    = ~ treatment
+)
+dds <- dds[rowSums(counts(dds)) > 10, ]  # low-count filter
+dds <- DESeq(dds)
+
+res    <- results(dds, contrast = c("treatment", "TGFb", "none"))
+res_df <- as.data.frame(res)
+
+# Map gene names back from annotation
+res_df$geneId      <- rownames(res_df)
+res_df$geneName    <- gene_anno$geneName[match(res_df$geneId, gene_anno$geneId)]
+res_df$description <- gene_anno$description[match(res_df$geneId, gene_anno$geneId)]
+
+library(openxlsx)
+write.xlsx(res_df, file = "Mus_TGFb_vs_none.xlsx", rowNames = FALSE)
+
+
+
+
+

Step 3: Filter for TGF-β Pathway Genes +

+

DEG results are joined against the curated gene lists, retaining only +TGF-β pathway members that reach statistical significance (adjusted +p < 0.05).

+
+library(readr)
+library(readxl)
+library(dplyr)
+
+human_d1  <- read_csv("DEG_D1_TGFb_vs_noTGFb.csv")
+human_d20 <- read_csv("DEG_D20_TGFb_vs_noTGFb.csv")
+mouse_df  <- read_excel("Mus_TGFb_vs_none.xlsx")
+
+# Human Day 1
+human_d1_results <- human_d1 %>%
+  filter(ID %in% tgfb_genes_human_flat$gene) %>%
+  left_join(tgfb_genes_human_flat, by = c("ID" = "gene")) %>%
+  filter(!is.na(adj.P.Val) & adj.P.Val < 0.05) %>%
+  arrange(adj.P.Val)
+
+# Human Day 20
+human_d20_results <- human_d20 %>%
+  filter(ID %in% tgfb_genes_human_flat$gene) %>%
+  left_join(tgfb_genes_human_flat, by = c("ID" = "gene")) %>%
+  filter(!is.na(adj.P.Val) & adj.P.Val < 0.05) %>%
+  arrange(adj.P.Val)
+
+# Mouse
+mouse_df_results <- mouse_df %>%
+  filter(geneName %in% tgfb_genes_mouse_flat$gene) %>%
+  left_join(tgfb_genes_mouse_flat, by = c("geneName" = "gene")) %>%
+  filter(!is.na(padj) & padj < 0.05) %>%
+  arrange(padj)
+
+cat("Human D1  pathway genes (padj<0.05):", nrow(human_d1_results),  "\n")
+cat("Human D20 pathway genes (padj<0.05):", nrow(human_d20_results), "\n")
+cat("Mouse     pathway genes (padj<0.05):", nrow(mouse_df_results),  "\n")
+
+
+
+

Step 4: Assign Activity Coefficients +

+
+

Rationale +

+

Each gene receives a direction coefficient +reflecting its behavior under TGFβ activation:

+ ++++ + + + + + + + + + + + + + + +
CoefficientMeaning
+1Upregulated with TGFβ — consistent with pathway activation
−1Downregulated with TGFβ — consistent with pathway inhibition
+

These coefficients are used by PathwayEmbed to compute a +signed pathway activity score: the weighted sum of a +sample’s expression values multiplied by their coefficients, giving a +single number that reflects the net direction and magnitude of TGF-β +activity.

+

The function also supports inhibitor experiments via +TGFB_activation = FALSE, which flips the sign logic — a +gene downregulated by an inhibitor is inferred to be positively +regulated under activation.

+
+assign_coefficient_tgfb <- function(log2FoldChange,
+                                    fc_threshold    = 0,
+                                    TGFB_activation = TRUE) {
+  if (is.na(log2FoldChange)) return(0)
+
+  if (TGFB_activation) {
+    if      (log2FoldChange >  fc_threshold) return( 1)
+    else if (log2FoldChange < -fc_threshold) return(-1)
+    else                                      return( 0)
+  } else {
+    # Inhibitor data: flip direction
+    if      (log2FoldChange < -fc_threshold) return( 1)
+    else if (log2FoldChange >  fc_threshold) return(-1)
+    else                                      return( 0)
+  }
+}
+
+

Threshold note: fc_threshold = 0 +assigns a coefficient to any non-zero fold-change. For stricter +databases, use fc_threshold = 0.5 to restrict to genes with +|log₂FC| ≥ 0.5, focusing on more robust responses.

+
+
+human_d1_results <- human_d1_results %>%
+  mutate(coef = sapply(logFC, assign_coefficient_tgfb, fc_threshold = 0))
+
+human_d20_results <- human_d20_results %>%
+  mutate(coef = sapply(logFC, assign_coefficient_tgfb, fc_threshold = 0))
+
+mouse_df_results <- mouse_df_results %>%
+  mutate(coef = sapply(log2FoldChange, assign_coefficient_tgfb, fc_threshold = 0))
+
+
+
+
+

Step 5: Export to Excel +

+

The final database is exported as a formatted .xlsx +workbook with a styled header row, frozen pane, and auto-sized +columns.

+
+library(openxlsx)
+
+# --- Helper: prepare one sheet's data frame ---
+prepare_sheet <- function(results, gene_col, logfc_col) {
+  results %>%
+    dplyr::select(
+      Gene_Symbol    = !!sym(gene_col),
+      Category       = category,
+      Coefficient    = coef,
+      log2FoldChange = !!sym(logfc_col)
+    ) %>%
+    as.data.frame()
+}
+
+human_d1_sheet  <- prepare_sheet(human_d1_results,  "ID",       "logFC")
+human_d20_sheet <- prepare_sheet(human_d20_results, "ID",       "logFC")
+mouse_df_sheet  <- prepare_sheet(mouse_df_results,  "geneName", "log2FoldChange")
+
+# --- Helper: write one formatted sheet ---
+add_pathway_sheet <- function(wb, sheet_name, df) {
+
+  addWorksheet(wb, sheet_name)
+
+  writeData(wb, sheet_name, df,
+    headerStyle = createStyle(
+      fontSize = 11, fontColour = "#FFFFFF", halign = "center",
+      fgFill = "#4472C4", border = "TopBottom",
+      fontName = "Arial", textDecoration = "bold"
+    )
+  )
+
+  freezePane(wb, sheet_name, firstRow = TRUE)
+  tryCatch(
+    setColWidths(wb, sheet_name, cols = seq_len(ncol(df)), widths = "auto"),
+    error = function(e)
+      setColWidths(wb, sheet_name, cols = seq_len(ncol(df)), widths = 15)
+  )
+}
+
+# --- Build workbook ---
+wb <- createWorkbook()
+add_pathway_sheet(wb, "TGFB_Human_D1",  human_d1_sheet)
+add_pathway_sheet(wb, "TGFB_Human_D20", human_d20_sheet)
+add_pathway_sheet(wb, "TGFB_Mouse",     mouse_df_sheet)
+
+saveWorkbook(wb, "TGFB_Pathway_Database.xlsx", overwrite = TRUE)
+cat("Saved: TGFB_Pathway_Database.xlsx\n")
+
+
+
+

Final Database Structure +

+

Each sheet in TGFB_Pathway_Database.xlsx contains:

+ ++++ + + + + + + + + + + + + + + + + + + + + + + +
ColumnDescription
Gene_SymbolHGNC (human) or MGI (mouse) gene symbol
CategoryFunctional category from KEGG + curation
Coefficient+1 (activated) or −1 (repressed) under TGFβ; filtered by padj < +0.05
log2FoldChangeLog₂ fold-change from the corresponding DEG analysis
+

Sheets produced:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
SheetSpeciesContextMethod
TGFB_Human_D1HumanLung fibroblasts, Day 1limma / voom
TGFB_Human_D20HumanLung fibroblasts, Day 20limma / voom
TGFB_MouseMouseCD8+ T cells, 2hDESeq2
+
+
+
+

Important Curation Notes +

+

The following caveats should be kept in mind when extending or +modifying the database:

+

Genes excluded from the mouse list due to no +ortholog: INHBC, INHBE — these +activin subunits are primate-specific and have no mouse ortholog.

+

Gene name ambiguities resolved: SARA is +a protein alias for the gene ZFYVE9 and should not be used +as a gene symbol. ELF is ambiguous (could refer to +ELF1 through ELF5) and was removed from the +mouse list.

+

Genes with completely different human/mouse +symbols:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HumanMouseCategory
RNF12RlimE3_Ligases
IMPORTIN7Ipo7Nuclear_Transport
IMPORTIN8Ipo8Nuclear_Transport
TAZ (WWTR1)Wwtr1Other_Regulators
EVI1 (MECOM)MecomOther_Regulators
+

Always verify mouse gene symbols against MGI before adding new +genes.

+
+
+
+

Session Information +

+
+sessionInfo()
+#> R version 4.4.2 (2024-10-31)
+#> Platform: aarch64-apple-darwin20
+#> Running under: macOS Sonoma 14.6
+#> 
+#> Matrix products: default
+#> BLAS:   /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRblas.0.dylib 
+#> LAPACK: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.0
+#> 
+#> locale:
+#> [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
+#> 
+#> time zone: America/New_York
+#> tzcode source: internal
+#> 
+#> attached base packages:
+#> [1] stats     graphics  grDevices utils     datasets  methods   base     
+#> 
+#> loaded via a namespace (and not attached):
+#>  [1] digest_0.6.39     desc_1.4.3        R6_2.6.1          fastmap_1.2.0    
+#>  [5] xfun_0.57         cachem_1.1.0      knitr_1.51        htmltools_0.5.9  
+#>  [9] rmarkdown_2.30    lifecycle_1.0.5   cli_3.6.5         sass_0.4.10      
+#> [13] pkgdown_2.2.0     textshaping_1.0.5 jquerylib_0.1.4   systemfonts_1.3.2
+#> [17] compiler_4.4.2    rstudioapi_0.18.0 tools_4.4.2       ragg_1.5.1       
+#> [21] bslib_0.10.0      evaluate_1.0.5    yaml_2.3.12       otel_0.2.0       
+#> [25] jsonlite_2.0.0    htmlwidgets_1.6.4 rlang_1.1.7       fs_1.6.7
+
+
+
+ + + +
+ + + +
+
+ + + + + + + diff --git a/docs/articles/TGFB_database_construction.md b/docs/articles/TGFB_database_construction.md new file mode 100644 index 0000000..2f8c6d4 --- /dev/null +++ b/docs/articles/TGFB_database_construction.md @@ -0,0 +1,641 @@ +# TGF-β Pathway Database Construction + +------------------------------------------------------------------------ + +## Overview + +This vignette documents the construction of the **TGF-β signaling +pathway database** used by `PathwayEmbed` for downstream pathway +activity scoring and embedding. The same construction workflow is +applied to all pathway databases in the package (e.g., WNT, NOTCH, YAP); +the TGF-β pathway is used here as the worked example. + +The database integrates: + +1. A manually curated pathway gene list organized by functional + category (KEGG hsa04350 ) +2. Separately curated mouse ortholog lists, with attention to symbols + that differ substantially between species +3. Differential expression results from two independent bulk RNA-seq + datasets covering multiple species and contexts +4. Per-gene **activity coefficients** (+1 / −1) derived from the + direction of regulation under TGF-β stimulation + +The final output is a formatted Excel workbook +(`TGFB_Pathway_Database.xlsx`) with three sheets: human Day 1, human Day +20, and mouse. + +**Datasets used:** + +| GEO Accession | Species | Model | Comparison | +|----|----|----|----| +| GSE110021 | Human | Lung fibroblasts | TGFβ1 vs. no TGFβ at Day 1 and Day 20 | +| GSE246932 | Mouse | T cells | TGFβ vs. none (2h) | + +------------------------------------------------------------------------ + +## Step 1: Curate the Pathway Gene List + +### Human Gene List + +TGF-β pathway genes were curated from **KEGG hsa04350** and organized +into 20 functional categories spanning canonical SMAD signaling, +non-canonical branches (MAPK, PI3K/AKT, RHO), and the extracellular +ligand/antagonist landscape. + +``` r +tgfb_genes_human <- list( + + Ligands_TGFB = c("TGFB1", "TGFB2", "TGFB3"), + + Ligands_BMP = c("BMP2", "BMP4", "BMP5", "BMP6", "BMP7", "BMP8A", "BMP8B", + "BMP10", "BMP15", "GDF5", "GDF6", "GDF7"), + + # NOTE: INHBC and INHBE have no mouse orthologs (see mouse section) + Ligands_Activin_GDF = c("INHBA", "INHBB", "INHBC", "INHBE", + "GDF1", "GDF2", "GDF3", "GDF8", "GDF9", "GDF10", + "GDF11", "GDF15", "AMH", "NODAL"), + + Receptors_TypeI = c("TGFBR1", "ACVR1", "ACVR1B", "ACVR1C", + "BMPR1A", "BMPR1B", "ACVRL1"), + + Receptors_TypeII = c("TGFBR2", "ACVR2A", "ACVR2B", "BMPR2", "AMHR2"), + + # Type III receptors act as co-receptors/presenters + Receptors_TypeIII = c("TGFBR3", "ENG"), + + # R-SMADs: phosphorylated by type I receptors; SMAD1/5/9 for BMP arm, + # SMAD2/3 for TGF-β/Activin arm + SMAD_Regulated = c("SMAD1", "SMAD2", "SMAD3", "SMAD5", "SMAD9"), + SMAD_Common = c("SMAD4"), + SMAD_Inhibitory = c("SMAD6", "SMAD7"), + + # SARA (ZFYVE9) anchors SMAD2/3 at the receptor membrane + SMAD_Anchors = c("SARA", "ZFYVE9"), + + Coactivators = c("CREBBP", "EP300", "SKI", "SKIL", "CITED1", "CITED2", + "FOXH1", "FOXO1", "FOXO3", "RUNX1", "RUNX2", "RUNX3", + "SP1", "JUN", "FOS", "ATF2"), + + Corepressors = c("TGIF1", "TGIF2", "SKI", "SKIL", "SIN3A", "NCOR1", + "NCOR2", "HDAC1", "HDAC2", "HDAC3"), + + E3_Ligases = c("SMURF1", "SMURF2", "NEDD4L", "WWP1", "WWP2", + "RNF12", "STUB1", "TRIM33"), + + Transcriptional_Targets = c( + "SERPINE1", "SMAD7", "CDKN1A", "CDKN2B", + "MYC", "SNAI1", "SNAI2", "TWIST1", "ZEB1", "ZEB2", + "VIM", "CDH1", "CDH2", "MMP2", "MMP9", + "COL1A1", "COL1A2", "COL3A1", "FN1", "ACTA2", + "CTGF", "TGFB1", "ID1", "ID2", "ID3" + ), + + Secreted_Antagonists = c( + "FST", "FSTL1", "FSTL3", "CHRD", "CHRDL1", "CHRDL2", + "NOG", "GREM1", "GREM2", "NBL1", "BAMBI", + "LTBP1", "LTBP2", "LTBP3", "LTBP4", "THBS1", "THBS2", + "DCN", "BGN", "ASPN" + ), + + MAPK_Pathway = c( + "MAP3K7", "TAB1", "TAB2", "TAB3", + "MAP2K3", "MAP2K4", "MAP2K6", "MAP2K7", + "MAPK1", "MAPK3", "MAPK8", "MAPK9", "MAPK10", + "MAPK11", "MAPK12", "MAPK13", "MAPK14" + ), + + PI3K_AKT_Pathway = c("PIK3CA", "PIK3CB", "PIK3CD", "PIK3R1", "PIK3R2", + "AKT1", "AKT2", "AKT3", "MTOR", "RHEB"), + + RHO_Pathway = c("RHOA", "RAC1", "CDC42", "ROCK1", "ROCK2", + "TGFBR1", "PAK1", "PAK2", "LIMK1", "LIMK2"), + + Latency_Activation = c( + "LTBP1", "LTBP2", "LTBP3", "LTBP4", + "LRRC32", "LRRC33", "THBS1", "ITGAV", "ITGB1", + "ITGB3", "ITGB5", "ITGB6", "ITGB8", "MMP2", "MMP9" + ), + + Phosphatases = c("PPM1A", "PPP1CA", "PPP1CB", "PPP1CC", "MTMR4"), + + Nuclear_Transport = c("IMPORTIN7", "IMPORTIN8", "XPO1", "RAN"), + + Other_Regulators = c( + "DAXX", "FNTA", "FKBP1A", "ELF", "YAP1", "TAZ", + "PMEPA1", "TRIM33", "EVI1", "BCOR", "DRAP1", "MAML1", + "PPP2CA", "PPP2R1A", "STRAP", "CDKN1B", "CDKN1C", + "RBL1", "RBL2", "E2F4", "E2F5", "COPS5" + ) +) + +# Genes per category +sapply(tgfb_genes_human, length) +#> Ligands_TGFB Ligands_BMP Ligands_Activin_GDF +#> 3 12 14 +#> Receptors_TypeI Receptors_TypeII Receptors_TypeIII +#> 7 5 2 +#> SMAD_Regulated SMAD_Common SMAD_Inhibitory +#> 5 1 2 +#> SMAD_Anchors Coactivators Corepressors +#> 2 16 10 +#> E3_Ligases Transcriptional_Targets Secreted_Antagonists +#> 8 25 20 +#> MAPK_Pathway PI3K_AKT_Pathway RHO_Pathway +#> 17 10 10 +#> Latency_Activation Phosphatases Nuclear_Transport +#> 15 5 4 +#> Other_Regulators +#> 22 +cat("Total unique human TGF-β genes:", length(unique(unlist(tgfb_genes_human))), "\n") +#> Total unique human TGF-β genes: 202 +``` + +### Mouse Gene List + +> ⚠️ **Mouse symbols are NOT simply lowercased human symbols.** The +> mouse list was curated manually with special attention to genes that +> have completely different symbols between species. Key differences are +> highlighted below. + +``` r +# Critical human → mouse symbol differences: +# RNF12 → Rlim (E3_Ligases) +# IMPORTIN7 → Ipo7 (Nuclear_Transport) +# IMPORTIN8 → Ipo8 (Nuclear_Transport) +# TAZ (WWTR1) → Wwtr1 (Other_Regulators) +# EVI1 (MECOM)→ Mecom (Other_Regulators) +# SARA → removed (protein name, not gene; gene is Zfyve9) +# INHBC, INHBE→ removed (no mouse ortholog) +# ELF → removed (ambiguous; could be Elf1–5) + +tgfb_genes_mouse <- list( + + Ligands_TGFB = c("Tgfb1", "Tgfb2", "Tgfb3"), + + Ligands_BMP = c("Bmp2", "Bmp4", "Bmp5", "Bmp6", "Bmp7", "Bmp8a", "Bmp8b", + "Bmp10", "Bmp15", "Gdf5", "Gdf6", "Gdf7"), + + # INHBC and INHBE have no mouse orthologs and are excluded + Ligands_Activin_GDF = c("Inhba", "Inhbb", + "Gdf1", "Gdf2", "Gdf3", "Gdf8", "Gdf9", "Gdf10", + "Gdf11", "Gdf15", "Amh", "Nodal"), + + Receptors_TypeI = c("Tgfbr1", "Acvr1", "Acvr1b", "Acvr1c", + "Bmpr1a", "Bmpr1b", "Acvrl1"), + + Receptors_TypeII = c("Tgfbr2", "Acvr2a", "Acvr2b", "Bmpr2", "Amhr2"), + + Receptors_TypeIII = c("Tgfbr3", "Eng"), + + SMAD_Regulated = c("Smad1", "Smad2", "Smad3", "Smad5", "Smad9"), + SMAD_Common = c("Smad4"), + SMAD_Inhibitory = c("Smad6", "Smad7"), + + # SARA is a protein name for ZFYVE9; only the gene symbol is used + SMAD_Anchors = c("Zfyve9"), + + Coactivators = c("Crebbp", "Ep300", "Ski", "Skil", "Cited1", "Cited2", + "Foxh1", "Foxo1", "Foxo3", "Runx1", "Runx2", "Runx3", + "Sp1", "Jun", "Fos", "Atf2"), + + Corepressors = c("Tgif1", "Tgif2", "Ski", "Skil", "Sin3a", "Ncor1", + "Ncor2", "Hdac1", "Hdac2", "Hdac3"), + + # RNF12 (human) = Rlim (mouse) — different symbol! + E3_Ligases = c("Smurf1", "Smurf2", "Nedd4l", "Wwp1", "Wwp2", + "Rlim", "Stub1", "Trim33"), + + Transcriptional_Targets = c( + "Serpine1", "Smad7", "Cdkn1a", "Cdkn2b", + "Myc", "Snai1", "Snai2", "Twist1", "Zeb1", "Zeb2", + "Vim", "Cdh1", "Cdh2", "Mmp2", "Mmp9", + "Col1a1", "Col1a2", "Col3a1", "Fn1", "Acta2", + "Ctgf", "Tgfb1", "Id1", "Id2", "Id3" + ), + + Secreted_Antagonists = c( + "Fst", "Fstl1", "Fstl3", "Chrd", "Chrdl1", "Chrdl2", + "Nog", "Grem1", "Grem2", "Nbl1", "Bambi", + "Ltbp1", "Ltbp2", "Ltbp3", "Ltbp4", "Thbs1", "Thbs2", + "Dcn", "Bgn", "Aspn" + ), + + MAPK_Pathway = c("Map3k7", "Tab1", "Tab2", "Tab3", + "Map2k3", "Map2k4", "Map2k6", "Map2k7", + "Mapk1", "Mapk3", "Mapk8", "Mapk9", "Mapk10", + "Mapk11", "Mapk12", "Mapk13", "Mapk14"), + + PI3K_AKT_Pathway = c("Pik3ca", "Pik3cb", "Pik3cd", "Pik3r1", "Pik3r2", + "Akt1", "Akt2", "Akt3", "Mtor", "Rheb"), + + RHO_Pathway = c("Rhoa", "Rac1", "Cdc42", "Rock1", "Rock2", + "Tgfbr1", "Pak1", "Pak2", "Limk1", "Limk2"), + + Latency_Activation = c("Ltbp1", "Ltbp2", "Ltbp3", "Ltbp4", + "Lrrc32", "Lrrc33", "Thbs1", "Itgav", "Itgb1", + "Itgb3", "Itgb5", "Itgb6", "Itgb8", "Mmp2", "Mmp9"), + + Phosphatases = c("Ppm1a", "Ppp1ca", "Ppp1cb", "Ppp1cc", "Mtmr4"), + + # IMPORTIN7 = Ipo7, IMPORTIN8 = Ipo8 in mouse + Nuclear_Transport = c("Ipo7", "Ipo8", "Xpo1", "Ran"), + + # TAZ = Wwtr1 (mouse), EVI1 = Mecom (mouse) + Other_Regulators = c("Daxx", "Fnta", "Fkbp1a", + "Yap1", "Wwtr1", "Pmepa1", "Trim33", + "Mecom", "Bcor", "Drap1", "Maml1", + "Ppp2ca", "Ppp2r1a", "Strap", "Cdkn1b", "Cdkn1c", + "Rbl1", "Rbl2", "E2f4", "E2f5", "Cops5") +) + +cat("Total unique mouse TGF-β genes:", length(unique(unlist(tgfb_genes_mouse))), "\n") +#> Total unique mouse TGF-β genes: 198 +``` + +### Flatten to Data Frames + +Both lists are converted to flat two-column data frames (`gene`, +`category`) for downstream joining operations. + +``` r +flatten_gene_list <- function(gene_list) { + do.call(rbind, lapply(names(gene_list), function(cat) { + data.frame(gene = gene_list[[cat]], category = cat, stringsAsFactors = FALSE) + })) +} + +tgfb_genes_human_flat <- flatten_gene_list(tgfb_genes_human) +tgfb_genes_mouse_flat <- flatten_gene_list(tgfb_genes_mouse) + +head(tgfb_genes_human_flat) +#> gene category +#> 1 TGFB1 Ligands_TGFB +#> 2 TGFB2 Ligands_TGFB +#> 3 TGFB3 Ligands_TGFB +#> 4 BMP2 Ligands_BMP +#> 5 BMP4 Ligands_BMP +#> 6 BMP5 Ligands_BMP +``` + +------------------------------------------------------------------------ + +## Step 2: Bulk RNA-seq Differential Expression + +### Human — Lung Fibroblasts (GSE110021) + +Human WI-38 fibroblasts were treated with TGFβ1 and profiled at **Day +1** (acute response) and **Day 20** (chronic/fibrotic response). The +dataset provides voom-normalized log-counts, so limma is applied +directly without further normalization. + +``` r +library(limma) + +# Load voom-normalized expression matrix +data_fibroblasts <- read.table( + "GSE110021_counts.voom.annot.txt.gz", + header = TRUE, sep = "\t", row.names = 1 +) + +# Separate expression values from annotation columns +expr <- as.matrix(data_fibroblasts[, -(1:2)]) +rownames(expr) <- data_fibroblasts$GeneSymbol + +# Sample metadata: 24 samples total, 12 per treatment, 6 per timepoint per treatment +sample_info <- data.frame( + sample = colnames(expr), + treatment = rep(c("noTGFb", "TGFb"), each = 12), + timepoint = rep(c("D1", "D20"), each = 6, times = 2) +) + +# Design matrix with all four groups +design <- model.matrix(~ 0 + treatment:timepoint, data = sample_info) +colnames(design) <- c("D1_noTGFb", "D1_TGFb", "D20_noTGFb", "D20_TGFb") + +fit <- lmFit(expr, design) + +# Contrasts: TGFb vs. control at each timepoint +contrast_matrix <- makeContrasts( + D1_TGFb_vs_noTGFb = D1_TGFb - D1_noTGFb, + D20_TGFb_vs_noTGFb = D20_TGFb - D20_noTGFb, + levels = design +) + +fit2 <- contrasts.fit(fit, contrast_matrix) +fit2 <- eBayes(fit2) + +# Extract full results tables +res_D1 <- topTable(fit2, coef = "D1_TGFb_vs_noTGFb", number = Inf, sort.by = "p") +res_D20 <- topTable(fit2, coef = "D20_TGFb_vs_noTGFb", number = Inf, sort.by = "p") + +# Add gene descriptions +res_D1$Description <- data_fibroblasts$Description[match(rownames(res_D1), data_fibroblasts$GeneSymbol)] +res_D20$Description <- data_fibroblasts$Description[match(rownames(res_D20), data_fibroblasts$GeneSymbol)] + +write.csv(res_D1, "DEG_D1_TGFb_vs_noTGFb.csv", row.names = TRUE) +write.csv(res_D20, "DEG_D20_TGFb_vs_noTGFb.csv", row.names = TRUE) +``` + +### Mouse — T Cells (GSE246932) + +Mouse CD8+ T cells were treated with TGFβ for 2 hours. Raw count data +required DESeq2 for normalization and differential testing. + +``` r +library(DESeq2) +library(dplyr) + +# Load raw counts +counts_data <- read.csv( + "GSE246932_220809-P490-1_RawGeneCounts.csv.gz", + header = TRUE, check.names = FALSE +) + +# Remove SIINFEKL peptide-treated samples (not relevant to TGFb comparison) +counts_data <- counts_data[, !grepl("SIINFEKL", colnames(counts_data))] + +# Separate gene annotation from count columns +gene_anno <- counts_data[, 1:4] +counts_only <- counts_data[, -(1:4)] + +# Collapse duplicate gene IDs by summing +counts_collapsed <- counts_only %>% + mutate(geneId = gene_anno$geneId) %>% + group_by(geneId) %>% + summarise(across(where(is.numeric), sum), .groups = "drop") + +counts_mat <- as.matrix(counts_collapsed[, -1]) +rownames(counts_mat) <- counts_collapsed$geneId + +# Build DESeq2 object +sample_names <- colnames(counts_mat) +coldata <- data.frame( + treatment = factor( + ifelse(grepl("TGFb", sample_names), "TGFb", "none"), + levels = c("none", "TGFb") + ), + row.names = sample_names +) + +dds <- DESeqDataSetFromMatrix( + countData = counts_mat, + colData = coldata, + design = ~ treatment +) +dds <- dds[rowSums(counts(dds)) > 10, ] # low-count filter +dds <- DESeq(dds) + +res <- results(dds, contrast = c("treatment", "TGFb", "none")) +res_df <- as.data.frame(res) + +# Map gene names back from annotation +res_df$geneId <- rownames(res_df) +res_df$geneName <- gene_anno$geneName[match(res_df$geneId, gene_anno$geneId)] +res_df$description <- gene_anno$description[match(res_df$geneId, gene_anno$geneId)] + +library(openxlsx) +write.xlsx(res_df, file = "Mus_TGFb_vs_none.xlsx", rowNames = FALSE) +``` + +------------------------------------------------------------------------ + +## Step 3: Filter for TGF-β Pathway Genes + +DEG results are joined against the curated gene lists, retaining only +TGF-β pathway members that reach statistical significance (adjusted *p* +\< 0.05). + +``` r +library(readr) +library(readxl) +library(dplyr) + +human_d1 <- read_csv("DEG_D1_TGFb_vs_noTGFb.csv") +human_d20 <- read_csv("DEG_D20_TGFb_vs_noTGFb.csv") +mouse_df <- read_excel("Mus_TGFb_vs_none.xlsx") + +# Human Day 1 +human_d1_results <- human_d1 %>% + filter(ID %in% tgfb_genes_human_flat$gene) %>% + left_join(tgfb_genes_human_flat, by = c("ID" = "gene")) %>% + filter(!is.na(adj.P.Val) & adj.P.Val < 0.05) %>% + arrange(adj.P.Val) + +# Human Day 20 +human_d20_results <- human_d20 %>% + filter(ID %in% tgfb_genes_human_flat$gene) %>% + left_join(tgfb_genes_human_flat, by = c("ID" = "gene")) %>% + filter(!is.na(adj.P.Val) & adj.P.Val < 0.05) %>% + arrange(adj.P.Val) + +# Mouse +mouse_df_results <- mouse_df %>% + filter(geneName %in% tgfb_genes_mouse_flat$gene) %>% + left_join(tgfb_genes_mouse_flat, by = c("geneName" = "gene")) %>% + filter(!is.na(padj) & padj < 0.05) %>% + arrange(padj) + +cat("Human D1 pathway genes (padj<0.05):", nrow(human_d1_results), "\n") +cat("Human D20 pathway genes (padj<0.05):", nrow(human_d20_results), "\n") +cat("Mouse pathway genes (padj<0.05):", nrow(mouse_df_results), "\n") +``` + +------------------------------------------------------------------------ + +## Step 4: Assign Activity Coefficients + +### Rationale + +Each gene receives a **direction coefficient** reflecting its behavior +under TGFβ activation: + +| Coefficient | Meaning | +|:-----------:|--------------------------------------------------------------| +| **+1** | Upregulated with TGFβ — consistent with pathway activation | +| **−1** | Downregulated with TGFβ — consistent with pathway inhibition | + +These coefficients are used by `PathwayEmbed` to compute a **signed +pathway activity score**: the weighted sum of a sample’s expression +values multiplied by their coefficients, giving a single number that +reflects the net direction and magnitude of TGF-β activity. + +The function also supports inhibitor experiments via +`TGFB_activation = FALSE`, which flips the sign logic — a gene +downregulated by an inhibitor is inferred to be positively regulated +under activation. + +``` r +assign_coefficient_tgfb <- function(log2FoldChange, + fc_threshold = 0, + TGFB_activation = TRUE) { + if (is.na(log2FoldChange)) return(0) + + if (TGFB_activation) { + if (log2FoldChange > fc_threshold) return( 1) + else if (log2FoldChange < -fc_threshold) return(-1) + else return( 0) + } else { + # Inhibitor data: flip direction + if (log2FoldChange < -fc_threshold) return( 1) + else if (log2FoldChange > fc_threshold) return(-1) + else return( 0) + } +} +``` + +> **Threshold note:** `fc_threshold = 0` assigns a coefficient to any +> non-zero fold-change. For stricter databases, use `fc_threshold = 0.5` +> to restrict to genes with \|log₂FC\| ≥ 0.5, focusing on more robust +> responses. + +``` r +human_d1_results <- human_d1_results %>% + mutate(coef = sapply(logFC, assign_coefficient_tgfb, fc_threshold = 0)) + +human_d20_results <- human_d20_results %>% + mutate(coef = sapply(logFC, assign_coefficient_tgfb, fc_threshold = 0)) + +mouse_df_results <- mouse_df_results %>% + mutate(coef = sapply(log2FoldChange, assign_coefficient_tgfb, fc_threshold = 0)) +``` + +------------------------------------------------------------------------ + +## Step 5: Export to Excel + +The final database is exported as a formatted `.xlsx` workbook with a +styled header row, frozen pane, and auto-sized columns. + +``` r +library(openxlsx) + +# --- Helper: prepare one sheet's data frame --- +prepare_sheet <- function(results, gene_col, logfc_col) { + results %>% + dplyr::select( + Gene_Symbol = !!sym(gene_col), + Category = category, + Coefficient = coef, + log2FoldChange = !!sym(logfc_col) + ) %>% + as.data.frame() +} + +human_d1_sheet <- prepare_sheet(human_d1_results, "ID", "logFC") +human_d20_sheet <- prepare_sheet(human_d20_results, "ID", "logFC") +mouse_df_sheet <- prepare_sheet(mouse_df_results, "geneName", "log2FoldChange") + +# --- Helper: write one formatted sheet --- +add_pathway_sheet <- function(wb, sheet_name, df) { + + addWorksheet(wb, sheet_name) + + writeData(wb, sheet_name, df, + headerStyle = createStyle( + fontSize = 11, fontColour = "#FFFFFF", halign = "center", + fgFill = "#4472C4", border = "TopBottom", + fontName = "Arial", textDecoration = "bold" + ) + ) + + freezePane(wb, sheet_name, firstRow = TRUE) + tryCatch( + setColWidths(wb, sheet_name, cols = seq_len(ncol(df)), widths = "auto"), + error = function(e) + setColWidths(wb, sheet_name, cols = seq_len(ncol(df)), widths = 15) + ) +} + +# --- Build workbook --- +wb <- createWorkbook() +add_pathway_sheet(wb, "TGFB_Human_D1", human_d1_sheet) +add_pathway_sheet(wb, "TGFB_Human_D20", human_d20_sheet) +add_pathway_sheet(wb, "TGFB_Mouse", mouse_df_sheet) + +saveWorkbook(wb, "TGFB_Pathway_Database.xlsx", overwrite = TRUE) +cat("Saved: TGFB_Pathway_Database.xlsx\n") +``` + +------------------------------------------------------------------------ + +## Final Database Structure + +Each sheet in `TGFB_Pathway_Database.xlsx` contains: + +| Column | Description | +|----|----| +| `Gene_Symbol` | HGNC (human) or MGI (mouse) gene symbol | +| `Category` | Functional category from KEGG + curation | +| `Coefficient` | +1 (activated) or −1 (repressed) under TGFβ; filtered by padj \< 0.05 | +| `log2FoldChange` | Log₂ fold-change from the corresponding DEG analysis | + +Sheets produced: + +| Sheet | Species | Context | Method | +|------------------|---------|--------------------------|--------------| +| `TGFB_Human_D1` | Human | Lung fibroblasts, Day 1 | limma / voom | +| `TGFB_Human_D20` | Human | Lung fibroblasts, Day 20 | limma / voom | +| `TGFB_Mouse` | Mouse | CD8+ T cells, 2h | DESeq2 | + +------------------------------------------------------------------------ + +## Important Curation Notes + +The following caveats should be kept in mind when extending or modifying +the database: + +**Genes excluded from the mouse list due to no ortholog:** `INHBC`, +`INHBE` — these activin subunits are primate-specific and have no mouse +ortholog. + +**Gene name ambiguities resolved:** `SARA` is a protein alias for the +gene `ZFYVE9` and should not be used as a gene symbol. `ELF` is +ambiguous (could refer to `ELF1` through `ELF5`) and was removed from +the mouse list. + +**Genes with completely different human/mouse symbols:** + +| Human | Mouse | Category | +|--------------|-------|-------------------| +| RNF12 | Rlim | E3_Ligases | +| IMPORTIN7 | Ipo7 | Nuclear_Transport | +| IMPORTIN8 | Ipo8 | Nuclear_Transport | +| TAZ (WWTR1) | Wwtr1 | Other_Regulators | +| EVI1 (MECOM) | Mecom | Other_Regulators | + +Always verify mouse gene symbols against +[MGI](http://www.informatics.jax.org/) before adding new genes. + +------------------------------------------------------------------------ + +## Session Information + +``` r +sessionInfo() +#> R version 4.4.2 (2024-10-31) +#> Platform: aarch64-apple-darwin20 +#> Running under: macOS Sonoma 14.6 +#> +#> Matrix products: default +#> BLAS: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRblas.0.dylib +#> LAPACK: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.0 +#> +#> locale: +#> [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8 +#> +#> time zone: America/New_York +#> tzcode source: internal +#> +#> attached base packages: +#> [1] stats graphics grDevices utils datasets methods base +#> +#> loaded via a namespace (and not attached): +#> [1] digest_0.6.39 desc_1.4.3 R6_2.6.1 fastmap_1.2.0 +#> [5] xfun_0.57 cachem_1.1.0 knitr_1.51 htmltools_0.5.9 +#> [9] rmarkdown_2.30 lifecycle_1.0.5 cli_3.6.5 sass_0.4.10 +#> [13] pkgdown_2.2.0 textshaping_1.0.5 jquerylib_0.1.4 systemfonts_1.3.2 +#> [17] compiler_4.4.2 rstudioapi_0.18.0 tools_4.4.2 ragg_1.5.1 +#> [21] bslib_0.10.0 evaluate_1.0.5 yaml_2.3.12 otel_0.2.0 +#> [25] jsonlite_2.0.0 htmlwidgets_1.6.4 rlang_1.1.7 fs_1.6.7 +``` diff --git a/docs/articles/beta_catenin_ko.html b/docs/articles/beta_catenin_ko.html deleted file mode 100644 index 97fa9dd..0000000 --- a/docs/articles/beta_catenin_ko.html +++ /dev/null @@ -1,364 +0,0 @@ - - - - - - - -Beta-Catenin Knockout Analysis with PathwayEmbed • PathwayEmbed - - - - - - - - - - - -
-
- - - - -
-
- - - - -
-

Load Packages and Download Data from Online Source -

-
-library(PathwayEmbed)
-library(Seurat)
-#> Loading required package: SeuratObject
-#> Loading required package: sp
-#> 'SeuratObject' was built under R 4.4.1 but the current version is
-#> 4.4.2; it is recomended that you reinstall 'SeuratObject' as the ABI
-#> for R may have changed
-#> 
-#> Attaching package: 'SeuratObject'
-#> The following objects are masked from 'package:base':
-#> 
-#>     intersect, t
-
-url_ko <- "https://ftp.ncbi.nlm.nih.gov/geo/series/GSE233nnn/GSE233978/suppl/GSE233978_KO_filtered_feature_bc_matrix.h5"
-url_wt <- "https://ftp.ncbi.nlm.nih.gov/geo/series/GSE233nnn/GSE233978/suppl/GSE233978_WT_filtered_feature_bc_matrix.h5"
-
-
-download.file(url_ko, destfile = "GSE233978_KO_filtered_feature_bc_matrix.h5", mode = "wb")
-download.file(url_wt, destfile = "GSE233978_WT_filtered_feature_bc_matrix.h5", mode = "wb")
-
-
-

Data Preparation -

-
-# Load KO and WT expression matrices from local HDF5 files
-ko_data <- Read10X_h5("GSE233978_KO_filtered_feature_bc_matrix.h5")
-wt_data <- Read10X_h5("GSE233978_WT_filtered_feature_bc_matrix.h5")
-
-# Create Seurat objects
-# Apply during object creation
-ko <- CreateSeuratObject(counts = ko_data, project = "KO", min.cells = 3, min.features = 200)
-wt <- CreateSeuratObject(counts = wt_data, project = "WT", min.cells = 3, min.features = 200)
-
-
-# Add sample metadata
-ko$sample <- "KO"
-wt$sample <- "WT"
-
-# Merge and join layers
-merged <- merge(ko, wt)
-#> Warning: Some cell names are duplicated across objects provided. Renaming to
-#> enforce unique cell names.
-merged[["RNA"]] <- JoinLayers(merged[["RNA"]])
-
-
-

Preprocessing -

-

Get normalized and scaled data

-
-# Normalize and scale
-merged <- NormalizeData(
-  object = merged,
-  normalization.method = "LogNormalize",
-  scale.factor = 10000
-)
-#> Normalizing layer: counts
-
-merged <- FindVariableFeatures(
-  object = merged,
-  selection.method = "vst",
-  nfeatures = 2000
-)
-#> Finding variable features for layer counts
-
-merged <- ScaleData(
-  object = merged,
-  features = VariableFeatures(object = merged)
-)
-#> Centering and scaling data matrix
-
-
-

Wnt Pathway Scoring and Visualization Using Pathway Embed -

-
-# Compute Wnt pathway score
-wnt_scores <- ComputeCellData(merged, "Wnt", distance.method = "manhattan", batch.size = 1000)
-#> Centering and scaling data matrix
-#> Warning: Different features in new layer data than already exists for
-#> scale.data
-#> Warning: The `slot` argument of `GetAssayData()` is deprecated as of SeuratObject 5.0.0.
-#>  Please use the `layer` argument instead.
-#>  The deprecated feature was likely used in the PathwayEmbed package.
-#>   Please report the issue to the authors.
-#> This warning is displayed once every 8 hours.
-#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
-#> generated.
-#> Centering and scaling data matrix
-#> Processing batch 1
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 1 processed with 1000 cells
-#> Processing batch 2
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 2 processed with 1000 cells
-#> Processing batch 3
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 3 processed with 1000 cells
-#> Processing batch 4
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 4 processed with 1000 cells
-#> Processing batch 5
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 5 processed with 1000 cells
-#> Processing batch 6
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 6 processed with 1000 cells
-#> Processing batch 7
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 7 processed with 1000 cells
-#> Processing batch 8
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 8 processed with 1000 cells
-#> Processing batch 9
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 9 processed with 1000 cells
-#> Processing batch 10
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 10 processed with 1000 cells
-#> Processing batch 11
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 11 processed with 1000 cells
-#> Processing batch 12
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 12 processed with 1000 cells
-#> Processing batch 13
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 13 processed with 1000 cells
-#> Processing batch 14
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 14 processed with 1000 cells
-#> Processing batch 15
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 15 processed with 1000 cells
-#> Processing batch 16
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 16 processed with 1000 cells
-#> Processing batch 17
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 17 processed with 1000 cells
-#> Processing batch 18
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 18 processed with 1000 cells
-#> Processing batch 19
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 19 processed with 1000 cells
-#> Processing batch 20
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 20 processed with 1000 cells
-#> Processing batch 21
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 21 processed with 1000 cells
-#> Processing batch 22
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 22 processed with 1000 cells
-#> Processing batch 23
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 23 processed with 1000 cells
-#> Processing batch 24
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 24 processed with 1000 cells
-#> Processing batch 25
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 25 processed with 1000 cells
-#> Processing batch 26
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 26 processed with 1000 cells
-#> Processing batch 27
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 27 processed with 1000 cells
-#> Processing batch 28
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 28 processed with 735 cells
-
-# Prepare for plotting
-plot_data <- PreparePlotData(merged, wnt_scores, group = "sample")
-
-# Plot
-PlotPathway(plot_data, pathway = "Wnt", group = "sample", c("#f4a4a4", "#6baed6"))
-

-
-
-# Show percentage of high-scoring cells (optional)
-CalculatePercentage(plot_data, "sample")
-#> # A tibble: 2 × 4
-#>   group percentage_on percentage_off cohens_d
-#>   <chr>         <dbl>          <dbl>    <dbl>
-#> 1 KO             31.8           68.2   -0.447
-#> 2 WT             46.9           53.1   -0.447
-
-
- - - -
- - - -
- -
-

-

Site built with pkgdown 2.1.3.

-
- -
-
- - - - - - - - diff --git a/docs/articles/beta_catenin_ko_files/figure-html/unnamed-chunk-4-1.png b/docs/articles/beta_catenin_ko_files/figure-html/unnamed-chunk-4-1.png deleted file mode 100644 index c44c89e..0000000 Binary files a/docs/articles/beta_catenin_ko_files/figure-html/unnamed-chunk-4-1.png and /dev/null differ diff --git a/docs/articles/beta_catenin_ko_updated.html b/docs/articles/beta_catenin_ko_updated.html new file mode 100644 index 0000000..cbce986 --- /dev/null +++ b/docs/articles/beta_catenin_ko_updated.html @@ -0,0 +1,462 @@ + + + + + + + +Beta-Catenin Knockout Analysis with PathwayEmbed • PathwayEmbed + + + + + + + + Skip to contents + + +
+ + + + +
+
+ + + +
+

Overview +

+

This vignette demonstrates the application of PathwayEmbed in a +beta-catenin perturbed system where the Ctnnb1 upstream +enhancer is depleted in intestinal epithelia. Because the KO genotype is +known by design, this dataset provides a clean biological ground truth +for a direct AUROC benchmark against PROGENy and AddModuleScore.

+

Reference: Hua et al., eLife 13: RP98238 (2024). https://doi.org/10.7554/eLife.98238

+
+
+ +
+

Helper: Annotation Label Builder +

+
+make_label <- function(stats, group1, group2) {
+  d    <- round(stats$cohens_d[1], 3)
+  p    <- formatC(stats$p_value[1], format = "e", digits = 2)
+  on1  <- stats$percentage_on[stats$group  == group1]
+  off1 <- stats$percentage_off[stats$group == group1]
+  on2  <- stats$percentage_on[stats$group  == group2]
+  off2 <- stats$percentage_off[stats$group == group2]
+  paste0(
+    group1, ": ON=", on1,  "%, OFF=", off1, "%\n",
+    group2, ": ON=", on2,  "%, OFF=", off2, "%\n",
+    "Cohen's d = ", d, "\n",
+    "p = ", p
+  )
+}
+
+
+
+

Download Data +

+
+url_ko <- "https://ftp.ncbi.nlm.nih.gov/geo/series/GSE233nnn/GSE233978/suppl/GSE233978_KO_filtered_feature_bc_matrix.h5"
+url_wt <- "https://ftp.ncbi.nlm.nih.gov/geo/series/GSE233nnn/GSE233978/suppl/GSE233978_WT_filtered_feature_bc_matrix.h5"
+
+download.file(url_ko, destfile = "GSE233978_KO_filtered_feature_bc_matrix.h5", mode = "wb")
+download.file(url_wt, destfile = "GSE233978_WT_filtered_feature_bc_matrix.h5", mode = "wb")
+
+
+
+

Data Preparation and Preprocessing +

+
+ko_data <- Read10X_h5("GSE233978_KO_filtered_feature_bc_matrix.h5")
+wt_data <- Read10X_h5("GSE233978_WT_filtered_feature_bc_matrix.h5")
+
+ko <- CreateSeuratObject(counts = ko_data, project = "KO",
+                          min.cells = 3, min.features = 200)
+wt <- CreateSeuratObject(counts = wt_data, project = "WT",
+                          min.cells = 3, min.features = 200)
+ko$sample <- "KO"
+wt$sample <- "WT"
+
+merged          <- merge(ko, wt)
+merged[["RNA"]] <- JoinLayers(merged[["RNA"]])
+
+merged <- NormalizeData(merged, normalization.method = "LogNormalize",
+                         scale.factor = 10000)
+merged <- FindVariableFeatures(merged, selection.method = "vst",
+                                nfeatures = 2000)
+merged <- ScaleData(merged, features = VariableFeatures(merged))
+
+
+
+

Wnt Pathway Scoring +

+
+Wnt_12h   <- LoadPathway("WNT3A_12H_ACTIVATION",  "mouse")
+Wnt_24h   <- LoadPathway("WNT3A_24H_ACTIVATION",  "mouse")
+Wnt_48h   <- LoadPathway("WNT3A_48H_ACTIVATION",  "mouse")
+Wnt_slope <- LoadPathway("WNT3A_SLOPE_ACTIVATION", "mouse")
+
+matrix_12h   <- DataPreProcess(merged, Wnt_12h,   Seurat.object = TRUE)
+matrix_24h   <- DataPreProcess(merged, Wnt_24h,   Seurat.object = TRUE)
+matrix_48h   <- DataPreProcess(merged, Wnt_48h,   Seurat.object = TRUE)
+matrix_slope <- DataPreProcess(merged, Wnt_slope, Seurat.object = TRUE)
+
+pathwaystat_12h   <- PathwayMaxMin(matrix_12h,   Wnt_12h)
+pathwaystat_24h   <- PathwayMaxMin(matrix_24h,   Wnt_24h)
+pathwaystat_48h   <- PathwayMaxMin(matrix_48h,   Wnt_48h)
+pathwaystat_slope <- PathwayMaxMin(matrix_slope, Wnt_slope)
+
+score_12h   <- ComputeCellData(matrix_12h,   pathwaystat_12h)
+score_24h   <- ComputeCellData(matrix_24h,   pathwaystat_24h)
+score_48h   <- ComputeCellData(matrix_48h,   pathwaystat_48h)
+score_slope <- ComputeCellData(matrix_slope, pathwaystat_slope)
+
+
+
+

Visualization +

+
+plot_data_12h   <- PreparePlotData(merged, score_12h,   "sample", Seurat.object = TRUE)
+plot_data_24h   <- PreparePlotData(merged, score_24h,   "sample", Seurat.object = TRUE)
+plot_data_48h   <- PreparePlotData(merged, score_48h,   "sample", Seurat.object = TRUE)
+plot_data_slope <- PreparePlotData(merged, score_slope, "sample", Seurat.object = TRUE)
+
+pct_12h   <- CalculatePercentage(plot_data_12h,   "sample")
+pct_24h   <- CalculatePercentage(plot_data_24h,   "sample")
+pct_48h   <- CalculatePercentage(plot_data_48h,   "sample")
+pct_slope <- CalculatePercentage(plot_data_slope, "sample")
+
+pct_12h; pct_24h; pct_48h; pct_slope
+#> # A tibble: 2 × 5
+#>   group percentage_on percentage_off cohens_d  p_value
+#>   <chr>         <dbl>          <dbl>    <dbl>    <dbl>
+#> 1 KO             50.5           49.5  -0.0728 2.50e-12
+#> 2 WT             53.6           46.4  -0.0728 2.50e-12
+#> # A tibble: 2 × 5
+#>   group percentage_on percentage_off cohens_d  p_value
+#>   <chr>         <dbl>          <dbl>    <dbl>    <dbl>
+#> 1 KO             57.7           42.3   0.0748 5.27e-12
+#> 2 WT             51.4           48.6   0.0748 5.27e-12
+#> # A tibble: 2 × 5
+#>   group percentage_on percentage_off cohens_d  p_value
+#>   <chr>         <dbl>          <dbl>    <dbl>    <dbl>
+#> 1 KO             41.7           58.3   -0.136 3.52e-36
+#> 2 WT             50.8           49.2   -0.136 3.52e-36
+#> # A tibble: 2 × 5
+#>   group percentage_on percentage_off cohens_d   p_value
+#>   <chr>         <dbl>          <dbl>    <dbl>     <dbl>
+#> 1 KO             38.0           62.0   -0.301 6.49e-147
+#> 2 WT             52.0           48.0   -0.301 6.49e-147
+
+p_12h <- PlotPathway(plot_data_12h,   "Wnt 12h",    "sample", c("#ae282c", "#2066a8")) +
+  annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5,
+           label = make_label(pct_12h, "KO", "WT"), size = 3.5, color = "black")
+
+p_24h <- PlotPathway(plot_data_24h,   "Wnt 24h",    "sample", c("#ae282c", "#2066a8")) +
+  annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5,
+           label = make_label(pct_24h, "KO", "WT"), size = 3.5, color = "black")
+
+p_48h <- PlotPathway(plot_data_48h,   "Wnt 48h",    "sample", c("#ae282c", "#2066a8")) +
+  annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5,
+           label = make_label(pct_48h, "KO", "WT"), size = 3.5, color = "black")
+
+p_slope <- PlotPathway(plot_data_slope, "Wnt (slope)", "sample", c("#ae282c", "#2066a8")) +
+  annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5,
+           label = make_label(pct_slope, "KO", "WT"), size = 3.5, color = "black")
+
+p_12h; p_24h; p_48h; p_slope
+

+
+
+
+

Technical Confounders +

+
+merged[["percent.mt"]] <- PercentageFeatureSet(merged, pattern = "^mt-")
+seurat_meta <- merged@meta.data
+
+make_scatter <- function(df, x_col, x_label) {
+  r <- cor(df$embed_score, df[[x_col]], method = "spearman", use = "complete.obs")
+  ggplot(df, aes(x = .data[[x_col]], y = embed_score)) +
+    geom_point(alpha = 0.3, size = 0.8, color = "#534AB7") +
+    geom_smooth(method = "lm", color = "#E24B4A", linewidth = 0.8, se = TRUE) +
+    labs(title = sprintf("%s (rho = %.3f)", x_label, r),
+         x = x_label, y = "PathwayEmbed score") +
+    theme_minimal()
+}
+
+confounder_df <- data.frame(
+  cell         = names(score_slope),
+  embed_score  = as.numeric(score_slope),
+  nCount_RNA   = seurat_meta[names(score_slope), "nCount_RNA"],
+  nFeature_RNA = seurat_meta[names(score_slope), "nFeature_RNA"],
+  percent_mt   = seurat_meta[names(score_slope), "percent.mt"]
+)
+
+for (cov in c("nCount_RNA", "nFeature_RNA", "percent_mt")) {
+  r <- cor(confounder_df$embed_score, confounder_df[[cov]],
+           method = "spearman", use = "complete.obs")
+  cat(sprintf("Spearman vs %-15s : %.3f\n", cov, r))
+}
+#> Spearman vs nCount_RNA      : 0.188
+#> Spearman vs nFeature_RNA    : 0.262
+#> Spearman vs percent_mt      : -0.119
+
+(make_scatter(confounder_df, "nCount_RNA",   "nCount_RNA") +
+ make_scatter(confounder_df, "nFeature_RNA", "nFeature_RNA") +
+ make_scatter(confounder_df, "percent_mt",   "percent.mt"))
+

+
+
+
+

Benchmark Against PROGENy and AddModuleScore +

+
+normalized_mat       <- GetAssayData(merged, assay = "RNA", layer = "data")
+normalized_mat_dense <- as.matrix(normalized_mat)
+
+common_genes         <- intersect(rownames(normalized_mat_dense), Wnt_slope$Gene_Symbol)
+gene_matrix          <- normalized_mat_dense[common_genes, ]
+mean_expr            <- colMeans(gene_matrix, na.rm = TRUE)
+zscore_mean_per_cell <- colMeans(t(scale(t(gene_matrix))), na.rm = TRUE)
+
+progeny_scores <- progeny(
+  normalized_mat_dense,
+  scale    = TRUE,
+  organism = "Mouse",
+  top      = 100,
+  perm     = 1
+)
+progeny_wnt <- setNames(as.numeric(progeny_scores[, "WNT"]),
+                         rownames(progeny_scores))
+
+wnt_features <- rownames(matrix_slope)
+merged <- AddModuleScore(
+  object   = merged,
+  features = list(wnt_features),
+  name     = "WNT_ModuleScore",
+  ctrl     = 5,
+  nbin     = 10
+)
+module_score <- setNames(
+  merged@meta.data$WNT_ModuleScore1,
+  rownames(merged@meta.data)
+)
+
+cells <- names(score_slope)
+benchmark_df <- data.frame(
+  PathwayEmbed   = as.numeric(score_slope),
+  PROGENy        = as.numeric(progeny_wnt[cells]),
+  AddModuleScore = as.numeric(module_score[cells]),
+  mean_expr      = as.numeric(mean_expr[cells]),
+  zscore_expr    = as.numeric(zscore_mean_per_cell[cells]),
+  row.names      = cells
+)
+
+benchmark_cor <- cor(benchmark_df, method = "spearman",
+                     use = "pairwise.complete.obs")
+print(round(benchmark_cor, 3))
+#>                PathwayEmbed PROGENy AddModuleScore mean_expr zscore_expr
+#> PathwayEmbed          1.000   0.095          0.106     0.359       0.356
+#> PROGENy               0.095   1.000         -0.180     0.367       0.362
+#> AddModuleScore        0.106  -0.180          1.000     0.146       0.139
+#> mean_expr             0.359   0.367          0.146     1.000       0.972
+#> zscore_expr           0.356   0.362          0.139     0.972       1.000
+
+p_cor <- pheatmap(
+  benchmark_cor,
+  color           = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100),
+  breaks          = seq(-1, 1, length.out = 101),
+  display_numbers = TRUE, number_format = "%.2f",
+  fontsize_number = 9,
+  main            = "Method Benchmark — Spearman Correlation (Ctnnb1 KO dataset)"
+)
+p_cor
+

+
+
+ko_label <- ifelse(merged@meta.data[cells, "sample"] == "KO", 1L, 0L)
+
+compute_auroc <- function(scores, labels) {
+  r       <- roc(labels, scores, quiet = TRUE)
+  auc_val <- as.numeric(auc(r))
+  if (auc_val < 0.5) auc_val <- 1 - auc_val
+  auc_val
+}
+
+auroc_results <- data.frame(
+  Method = colnames(benchmark_df),
+  AUROC  = sapply(benchmark_df, compute_auroc, labels = ko_label)
+)
+auroc_results <- auroc_results[order(-auroc_results$AUROC), ]
+print(auroc_results)
+#>                        Method     AUROC
+#> AddModuleScore AddModuleScore 0.6827026
+#> mean_expr           mean_expr 0.6482098
+#> zscore_expr       zscore_expr 0.6425566
+#> PathwayEmbed     PathwayEmbed 0.5897700
+#> PROGENy               PROGENy 0.5106677
+
+compute_cohens_d_method <- function(scores_vec, seurat_obj, group_col) {
+  pd  <- PreparePlotData(seurat_obj, scores_vec, group_col, Seurat.object = TRUE)
+  pct <- CalculatePercentage(pd, group_var = group_col)
+  abs(pct$cohens_d[1])
+}
+
+cohens_d_results <- data.frame(
+  Method   = colnames(benchmark_df),
+  Cohens_d = sapply(
+    colnames(benchmark_df),
+    function(m) {
+      sv <- setNames(benchmark_df[[m]], rownames(benchmark_df))
+      compute_cohens_d_method(sv, merged, "sample")
+    }
+  )
+)
+cohens_d_results <- cohens_d_results[order(-cohens_d_results$Cohens_d), ]
+print(cohens_d_results)
+#>                        Method   Cohens_d
+#> AddModuleScore AddModuleScore 0.64575350
+#> mean_expr           mean_expr 0.54020251
+#> zscore_expr       zscore_expr 0.51565732
+#> PathwayEmbed     PathwayEmbed 0.30056596
+#> PROGENy               PROGENy 0.03129493
+
+method_colors <- c(
+  "PathwayEmbed"   = "#534AB7",
+  "PROGENy"        = "#E24B4A",
+  "AddModuleScore" = "#EF9F27",
+  "mean_expr"      = "#888780",
+  "zscore_expr"    = "#B4B2A9"
+)
+
+p_cd <- ggplot(cohens_d_results,
+       aes(x = reorder(Method, Cohens_d), y = Cohens_d, fill = Method)) +
+  geom_bar(stat = "identity", width = 0.6) +
+  coord_flip() +
+  scale_fill_manual(values = method_colors) +
+  labs(title = "Effect size (Cohen's d): KO vs. WT",
+       x = NULL, y = "Cohen's d (absolute)") +
+  theme_classic() +
+  theme(legend.position = "none")
+p_cd
+

+
+
+p_auroc <- ggplot(auroc_results,
+       aes(x = reorder(Method, AUROC), y = AUROC, fill = Method)) +
+  geom_bar(stat = "identity", width = 0.6) +
+  geom_hline(yintercept = 0.5, linetype = "dashed", color = "black") +
+  coord_flip() +
+  scale_fill_manual(values = method_colors) +
+  labs(title = "AUROC: KO vs. WT separation (Ctnnb1 KO dataset)",
+       x = NULL, y = "AUROC") +
+  ylim(0, 1) +
+  theme_classic() +
+  theme(legend.position = "none")
+p_auroc
+

+
+
+roc_list <- lapply(colnames(benchmark_df), function(m) {
+  roc(ko_label, benchmark_df[[m]], quiet = TRUE)
+})
+names(roc_list) <- colnames(benchmark_df)
+
+roc_df <- do.call(rbind, lapply(names(roc_list), function(m) {
+  r <- roc_list[[m]]
+  data.frame(Method = m, FPR = 1 - r$specificities, TPR = r$sensitivities)
+}))
+
+p_roc <- ggplot(roc_df, aes(x = FPR, y = TPR, color = Method)) +
+  geom_line(linewidth = 0.9) +
+  geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "grey60") +
+  scale_color_manual(values = method_colors) +
+  labs(title = "ROC curves: KO vs. WT (Ctnnb1 KO dataset)",
+       x = "False positive rate", y = "True positive rate") +
+  theme_classic()
+p_roc
+

+
+
+
+ + + +
+ + + +
+
+ + + + + + + diff --git a/docs/articles/beta_catenin_ko_updated.md b/docs/articles/beta_catenin_ko_updated.md new file mode 100644 index 0000000..cc5398d --- /dev/null +++ b/docs/articles/beta_catenin_ko_updated.md @@ -0,0 +1,392 @@ +# Beta-Catenin Knockout Analysis with PathwayEmbed + +## Overview + +This vignette demonstrates the application of PathwayEmbed in a +beta-catenin perturbed system where the *Ctnnb1* upstream enhancer is +depleted in intestinal epithelia. Because the KO genotype is known by +design, this dataset provides a clean biological ground truth for a +direct AUROC benchmark against PROGENy and AddModuleScore. + +Reference: Hua et al., *eLife* 13: RP98238 (2024). + + +------------------------------------------------------------------------ + +## Load Packages + +``` r +library(PathwayEmbed) +library(Seurat) +library(ggplot2) +library(patchwork) +library(pheatmap) +library(progeny) +library(pROC) +``` + +------------------------------------------------------------------------ + +## Helper: Annotation Label Builder + +``` r +make_label <- function(stats, group1, group2) { + d <- round(stats$cohens_d[1], 3) + p <- formatC(stats$p_value[1], format = "e", digits = 2) + on1 <- stats$percentage_on[stats$group == group1] + off1 <- stats$percentage_off[stats$group == group1] + on2 <- stats$percentage_on[stats$group == group2] + off2 <- stats$percentage_off[stats$group == group2] + paste0( + group1, ": ON=", on1, "%, OFF=", off1, "%\n", + group2, ": ON=", on2, "%, OFF=", off2, "%\n", + "Cohen's d = ", d, "\n", + "p = ", p + ) +} +``` + +------------------------------------------------------------------------ + +## Download Data + +``` r +url_ko <- "https://ftp.ncbi.nlm.nih.gov/geo/series/GSE233nnn/GSE233978/suppl/GSE233978_KO_filtered_feature_bc_matrix.h5" +url_wt <- "https://ftp.ncbi.nlm.nih.gov/geo/series/GSE233nnn/GSE233978/suppl/GSE233978_WT_filtered_feature_bc_matrix.h5" + +download.file(url_ko, destfile = "GSE233978_KO_filtered_feature_bc_matrix.h5", mode = "wb") +download.file(url_wt, destfile = "GSE233978_WT_filtered_feature_bc_matrix.h5", mode = "wb") +``` + +------------------------------------------------------------------------ + +## Data Preparation and Preprocessing + +``` r +ko_data <- Read10X_h5("GSE233978_KO_filtered_feature_bc_matrix.h5") +wt_data <- Read10X_h5("GSE233978_WT_filtered_feature_bc_matrix.h5") + +ko <- CreateSeuratObject(counts = ko_data, project = "KO", + min.cells = 3, min.features = 200) +wt <- CreateSeuratObject(counts = wt_data, project = "WT", + min.cells = 3, min.features = 200) +ko$sample <- "KO" +wt$sample <- "WT" + +merged <- merge(ko, wt) +merged[["RNA"]] <- JoinLayers(merged[["RNA"]]) + +merged <- NormalizeData(merged, normalization.method = "LogNormalize", + scale.factor = 10000) +merged <- FindVariableFeatures(merged, selection.method = "vst", + nfeatures = 2000) +merged <- ScaleData(merged, features = VariableFeatures(merged)) +``` + +------------------------------------------------------------------------ + +## Wnt Pathway Scoring + +``` r +Wnt_12h <- LoadPathway("WNT3A_12H_ACTIVATION", "mouse") +Wnt_24h <- LoadPathway("WNT3A_24H_ACTIVATION", "mouse") +Wnt_48h <- LoadPathway("WNT3A_48H_ACTIVATION", "mouse") +Wnt_slope <- LoadPathway("WNT3A_SLOPE_ACTIVATION", "mouse") + +matrix_12h <- DataPreProcess(merged, Wnt_12h, Seurat.object = TRUE) +matrix_24h <- DataPreProcess(merged, Wnt_24h, Seurat.object = TRUE) +matrix_48h <- DataPreProcess(merged, Wnt_48h, Seurat.object = TRUE) +matrix_slope <- DataPreProcess(merged, Wnt_slope, Seurat.object = TRUE) + +pathwaystat_12h <- PathwayMaxMin(matrix_12h, Wnt_12h) +pathwaystat_24h <- PathwayMaxMin(matrix_24h, Wnt_24h) +pathwaystat_48h <- PathwayMaxMin(matrix_48h, Wnt_48h) +pathwaystat_slope <- PathwayMaxMin(matrix_slope, Wnt_slope) + +score_12h <- ComputeCellData(matrix_12h, pathwaystat_12h) +score_24h <- ComputeCellData(matrix_24h, pathwaystat_24h) +score_48h <- ComputeCellData(matrix_48h, pathwaystat_48h) +score_slope <- ComputeCellData(matrix_slope, pathwaystat_slope) +``` + +------------------------------------------------------------------------ + +## Visualization + +``` r +plot_data_12h <- PreparePlotData(merged, score_12h, "sample", Seurat.object = TRUE) +plot_data_24h <- PreparePlotData(merged, score_24h, "sample", Seurat.object = TRUE) +plot_data_48h <- PreparePlotData(merged, score_48h, "sample", Seurat.object = TRUE) +plot_data_slope <- PreparePlotData(merged, score_slope, "sample", Seurat.object = TRUE) + +pct_12h <- CalculatePercentage(plot_data_12h, "sample") +pct_24h <- CalculatePercentage(plot_data_24h, "sample") +pct_48h <- CalculatePercentage(plot_data_48h, "sample") +pct_slope <- CalculatePercentage(plot_data_slope, "sample") + +pct_12h; pct_24h; pct_48h; pct_slope +#> # A tibble: 2 × 5 +#> group percentage_on percentage_off cohens_d p_value +#> +#> 1 KO 50.5 49.5 -0.0728 2.50e-12 +#> 2 WT 53.6 46.4 -0.0728 2.50e-12 +#> # A tibble: 2 × 5 +#> group percentage_on percentage_off cohens_d p_value +#> +#> 1 KO 57.7 42.3 0.0748 5.27e-12 +#> 2 WT 51.4 48.6 0.0748 5.27e-12 +#> # A tibble: 2 × 5 +#> group percentage_on percentage_off cohens_d p_value +#> +#> 1 KO 41.7 58.3 -0.136 3.52e-36 +#> 2 WT 50.8 49.2 -0.136 3.52e-36 +#> # A tibble: 2 × 5 +#> group percentage_on percentage_off cohens_d p_value +#> +#> 1 KO 38.0 62.0 -0.301 6.49e-147 +#> 2 WT 52.0 48.0 -0.301 6.49e-147 + +p_12h <- PlotPathway(plot_data_12h, "Wnt 12h", "sample", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_12h, "KO", "WT"), size = 3.5, color = "black") + +p_24h <- PlotPathway(plot_data_24h, "Wnt 24h", "sample", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_24h, "KO", "WT"), size = 3.5, color = "black") + +p_48h <- PlotPathway(plot_data_48h, "Wnt 48h", "sample", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_48h, "KO", "WT"), size = 3.5, color = "black") + +p_slope <- PlotPathway(plot_data_slope, "Wnt (slope)", "sample", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_slope, "KO", "WT"), size = 3.5, color = "black") + +p_12h; p_24h; p_48h; p_slope +``` + +![](beta_catenin_ko_updated_files/figure-html/visualization-1.png)![](beta_catenin_ko_updated_files/figure-html/visualization-2.png)![](beta_catenin_ko_updated_files/figure-html/visualization-3.png)![](beta_catenin_ko_updated_files/figure-html/visualization-4.png) + +------------------------------------------------------------------------ + +## Technical Confounders + +``` r +merged[["percent.mt"]] <- PercentageFeatureSet(merged, pattern = "^mt-") +seurat_meta <- merged@meta.data + +make_scatter <- function(df, x_col, x_label) { + r <- cor(df$embed_score, df[[x_col]], method = "spearman", use = "complete.obs") + ggplot(df, aes(x = .data[[x_col]], y = embed_score)) + + geom_point(alpha = 0.3, size = 0.8, color = "#534AB7") + + geom_smooth(method = "lm", color = "#E24B4A", linewidth = 0.8, se = TRUE) + + labs(title = sprintf("%s (rho = %.3f)", x_label, r), + x = x_label, y = "PathwayEmbed score") + + theme_minimal() +} + +confounder_df <- data.frame( + cell = names(score_slope), + embed_score = as.numeric(score_slope), + nCount_RNA = seurat_meta[names(score_slope), "nCount_RNA"], + nFeature_RNA = seurat_meta[names(score_slope), "nFeature_RNA"], + percent_mt = seurat_meta[names(score_slope), "percent.mt"] +) + +for (cov in c("nCount_RNA", "nFeature_RNA", "percent_mt")) { + r <- cor(confounder_df$embed_score, confounder_df[[cov]], + method = "spearman", use = "complete.obs") + cat(sprintf("Spearman vs %-15s : %.3f\n", cov, r)) +} +#> Spearman vs nCount_RNA : 0.188 +#> Spearman vs nFeature_RNA : 0.262 +#> Spearman vs percent_mt : -0.119 + +(make_scatter(confounder_df, "nCount_RNA", "nCount_RNA") + + make_scatter(confounder_df, "nFeature_RNA", "nFeature_RNA") + + make_scatter(confounder_df, "percent_mt", "percent.mt")) +``` + +![](beta_catenin_ko_updated_files/figure-html/confounders-1.png) + +------------------------------------------------------------------------ + +## Benchmark Against PROGENy and AddModuleScore + +``` r +normalized_mat <- GetAssayData(merged, assay = "RNA", layer = "data") +normalized_mat_dense <- as.matrix(normalized_mat) + +common_genes <- intersect(rownames(normalized_mat_dense), Wnt_slope$Gene_Symbol) +gene_matrix <- normalized_mat_dense[common_genes, ] +mean_expr <- colMeans(gene_matrix, na.rm = TRUE) +zscore_mean_per_cell <- colMeans(t(scale(t(gene_matrix))), na.rm = TRUE) + +progeny_scores <- progeny( + normalized_mat_dense, + scale = TRUE, + organism = "Mouse", + top = 100, + perm = 1 +) +progeny_wnt <- setNames(as.numeric(progeny_scores[, "WNT"]), + rownames(progeny_scores)) + +wnt_features <- rownames(matrix_slope) +merged <- AddModuleScore( + object = merged, + features = list(wnt_features), + name = "WNT_ModuleScore", + ctrl = 5, + nbin = 10 +) +module_score <- setNames( + merged@meta.data$WNT_ModuleScore1, + rownames(merged@meta.data) +) + +cells <- names(score_slope) +benchmark_df <- data.frame( + PathwayEmbed = as.numeric(score_slope), + PROGENy = as.numeric(progeny_wnt[cells]), + AddModuleScore = as.numeric(module_score[cells]), + mean_expr = as.numeric(mean_expr[cells]), + zscore_expr = as.numeric(zscore_mean_per_cell[cells]), + row.names = cells +) + +benchmark_cor <- cor(benchmark_df, method = "spearman", + use = "pairwise.complete.obs") +print(round(benchmark_cor, 3)) +#> PathwayEmbed PROGENy AddModuleScore mean_expr zscore_expr +#> PathwayEmbed 1.000 0.095 0.106 0.359 0.356 +#> PROGENy 0.095 1.000 -0.180 0.367 0.362 +#> AddModuleScore 0.106 -0.180 1.000 0.146 0.139 +#> mean_expr 0.359 0.367 0.146 1.000 0.972 +#> zscore_expr 0.356 0.362 0.139 0.972 1.000 + +p_cor <- pheatmap( + benchmark_cor, + color = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100), + breaks = seq(-1, 1, length.out = 101), + display_numbers = TRUE, number_format = "%.2f", + fontsize_number = 9, + main = "Method Benchmark — Spearman Correlation (Ctnnb1 KO dataset)" +) +p_cor +``` + +![](beta_catenin_ko_updated_files/figure-html/benchmark-1.png) + +``` r + +ko_label <- ifelse(merged@meta.data[cells, "sample"] == "KO", 1L, 0L) + +compute_auroc <- function(scores, labels) { + r <- roc(labels, scores, quiet = TRUE) + auc_val <- as.numeric(auc(r)) + if (auc_val < 0.5) auc_val <- 1 - auc_val + auc_val +} + +auroc_results <- data.frame( + Method = colnames(benchmark_df), + AUROC = sapply(benchmark_df, compute_auroc, labels = ko_label) +) +auroc_results <- auroc_results[order(-auroc_results$AUROC), ] +print(auroc_results) +#> Method AUROC +#> AddModuleScore AddModuleScore 0.6827026 +#> mean_expr mean_expr 0.6482098 +#> zscore_expr zscore_expr 0.6425566 +#> PathwayEmbed PathwayEmbed 0.5897700 +#> PROGENy PROGENy 0.5106677 + +compute_cohens_d_method <- function(scores_vec, seurat_obj, group_col) { + pd <- PreparePlotData(seurat_obj, scores_vec, group_col, Seurat.object = TRUE) + pct <- CalculatePercentage(pd, group_var = group_col) + abs(pct$cohens_d[1]) +} + +cohens_d_results <- data.frame( + Method = colnames(benchmark_df), + Cohens_d = sapply( + colnames(benchmark_df), + function(m) { + sv <- setNames(benchmark_df[[m]], rownames(benchmark_df)) + compute_cohens_d_method(sv, merged, "sample") + } + ) +) +cohens_d_results <- cohens_d_results[order(-cohens_d_results$Cohens_d), ] +print(cohens_d_results) +#> Method Cohens_d +#> AddModuleScore AddModuleScore 0.64575350 +#> mean_expr mean_expr 0.54020251 +#> zscore_expr zscore_expr 0.51565732 +#> PathwayEmbed PathwayEmbed 0.30056596 +#> PROGENy PROGENy 0.03129493 + +method_colors <- c( + "PathwayEmbed" = "#534AB7", + "PROGENy" = "#E24B4A", + "AddModuleScore" = "#EF9F27", + "mean_expr" = "#888780", + "zscore_expr" = "#B4B2A9" +) + +p_cd <- ggplot(cohens_d_results, + aes(x = reorder(Method, Cohens_d), y = Cohens_d, fill = Method)) + + geom_bar(stat = "identity", width = 0.6) + + coord_flip() + + scale_fill_manual(values = method_colors) + + labs(title = "Effect size (Cohen's d): KO vs. WT", + x = NULL, y = "Cohen's d (absolute)") + + theme_classic() + + theme(legend.position = "none") +p_cd +``` + +![](beta_catenin_ko_updated_files/figure-html/benchmark-2.png) + +``` r + +p_auroc <- ggplot(auroc_results, + aes(x = reorder(Method, AUROC), y = AUROC, fill = Method)) + + geom_bar(stat = "identity", width = 0.6) + + geom_hline(yintercept = 0.5, linetype = "dashed", color = "black") + + coord_flip() + + scale_fill_manual(values = method_colors) + + labs(title = "AUROC: KO vs. WT separation (Ctnnb1 KO dataset)", + x = NULL, y = "AUROC") + + ylim(0, 1) + + theme_classic() + + theme(legend.position = "none") +p_auroc +``` + +![](beta_catenin_ko_updated_files/figure-html/benchmark-3.png) + +``` r + +roc_list <- lapply(colnames(benchmark_df), function(m) { + roc(ko_label, benchmark_df[[m]], quiet = TRUE) +}) +names(roc_list) <- colnames(benchmark_df) + +roc_df <- do.call(rbind, lapply(names(roc_list), function(m) { + r <- roc_list[[m]] + data.frame(Method = m, FPR = 1 - r$specificities, TPR = r$sensitivities) +})) + +p_roc <- ggplot(roc_df, aes(x = FPR, y = TPR, color = Method)) + + geom_line(linewidth = 0.9) + + geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "grey60") + + scale_color_manual(values = method_colors) + + labs(title = "ROC curves: KO vs. WT (Ctnnb1 KO dataset)", + x = "False positive rate", y = "True positive rate") + + theme_classic() +p_roc +``` + +![](beta_catenin_ko_updated_files/figure-html/benchmark-4.png) diff --git a/docs/articles/beta_catenin_ko_updated_files/figure-html/benchmark-1.png b/docs/articles/beta_catenin_ko_updated_files/figure-html/benchmark-1.png new file mode 100644 index 0000000..891c0fe Binary files /dev/null and b/docs/articles/beta_catenin_ko_updated_files/figure-html/benchmark-1.png differ diff --git a/docs/articles/beta_catenin_ko_updated_files/figure-html/benchmark-2.png b/docs/articles/beta_catenin_ko_updated_files/figure-html/benchmark-2.png new file mode 100644 index 0000000..d52e4b9 Binary files /dev/null and b/docs/articles/beta_catenin_ko_updated_files/figure-html/benchmark-2.png differ diff --git a/docs/articles/beta_catenin_ko_updated_files/figure-html/benchmark-3.png b/docs/articles/beta_catenin_ko_updated_files/figure-html/benchmark-3.png new file mode 100644 index 0000000..f42357d Binary files /dev/null and b/docs/articles/beta_catenin_ko_updated_files/figure-html/benchmark-3.png differ diff --git a/docs/articles/beta_catenin_ko_updated_files/figure-html/benchmark-4.png b/docs/articles/beta_catenin_ko_updated_files/figure-html/benchmark-4.png new file mode 100644 index 0000000..c22817e Binary files /dev/null and b/docs/articles/beta_catenin_ko_updated_files/figure-html/benchmark-4.png differ diff --git a/docs/articles/beta_catenin_ko_updated_files/figure-html/confounders-1.png b/docs/articles/beta_catenin_ko_updated_files/figure-html/confounders-1.png new file mode 100644 index 0000000..80ea645 Binary files /dev/null and b/docs/articles/beta_catenin_ko_updated_files/figure-html/confounders-1.png differ diff --git a/docs/articles/beta_catenin_ko_updated_files/figure-html/visualization-1.png b/docs/articles/beta_catenin_ko_updated_files/figure-html/visualization-1.png new file mode 100644 index 0000000..cc89710 Binary files /dev/null and b/docs/articles/beta_catenin_ko_updated_files/figure-html/visualization-1.png differ diff --git a/docs/articles/beta_catenin_ko_updated_files/figure-html/visualization-2.png b/docs/articles/beta_catenin_ko_updated_files/figure-html/visualization-2.png new file mode 100644 index 0000000..553e32c Binary files /dev/null and b/docs/articles/beta_catenin_ko_updated_files/figure-html/visualization-2.png differ diff --git a/docs/articles/beta_catenin_ko_updated_files/figure-html/visualization-3.png b/docs/articles/beta_catenin_ko_updated_files/figure-html/visualization-3.png new file mode 100644 index 0000000..781e1f9 Binary files /dev/null and b/docs/articles/beta_catenin_ko_updated_files/figure-html/visualization-3.png differ diff --git a/docs/articles/beta_catenin_ko_updated_files/figure-html/visualization-4.png b/docs/articles/beta_catenin_ko_updated_files/figure-html/visualization-4.png new file mode 100644 index 0000000..3570491 Binary files /dev/null and b/docs/articles/beta_catenin_ko_updated_files/figure-html/visualization-4.png differ diff --git a/docs/articles/examples.html b/docs/articles/examples.html deleted file mode 100644 index a5ed469..0000000 --- a/docs/articles/examples.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - -Toy Set • PathwayEmbed - - - - - - - - - - - -
-
- - - - -
-
- - - - -
-

Overview -

-

This vignette demonstrates how to use the PathwayEmbed package to -compute and visualize pathway activation using single-cell -transcriptomic data. We use the example dataset fake_test_object -included with the package.

-
-
-

Load Package and Example Data -

-
-library(PathwayEmbed)
-# Load the example Seurat object included in the package
-data(fake_test_object)
-
-
-

Compute Pathway Activation -

-
-# Calculate pathway activation using MDS
-# Default batch.size is set to 1000
-mds_results <- ComputeCellData(
-  fake_test_object,
-  pathway = "Wnt",
-  distance.method = "manhattan"
-)
-#> Centering and scaling data matrix
-#> Warning: The `slot` argument of `GetAssayData()` is deprecated as of SeuratObject 5.0.0.
-#>  Please use the `layer` argument instead.
-#>  The deprecated feature was likely used in the PathwayEmbed package.
-#>   Please report the issue to the authors.
-#> This warning is displayed once every 8 hours.
-#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
-#> generated.
-#> Centering and scaling data matrix
-#> Parameter 'batch.size' is missing or NULL. Setting default batch size to 1000.
-#> Processing batch 1
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 1 processed with 1000 cells
-#> Processing batch 2
-#> Computing distance...
-#> Running MDS ...
-#> MDS finished
-#> Batch 2 processed with 1000 cells
-
-
-

Prepare Data for Plotting -

-
-# Format MDS results and metadata for plotting
-plot_data <- PreparePlotData(
-  fake_test_object,
-  mds_results,
-  group = "genotype"
-)
-
-
-

Visualize Pathway Activation -

-
-# Visualize 2D MDS embedding colored by genotype
-PlotPathway(
-  to.plot = plot_data,
-  pathway = "Wnt",
-  group = "genotype",
-  color = c("#ae282c", "#2066a8")
-)
-

-
-
-

Calculate Group-wise Activation Percentage (Optional) -

-
-# Calculate % of cells per group with high pathway activation
-CalculatePercentage(
-  to.plot = plot_data,
-  group_var = "genotype"
-)
-#> # A tibble: 2 × 4
-#>   group  percentage_on percentage_off cohens_d
-#>   <chr>          <dbl>          <dbl>    <dbl>
-#> 1 Mutant          94.9            5.1     1.97
-#> 2 WT              17.7           82.3     1.97
-
-
-
- - - -
- - - -
- -
-

-

Site built with pkgdown 2.1.3.

-
- -
-
- - - - - - - - diff --git a/docs/articles/examples_files/figure-html/unnamed-chunk-4-1.png b/docs/articles/examples_files/figure-html/unnamed-chunk-4-1.png deleted file mode 100644 index e967bfa..0000000 Binary files a/docs/articles/examples_files/figure-html/unnamed-chunk-4-1.png and /dev/null differ diff --git a/docs/articles/examples_updated.html b/docs/articles/examples_updated.html new file mode 100644 index 0000000..9177762 --- /dev/null +++ b/docs/articles/examples_updated.html @@ -0,0 +1,939 @@ + + + + + + + +Toy Set • PathwayEmbed + + + + + + + + Skip to contents + + +
+ + + + +
+
+ + + +
+

Overview +

+

This vignette demonstrates how to use the PathwayEmbed package to +compute and visualize pathway activation using single-cell +transcriptomic data. We use the example dataset +synthetic_test_object_100 included with the package.

+
+
+
+

Load Packages and Data +

+
+library(PathwayEmbed)
+library(Seurat)
+library(dplyr)
+library(tidyr)
+library(ggplot2)
+library(ggridges)
+library(patchwork)
+library(pheatmap)
+library(progeny)
+library(pROC)
+
+data("synthetic_test_object_100")
+data("synthetic_test_metadata")
+
+
+
+

Helper: Annotation Label Builder +

+
+make_label <- function(stats, group1, group2) {
+  d    <- round(stats$cohens_d[1], 3)
+  p    <- formatC(stats$p_value[1], format = "e", digits = 2)
+  on1  <- stats$percentage_on[stats$group  == group1]
+  off1 <- stats$percentage_off[stats$group == group1]
+  on2  <- stats$percentage_on[stats$group  == group2]
+  off2 <- stats$percentage_off[stats$group == group2]
+  paste0(
+    group1, ": ON=", on1,  "%, OFF=", off1, "%\n",
+    group2, ": ON=", on2,  "%, OFF=", off2, "%\n",
+    "Cohen's d = ", d, "\n",
+    "p = ", p
+  )
+}
+
+
+
+

Load Pathway Databases +

+
+ListPathway()
+#> # A tibble: 17 × 8
+#>    Pathway Sheet.Name      GEO.Accession Condition Cell.Source Species No..Genes
+#>    <chr>   <chr>           <chr>         <chr>     <chr>       <chr>       <dbl>
+#>  1 HIF1A   Hypoxia_6hr     GSE227502     Hypoxia … Primary hu… Human          21
+#>  2 HIF1A   Hypoxia_24hr    GSE227502     Hypoxia … Primary hu… Human          18
+#>  3 HIF1A   Hypoxia_5Day    GSE227502     Hypoxia … Primary hu… Human          10
+#>  4 HIPPO   HIPPO_heat      GSE133251     Heat str… B16-OVA me… Mouse          40
+#>  5 NOTCH   NOTCH_JAG1      GSE223734     rJAG1 li… Mouse embr… Mouse           5
+#>  6 NOTCH   NOTCH_CB103_IN… GSE221577     CB-103 N… RPMI-8402 … Human          46
+#>  7 NOTCH   NOTCH_LY_INHIB… GSE221577     LY411575… RPMI-8402 … Human          46
+#>  8 NOTCH   NOTCH_JAG1_2H   GSE235637     JAG1 sti… SVG-A cells Human          11
+#>  9 NOTCH   NOTCH_JAG1_4H   GSE235637     JAG1 sti… SVG-A cells Human          11
+#> 10 NOTCH   NOTCH_JAG1_24H  GSE235637     JAG1 sti… SVG-A cells Human          11
+#> 11 TGFB    TGFB_Human_D1   GSE110021     TGF-β1 t… WI-38 fibr… Human          35
+#> 12 TGFB    TGFB_Human_D20  GSE110021     TGF-β1 t… WI-38 fibr… Human          39
+#> 13 TGFB    TGFB_Mouse      GSE246932     TGF-β1 t… T Cells     Mouse           9
+#> 14 WNT     WNT3A_12H_ACTI… GSE103175     WNT3A tr… Human Embr… Human          90
+#> 15 WNT     WNT3A_24H_ACTI… GSE103175     WNT3A tr… Human Embr… Human          88
+#> 16 WNT     WNT3A_48H_ACTI… GSE103175     WNT3A tr… Human Embr… Human          90
+#> 17 WNT     WNT3A_SLOPE_AC… GSE103175     WNT3A tr… Human Embr… Human          90
+#> # ℹ 1 more variable: Notes <chr>
+ListPathway("Pathway")
+#> [1] "HIF1A" "HIPPO" "NOTCH" "TGFB"  "WNT"
+ListPathway("WNT")
+#> # A tibble: 4 × 8
+#>   Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes
+#>   <chr>   <chr>      <chr>         <chr>     <chr>       <chr>       <dbl> <chr>
+#> 1 WNT     WNT3A_12H… GSE103175     WNT3A tr… Human Embr… Human          90 NA   
+#> 2 WNT     WNT3A_24H… GSE103175     WNT3A tr… Human Embr… Human          88 NA   
+#> 3 WNT     WNT3A_48H… GSE103175     WNT3A tr… Human Embr… Human          90 NA   
+#> 4 WNT     WNT3A_SLO… GSE103175     WNT3A tr… Human Embr… Human          90 NA
+
+Wnt_12h   <- LoadPathway("WNT3A_12H_ACTIVATION",  "mouse")
+Wnt_24h   <- LoadPathway("WNT3A_24H_ACTIVATION",  "mouse")
+Wnt_48h   <- LoadPathway("WNT3A_48H_ACTIVATION",  "mouse")
+Wnt_slope <- LoadPathway("WNT3A_SLOPE_ACTIVATION", "mouse")
+
+
+
+

Preprocessing and Pathway Reference States +

+
+matrix_12h   <- DataPreProcess(synthetic_test_object_100, Wnt_12h,   Seurat.object = TRUE)
+matrix_24h   <- DataPreProcess(synthetic_test_object_100, Wnt_24h,   Seurat.object = TRUE)
+matrix_48h   <- DataPreProcess(synthetic_test_object_100, Wnt_48h,   Seurat.object = TRUE)
+matrix_slope <- DataPreProcess(synthetic_test_object_100, Wnt_slope, Seurat.object = TRUE)
+
+pathwaystat_12h   <- PathwayMaxMin(matrix_12h,   Wnt_12h)
+pathwaystat_24h   <- PathwayMaxMin(matrix_24h,   Wnt_24h)
+pathwaystat_48h   <- PathwayMaxMin(matrix_48h,   Wnt_48h)
+pathwaystat_slope <- PathwayMaxMin(matrix_slope, Wnt_slope)
+
+
+
+

Compute Pathway Scores +

+
+score_12h   <- ComputeCellData(matrix_12h,   pathwaystat_12h)
+score_24h   <- ComputeCellData(matrix_24h,   pathwaystat_24h)
+score_48h   <- ComputeCellData(matrix_48h,   pathwaystat_48h)
+score_slope <- ComputeCellData(matrix_slope, pathwaystat_slope)
+
+
+
+

Prepare Plot Data and Calculate Group Statistics +

+
+plot_data_12h   <- PreparePlotData(synthetic_test_metadata, score_12h,   group = "genotype")
+plot_data_24h   <- PreparePlotData(synthetic_test_metadata, score_24h,   group = "genotype")
+plot_data_48h   <- PreparePlotData(synthetic_test_metadata, score_48h,   group = "genotype")
+plot_data_slope <- PreparePlotData(synthetic_test_metadata, score_slope, group = "genotype")
+
+pct_12h   <- CalculatePercentage(to.plot = plot_data_12h,   group_var = "genotype")
+pct_24h   <- CalculatePercentage(to.plot = plot_data_24h,   group_var = "genotype")
+pct_48h   <- CalculatePercentage(to.plot = plot_data_48h,   group_var = "genotype")
+pct_slope <- CalculatePercentage(to.plot = plot_data_slope, group_var = "genotype")
+
+pct_12h; pct_24h; pct_48h; pct_slope
+#> # A tibble: 2 × 5
+#>   group  percentage_on percentage_off cohens_d  p_value
+#>   <chr>          <dbl>          <dbl>    <dbl>    <dbl>
+#> 1 WT              41.5           58.5   -0.431 5.08e-25
+#> 2 Mutant          61.7           38.3   -0.431 5.08e-25
+#> # A tibble: 2 × 5
+#>   group  percentage_on percentage_off cohens_d  p_value
+#>   <chr>          <dbl>          <dbl>    <dbl>    <dbl>
+#> 1 WT              40.3           59.7   -0.379 2.48e-20
+#> 2 Mutant          58.7           41.3   -0.379 2.48e-20
+#> # A tibble: 2 × 5
+#>   group  percentage_on percentage_off cohens_d    p_value
+#>   <chr>          <dbl>          <dbl>    <dbl>      <dbl>
+#> 1 WT              46             54     -0.187 0.00000376
+#> 2 Mutant          53.9           46.1   -0.187 0.00000376
+#> # A tibble: 2 × 5
+#>   group  percentage_on percentage_off cohens_d  p_value
+#>   <chr>          <dbl>          <dbl>    <dbl>    <dbl>
+#> 1 WT              45.2           54.8   -0.149 0.000119
+#> 2 Mutant          52             48     -0.149 0.000119
+
+
+
+

Visualization 1 — Density Plots +

+
+p1 <- PlotPathway(plot_data_12h,   "12hr Wnt",    "genotype", c("#ae282c", "#2066a8")) +
+  annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5,
+           label = make_label(pct_12h, "WT", "Mutant"), size = 3.5, color = "black")
+
+p2 <- PlotPathway(plot_data_24h,   "24hr Wnt",    "genotype", c("#ae282c", "#2066a8")) +
+  annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5,
+           label = make_label(pct_24h, "WT", "Mutant"), size = 3.5, color = "black")
+
+p3 <- PlotPathway(plot_data_48h,   "48hr Wnt",    "genotype", c("#ae282c", "#2066a8")) +
+  annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5,
+           label = make_label(pct_48h, "WT", "Mutant"), size = 3.5, color = "black")
+
+p4 <- PlotPathway(plot_data_slope, "Wnt (slope)", "genotype", c("#ae282c", "#2066a8")) +
+  annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5,
+           label = make_label(pct_slope, "WT", "Mutant"), size = 3.5, color = "black")
+
+p1; p2; p3; p4
+

+
+
+
+

Visualization 2 — Violin + Jitter Plot +

+
+p5 <- ggplot(plot_data_12h,
+       aes(x = genotype, y = scale, fill = genotype, color = genotype)) +
+  geom_violin(alpha = 0.5, trim = FALSE) +
+  geom_jitter(width = 0.15, size = 0.6, alpha = 0.3) +
+  geom_hline(yintercept = 0, linetype = "dotted", color = "black", linewidth = 0.5) +
+  scale_fill_manual(values  = c("#ae282c", "#2066a8")) +
+  scale_color_manual(values = c("#ae282c", "#2066a8")) +
+  annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5,
+           label = make_label(pct_12h, "WT", "Mutant"), size = 3.5, color = "black") +
+  labs(title = "12hr WNT Pathway Activation",
+       x = NULL, y = "Relative Transduction State (z-score)") +
+  theme_classic() +
+  theme(legend.position = "none")
+p5
+

+
+
+
+

Visualization 3 — Waterfall Plot +

+
+waterfall_data <- plot_data_12h %>%
+  group_by(genotype) %>%
+  arrange(scale, .by_group = TRUE) %>%
+  mutate(rank  = row_number(),
+         state = ifelse(scale >= 0, "ON", "OFF")) %>%
+  ungroup()
+
+annotation_df <- pct_12h %>%
+  mutate(
+    label = paste0("Cohen's d = ", round(cohens_d, 3), "\n",
+                   "p = ", formatC(p_value, format = "e", digits = 2), "\n",
+                   "ON = ", percentage_on, "%\n",
+                   "OFF = ", percentage_off, "%"),
+    genotype = group
+  )
+
+p6 <- ggplot(waterfall_data, aes(x = rank, y = scale, fill = state)) +
+  geom_bar(stat = "identity", width = 1) +
+  facet_wrap(~ genotype, scales = "free_x") +
+  scale_fill_manual(values = c("ON" = "#ae282c", "OFF" = "#2066a8")) +
+  geom_hline(yintercept = 0, color = "black", linewidth = 0.4) +
+  geom_text(data = annotation_df,
+            aes(x = Inf, y = Inf, label = label),
+            hjust = 1.1, vjust = 1.5, size = 3, color = "black",
+            inherit.aes = FALSE) +
+  labs(title = "Waterfall Plot of Cell Activation",
+       x = "Cells (ranked by activation)",
+       y = "Relative Transduction State (z-score)",
+       fill = "State") +
+  theme_classic() +
+  theme(axis.text.x = element_blank(), axis.ticks.x = element_blank(),
+        strip.background = element_rect(fill = "grey90", color = NA))
+p6
+

+
+
+
+

Customize Pathway Input +

+
+# Customize the wnt pathway using coefficients defined by us
+Wnt.molecules <- c('Lgr5','Rnf43','Lrp5',
+           'Lrp6','Fzd6','Ctnnb1',
+           'Gsk3b','Ccnd1','Axin2',
+           'Myc','Lef1','Tcf7',
+           'Tcf7l1','Tcf7l2','Tle1',
+           'Apc','Csnk1a1','Dvl1')
+Wnt.cof <- c(1,1,-1,-1,-1,-1, 1,1,1, 1,1,1, 1,1,1, -1,-1,-1) 
+Wnt_df <- data.frame(
+  Gene_Symbol = Wnt.molecules,
+  Coefficient = Wnt.cof)
+
+print(Wnt_df)
+#>    Gene_Symbol Coefficient
+#> 1         Lgr5           1
+#> 2        Rnf43           1
+#> 3         Lrp5          -1
+#> 4         Lrp6          -1
+#> 5         Fzd6          -1
+#> 6       Ctnnb1          -1
+#> 7        Gsk3b           1
+#> 8        Ccnd1           1
+#> 9        Axin2           1
+#> 10         Myc           1
+#> 11        Lef1           1
+#> 12        Tcf7           1
+#> 13      Tcf7l1           1
+#> 14      Tcf7l2           1
+#> 15        Tle1           1
+#> 16         Apc          -1
+#> 17     Csnk1a1          -1
+#> 18        Dvl1          -1
+
+# Calculate score using customized pathway data
+matrix_df   <- DataPreProcess(synthetic_test_object_100, Wnt_df,   Seurat.object = TRUE)
+pathwaystat_df   <- PathwayMaxMin(matrix_df,   Wnt_df)
+score_df   <- ComputeCellData(matrix_df,   pathwaystat_df)
+plot_data_df   <- PreparePlotData(synthetic_test_metadata, score_df,   group = "genotype")
+pct_df   <- CalculatePercentage(to.plot = plot_data_df,   group_var = "genotype")
+PlotPathway(plot_data_df,   "Customized Wnt",    "genotype", c("#ae282c", "#2066a8")) +
+  annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5,
+           label = make_label(pct_df, "WT", "Mutant"), size = 3.5, color = "black")
+

+
+
+

Null Distribution — Random Gene Sets +

+
+set.seed(123)
+
+real_n_genes  <- nrow(matrix_12h)
+real_cohens_d <- pct_12h$cohens_d[1]
+n_reps        <- 20
+
+# Sparse size grid covering the relevant range, always including real n
+size_grid <- sort(unique(c(
+  seq(5, 50,  by = 5),
+  seq(60, 200, by = 20),
+  real_n_genes
+)))
+
+all_genes_pool <- rownames(
+  GetAssayData(synthetic_test_object_100, assay = "RNA", layer = "data")
+)
+size_grid <- size_grid[size_grid <= length(all_genes_pool)]
+
+cohens_d_random <- data.frame()
+
+for (i in size_grid) {
+  for (rep in seq_len(n_reps)) {
+    sampled_genes <- sample(all_genes_pool, i)
+    fake_pathway  <- data.frame(
+      Gene_Symbol = sampled_genes,
+      Coefficient = sample(c(-1L, 1L), i, replace = TRUE)
+    )
+    expr_matrix      <- DataPreProcess(synthetic_test_object_100, fake_pathway,
+                                       Seurat.object = TRUE)
+    pathwaystat_rand <- PathwayMaxMin(expr_matrix, fake_pathway)
+    score_rand       <- ComputeCellData(expr_matrix, pathwaystat_rand)
+    plot_data_rand   <- PreparePlotData(synthetic_test_metadata, score_rand,
+                                        group = "genotype")
+    outcome_rand     <- CalculatePercentage(plot_data_rand, group_var = "genotype")
+
+    cohens_d_random <- rbind(cohens_d_random, data.frame(
+      n_genes  = i,
+      rep      = rep,
+      cohens_d = outcome_rand$cohens_d[1]
+    ))
+  }
+}
+
+cohens_d_summary_rand <- cohens_d_random %>%
+  group_by(n_genes) %>%
+  summarise(mean_d = mean(cohens_d, na.rm = TRUE),
+            sd_d   = sd(cohens_d,   na.rm = TRUE),
+            .groups = "drop")
+
+null_at_real_n <- cohens_d_random %>% filter(n_genes == real_n_genes)
+emp_p <- mean(abs(null_at_real_n$cohens_d) >= abs(real_cohens_d), na.rm = TRUE)
+
+cat("Real pathway Cohen's d:    ", round(real_cohens_d, 3), "\n")
+#> Real pathway Cohen's d:     -0.431
+cat("Null mean at same n genes: ", round(mean(null_at_real_n$cohens_d, na.rm = TRUE), 3), "\n")
+#> Null mean at same n genes:  -0.082
+cat("Null SD at same n genes:   ", round(sd(null_at_real_n$cohens_d,   na.rm = TRUE), 3), "\n")
+#> Null SD at same n genes:    0.328
+cat("Empirical p-value:         ", round(emp_p, 3), "\n")
+#> Empirical p-value:          0.25
+
+p7 <- ggplot() +
+  geom_hline(yintercept =  0,   linetype = "solid",  color = "#888780", linewidth = 0.4) +
+  geom_hline(yintercept =  0.8, linetype = "dashed", color = "#E24B4A", linewidth = 0.5) +
+  geom_hline(yintercept = -0.8, linetype = "dashed", color = "#E24B4A", linewidth = 0.5) +
+  geom_hline(yintercept =  0.5, linetype = "dashed", color = "#EF9F27", linewidth = 0.5) +
+  geom_hline(yintercept = -0.5, linetype = "dashed", color = "#EF9F27", linewidth = 0.5) +
+  geom_point(data = cohens_d_random,
+             aes(x = n_genes, y = cohens_d),
+             color = "#534AB7", alpha = 0.25, size = 1.2) +
+  geom_ribbon(data = cohens_d_summary_rand,
+              aes(x = n_genes, ymin = mean_d - sd_d, ymax = mean_d + sd_d),
+              fill = "#534AB7", alpha = 0.15) +
+  geom_line(data = cohens_d_summary_rand,
+            aes(x = n_genes, y = mean_d),
+            color = "#534AB7", linewidth = 0.9) +
+  geom_point(aes(x = real_n_genes, y = real_cohens_d),
+             color = "#E24B4A", size = 3, shape = 18) +
+  geom_vline(xintercept = real_n_genes, color = "#E24B4A",
+             linetype = "dashed", linewidth = 0.5) +
+  annotate("text", x = real_n_genes, y = Inf,
+           label = paste0("Real pathway\nn = ", real_n_genes,
+                          "\nd = ", round(real_cohens_d, 3),
+                          "\nemp. p = ", round(emp_p, 3)),
+           hjust = -0.1, vjust = 1.5, size = 3, color = "#E24B4A") +
+  annotate("text", x = max(cohens_d_summary_rand$n_genes), y =  0.82,
+           label = "large (+0.8)",  hjust = 1, size = 3, color = "#E24B4A") +
+  annotate("text", x = max(cohens_d_summary_rand$n_genes), y = -0.82,
+           label = "large (-0.8)",  hjust = 1, size = 3, color = "#E24B4A") +
+  annotate("text", x = max(cohens_d_summary_rand$n_genes), y =  0.52,
+           label = "medium (+0.5)", hjust = 1, size = 3, color = "#EF9F27") +
+  annotate("text", x = max(cohens_d_summary_rand$n_genes), y = -0.52,
+           label = "medium (-0.5)", hjust = 1, size = 3, color = "#EF9F27") +
+  labs(title = "Null Distribution — Cohen's d by Gene Set Size",
+       x = "Number of genes", y = "Cohen's d") +
+  theme_minimal()
+p7
+

+
+
+
+

Null Distribution — Within Pathway Gene Pool +

+
+set.seed(123)
+
+all_genes <- rownames(matrix_12h)
+n_genes   <- length(all_genes)
+n_reps    <- 10
+
+cohens_d_pathway <- data.frame()
+
+for (i in 2:n_genes) {
+  for (rep in seq_len(n_reps)) {
+    sampled_genes    <- sample(all_genes, i)
+    expr_matrix      <- matrix_12h[sampled_genes, , drop = FALSE]
+    pathwaystat_rand <- PathwayMaxMin(expr_matrix, Wnt_12h)
+    score_rand       <- ComputeCellData(expr_matrix, pathwaystat_rand)
+    plot_data_rand   <- PreparePlotData(synthetic_test_metadata, score_rand,
+                                        group = "genotype")
+    outcome_rand     <- CalculatePercentage(to.plot   = plot_data_rand,
+                                            group_var = "genotype")
+    cohens_d_pathway <- rbind(cohens_d_pathway, data.frame(
+      n_genes  = i,
+      rep      = rep,
+      cohens_d = outcome_rand$cohens_d[1]
+    ))
+  }
+}
+
+cohens_d_summary_pw <- cohens_d_pathway %>%
+  group_by(n_genes) %>%
+  summarise(mean_d = mean(cohens_d, na.rm = TRUE),
+            sd_d   = sd(cohens_d,   na.rm = TRUE),
+            .groups = "drop")
+
+null_at_real_n_pw <- cohens_d_pathway %>% filter(n_genes == real_n_genes)
+emp_p_pw <- mean(abs(null_at_real_n_pw$cohens_d) >= abs(real_cohens_d), na.rm = TRUE)
+
+cat("Real pathway Cohen's d:    ", round(real_cohens_d, 3), "\n")
+#> Real pathway Cohen's d:     -0.431
+cat("Null mean at same n genes: ", round(mean(null_at_real_n_pw$cohens_d, na.rm = TRUE), 3), "\n")
+#> Null mean at same n genes:  -0.431
+cat("Null SD at same n genes:   ", round(sd(null_at_real_n_pw$cohens_d,   na.rm = TRUE), 3), "\n")
+#> Null SD at same n genes:    0
+cat("Empirical p-value:         ", round(emp_p_pw, 3), "\n")
+#> Empirical p-value:          0.6
+
+p_null <- ggplot() +
+  geom_hline(yintercept =  0,   linetype = "solid",  color = "#888780", linewidth = 0.4) +
+  geom_hline(yintercept =  0.8, linetype = "dashed", color = "#E24B4A", linewidth = 0.5) +
+  geom_hline(yintercept = -0.8, linetype = "dashed", color = "#E24B4A", linewidth = 0.5) +
+  geom_hline(yintercept =  0.5, linetype = "dashed", color = "#EF9F27", linewidth = 0.5) +
+  geom_hline(yintercept = -0.5, linetype = "dashed", color = "#EF9F27", linewidth = 0.5) +
+  geom_point(data = cohens_d_pathway,
+             aes(x = n_genes, y = cohens_d),
+             color = "#534AB7", alpha = 0.25, size = 1.2) +
+  geom_ribbon(data = cohens_d_summary_pw,
+              aes(x = n_genes, ymin = mean_d - sd_d, ymax = mean_d + sd_d),
+              fill = "#534AB7", alpha = 0.15) +
+  geom_line(data = cohens_d_summary_pw,
+            aes(x = n_genes, y = mean_d),
+            color = "#534AB7", linewidth = 0.9) +
+  geom_point(aes(x = real_n_genes, y = real_cohens_d),
+             color = "#E24B4A", size = 3, shape = 18) +
+  geom_vline(xintercept = real_n_genes, color = "#E24B4A",
+             linetype = "dashed", linewidth = 0.5) +
+  annotate("text", x = real_n_genes, y = Inf,
+           label = paste0("Real pathway\nn = ", real_n_genes,
+                          "\nd = ", round(real_cohens_d, 3)),
+           hjust = -0.1, vjust = 1.5, size = 3, color = "#E24B4A") +
+  labs(title = "Null Distribution — Cohen's d by Gene Set Size (10 reps each)",
+       x = "Number of genes", y = "Cohen's d") +
+  theme_minimal()
+p_null
+

+
+
+
+

Sensitivity Analysis 1 — Effect of Input Matrix Type +

+
+data("synthetic_test_matrix_100")
+
+matrix_raw     <- synthetic_test_matrix_100
+lib_size       <- colSums(synthetic_test_matrix_100)
+matrix_lognorm <- log1p(sweep(synthetic_test_matrix_100, 2, lib_size, "/") * 1e4)
+matrix_norm    <- sweep(synthetic_test_matrix_100, 2, lib_size, "/") * 1e4
+gene_var       <- apply(matrix_lognorm, 1, var)
+hvg_genes      <- names(sort(gene_var, decreasing = TRUE))[
+                    1:ceiling(nrow(matrix_lognorm) * 0.5)]
+matrix_hvg     <- matrix_lognorm[hvg_genes, ]
+
+run_pipeline <- function(expr_mat, pathwaydata, metadata, group,
+                          scale.data = TRUE) {
+  mat      <- DataPreProcess(expr_mat, pathwaydata, scale.data = scale.data)
+  pstat    <- PathwayMaxMin(mat, pathwaydata)
+  score    <- ComputeCellData(mat, pstat)
+  plotdata <- PreparePlotData(metadata, score, group = group)
+  outcome  <- CalculatePercentage(plotdata, group_var = group)
+  list(score = score, plotdata = plotdata, outcome = outcome)
+}
+
+result_raw             <- run_pipeline(matrix_raw,     Wnt_12h, synthetic_test_metadata, "genotype")
+result_lognorm         <- run_pipeline(matrix_lognorm, Wnt_12h, synthetic_test_metadata, "genotype")
+result_norm            <- run_pipeline(matrix_norm,    Wnt_12h, synthetic_test_metadata, "genotype")
+result_hvg             <- run_pipeline(matrix_hvg,     Wnt_12h, synthetic_test_metadata, "genotype")
+result_raw_noscale     <- run_pipeline(matrix_raw,     Wnt_12h, synthetic_test_metadata, "genotype", scale.data = FALSE)
+result_lognorm_noscale <- run_pipeline(matrix_lognorm, Wnt_12h, synthetic_test_metadata, "genotype", scale.data = FALSE)
+result_norm_noscale    <- run_pipeline(matrix_norm,    Wnt_12h, synthetic_test_metadata, "genotype", scale.data = FALSE)
+result_hvg_noscale     <- run_pipeline(matrix_hvg,     Wnt_12h, synthetic_test_metadata, "genotype", scale.data = FALSE)
+
+input_labels <- c("Raw", "Log-norm", "Norm", "HVG",
+                   "Raw (noscale)", "Log-norm (noscale)",
+                   "Norm (noscale)", "HVG (noscale)")
+results_list <- list(result_raw, result_lognorm, result_norm, result_hvg,
+                      result_raw_noscale, result_lognorm_noscale,
+                      result_norm_noscale, result_hvg_noscale)
+
+cohens_d_input <- data.frame(
+  input_type = input_labels,
+  cohens_d   = sapply(results_list, function(r) r$outcome$cohens_d[1]),
+  p_value    = sapply(results_list, function(r) r$outcome$p_value[1])
+)
+print(cohens_d_input)
+#>           input_type    cohens_d      p_value
+#> 1                Raw -0.80105995 1.120664e-65
+#> 2           Log-norm -0.43058889 5.083976e-25
+#> 3               Norm -0.38149058 2.648944e-18
+#> 4                HVG -0.02940827 5.222419e-01
+#> 5      Raw (noscale) -0.99496812 9.932645e-94
+#> 6 Log-norm (noscale) -0.22648846 5.743074e-07
+#> 7     Norm (noscale) -0.42743835 2.281451e-22
+#> 8      HVG (noscale) -0.02943217 5.259599e-01
+
+score_df_sens <- as.data.frame(
+  setNames(lapply(results_list, function(r) as.numeric(r$score)), input_labels),
+  row.names = names(results_list[[1]]$score)
+)
+
+score_cor <- cor(score_df_sens, method = "spearman", use = "pairwise.complete.obs")
+p12 <- pheatmap(score_cor,
+         color = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100),
+         breaks = seq(-1, 1, length.out = 101),
+         display_numbers = TRUE, number_format = "%.2f",
+         fontsize_number = 9,
+         main = "Score Correlation Across Input Matrix Types — Spearman")
+
+named_results <- list(Raw = result_raw, `Log-norm` = result_lognorm,
+                       Norm = result_norm, HVG = result_hvg)
+density_plots <- lapply(
+  names(named_results),
+  function(nm) PlotPathway(named_results[[nm]]$plotdata,
+                            paste("Wnt 12h —", nm), "genotype",
+                            c("#ae282c", "#2066a8"))
+)
+p13 <- wrap_plots(density_plots, ncol = 2) +
+  plot_annotation(title = "Pathway Activation by Input Matrix Type")
+
+p12; p13
+

+
+
+
+

Correlation with Technical Confounders +

+
+normalized_mat <- GetAssayData(synthetic_test_object_100, assay = "RNA", layer = "data")
+common_genes   <- intersect(rownames(normalized_mat), Wnt_12h$Gene_Symbol)
+gene_matrix    <- as.matrix(normalized_mat[common_genes, ])
+
+mean_expr            <- colMeans(gene_matrix, na.rm = TRUE)
+zscore_mean_per_cell <- colMeans(t(scale(t(gene_matrix))), na.rm = TRUE)
+seurat_meta          <- synthetic_test_object_100@meta.data
+
+make_scatter <- function(df, x_col, x_label) {
+  r <- cor(df$embed_score, df[[x_col]], method = "spearman", use = "complete.obs")
+  ggplot(df, aes(x = .data[[x_col]], y = embed_score)) +
+    geom_point(alpha = 0.4, size = 1.2, color = "#534AB7") +
+    geom_smooth(method = "lm", color = "#E24B4A", linewidth = 0.8, se = TRUE) +
+    labs(title = sprintf("%s (rho = %.3f)", x_label, r),
+         x = x_label, y = "PathwayEmbed score") +
+    theme_minimal()
+}
+
+confounder_df_norm <- data.frame(
+  cell         = names(score_12h),
+  embed_score  = as.numeric(score_12h),
+  mean_expr    = mean_expr[names(score_12h)],
+  zscore_expr  = zscore_mean_per_cell[names(score_12h)],
+  nCount_RNA   = seurat_meta[names(score_12h), "nCount_RNA"],
+  nFeature_RNA = seurat_meta[names(score_12h), "nFeature_RNA"]
+)
+
+for (cov in c("mean_expr", "zscore_expr", "nCount_RNA", "nFeature_RNA")) {
+  r <- cor(confounder_df_norm$embed_score, confounder_df_norm[[cov]],
+           method = "spearman", use = "complete.obs")
+  cat(sprintf("Spearman vs %-20s : %.3f\n", cov, r))
+}
+#> Spearman vs mean_expr            : 0.163
+#> Spearman vs zscore_expr          : 0.280
+#> Spearman vs nCount_RNA           : 0.089
+#> Spearman vs nFeature_RNA         : -0.145
+
+p_nor <- (make_scatter(confounder_df_norm, "mean_expr",    "Mean expression") +
+           make_scatter(confounder_df_norm, "zscore_expr",  "Z-score mean")) /
+          (make_scatter(confounder_df_norm, "nCount_RNA",   "nCount_RNA") +
+           make_scatter(confounder_df_norm, "nFeature_RNA", "nFeature_RNA"))
+p_nor
+

+
+
+

Correlation with Technical Confounders — Raw Counts +

+
+common_genes_raw <- intersect(rownames(matrix_raw), Wnt_12h$Gene_Symbol)
+gene_matrix_raw  <- as.matrix(matrix_raw[common_genes_raw, ])
+
+mean_expr_raw            <- colMeans(gene_matrix_raw, na.rm = TRUE)
+zscore_mean_per_cell_raw <- colMeans(t(scale(t(gene_matrix_raw))), na.rm = TRUE)
+score_raw_12h            <- result_raw$score
+
+confounder_df_raw <- data.frame(
+  cell         = names(score_raw_12h),
+  embed_score  = as.numeric(score_raw_12h),
+  mean_expr    = mean_expr_raw[names(score_raw_12h)],
+  zscore_expr  = zscore_mean_per_cell_raw[names(score_raw_12h)],
+  nCount_RNA   = seurat_meta[names(score_raw_12h), "nCount_RNA"],
+  nFeature_RNA = seurat_meta[names(score_raw_12h), "nFeature_RNA"]
+)
+
+for (cov in c("mean_expr", "zscore_expr", "nCount_RNA", "nFeature_RNA")) {
+  r <- cor(confounder_df_raw$embed_score, confounder_df_raw[[cov]],
+           method = "spearman", use = "complete.obs")
+  cat(sprintf("Spearman vs %-20s : %.3f\n", cov, r))
+}
+#> Spearman vs mean_expr            : 0.411
+#> Spearman vs zscore_expr          : 0.406
+#> Spearman vs nCount_RNA           : 0.335
+#> Spearman vs nFeature_RNA         : -0.024
+
+p_raw <- (make_scatter(confounder_df_raw, "mean_expr",    "Mean expression") +
+           make_scatter(confounder_df_raw, "zscore_expr",  "Z-score mean")) /
+          (make_scatter(confounder_df_raw, "nCount_RNA",   "nCount_RNA") +
+           make_scatter(confounder_df_raw, "nFeature_RNA", "nFeature_RNA"))
+p_raw
+

+
+
+
+

Benchmark Against PROGENy and AddModuleScore +

+
+normalized_mat_dense <- as.matrix(normalized_mat)
+
+progeny_scores <- progeny(
+  normalized_mat_dense,
+  scale    = TRUE,
+  organism = "Mouse",
+  top      = 100,
+  perm     = 1
+)
+progeny_wnt <- setNames(as.numeric(progeny_scores[, "WNT"]),
+                         rownames(progeny_scores))
+
+wnt_features <- rownames(matrix_24h)
+synthetic_test_object_100 <- AddModuleScore(
+  object   = synthetic_test_object_100,
+  features = list(wnt_features),
+  name     = "WNT_ModuleScore",
+  ctrl     = 5,
+  nbin     = 10
+)
+module_score <- setNames(
+  synthetic_test_object_100@meta.data$WNT_ModuleScore1,
+  rownames(synthetic_test_object_100@meta.data)
+)
+
+cells <- names(score_24h)
+benchmark_df <- data.frame(
+  PathwayEmbed   = as.numeric(score_24h),
+  PROGENy        = as.numeric(progeny_wnt[cells]),
+  AddModuleScore = as.numeric(module_score[cells]),
+  mean_expr      = as.numeric(mean_expr[cells]),
+  zscore_expr    = as.numeric(zscore_mean_per_cell[cells]),
+  row.names      = cells
+)
+
+benchmark_cor <- cor(benchmark_df, method = "spearman",
+                     use = "pairwise.complete.obs")
+print(round(benchmark_cor, 3))
+#>                PathwayEmbed PROGENy AddModuleScore mean_expr zscore_expr
+#> PathwayEmbed          1.000   0.042         -0.049    -0.078      -0.082
+#> PROGENy               0.042   1.000          0.028     0.046       0.137
+#> AddModuleScore       -0.049   0.028          1.000     0.625       0.440
+#> mean_expr            -0.078   0.046          0.625     1.000       0.807
+#> zscore_expr          -0.082   0.137          0.440     0.807       1.000
+
+p9 <- pheatmap(
+  benchmark_cor,
+  color           = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100),
+  breaks          = seq(-1, 1, length.out = 101),
+  display_numbers = TRUE, number_format = "%.2f",
+  fontsize_number = 9,
+  main            = "Method Benchmark — Spearman Correlation"
+)
+p9
+

+
+
+genotype_label <- ifelse(
+  synthetic_test_metadata[cells, "genotype"] == "Mutant", 1L, 0L
+)
+
+compute_auroc <- function(scores, labels) {
+  r       <- roc(labels, scores, quiet = TRUE)
+  auc_val <- as.numeric(auc(r))
+  if (auc_val < 0.5) auc_val <- 1 - auc_val
+  auc_val
+}
+
+auroc_results <- data.frame(
+  Method = colnames(benchmark_df),
+  AUROC  = sapply(benchmark_df, compute_auroc, labels = genotype_label)
+)
+auroc_results <- auroc_results[order(-auroc_results$AUROC), ]
+print(auroc_results)
+#>                        Method    AUROC
+#> zscore_expr       zscore_expr 0.755310
+#> PROGENy               PROGENy 0.656320
+#> mean_expr           mean_expr 0.626260
+#> PathwayEmbed     PathwayEmbed 0.619310
+#> AddModuleScore AddModuleScore 0.526651
+
+compute_cohens_d_method <- function(scores, metadata, group_col) {
+  scores <- setNames(as.numeric(scores), names(scores))
+  pd     <- PreparePlotData(metadata, scores, group = group_col)
+  pct    <- CalculatePercentage(pd, group_var = group_col)
+  abs(pct$cohens_d[1])
+}
+
+cohens_d_results <- data.frame(
+  Method   = colnames(benchmark_df),
+  Cohens_d = sapply(
+    colnames(benchmark_df),
+    function(m) compute_cohens_d_method(
+      setNames(benchmark_df[[m]], rownames(benchmark_df)),
+      synthetic_test_metadata, "genotype"
+    )
+  )
+)
+cohens_d_results <- cohens_d_results[order(-cohens_d_results$Cohens_d), ]
+print(cohens_d_results)
+#>                        Method   Cohens_d
+#> zscore_expr       zscore_expr 0.94892009
+#> mean_expr           mean_expr 0.44722384
+#> PathwayEmbed     PathwayEmbed 0.37911019
+#> AddModuleScore AddModuleScore 0.07942301
+#> PROGENy               PROGENy 0.07087977
+
+method_colors <- c(
+  "PathwayEmbed"   = "#534AB7",
+  "PROGENy"        = "#E24B4A",
+  "AddModuleScore" = "#EF9F27",
+  "mean_expr"      = "#888780",
+  "zscore_expr"    = "#B4B2A9"
+)
+
+p10 <- ggplot(auroc_results, aes(x = reorder(Method, AUROC), y = AUROC, fill = Method)) +
+  geom_bar(stat = "identity", width = 0.6) +
+  geom_hline(yintercept = 0.5, linetype = "dashed", color = "black") +
+  coord_flip() +
+  scale_fill_manual(values = method_colors) +
+  labs(title = "AUROC: Mutant vs WT separation by scoring method",
+       x = NULL, y = "AUROC") +
+  ylim(0, 1) +
+  theme_classic() +
+  theme(legend.position = "none",
+        axis.text.y  = element_text(size = 12),
+        axis.text.x  = element_text(size = 11),
+        axis.title.x = element_text(size = 12),
+        plot.title   = element_text(size = 13, face = "bold"))
+
+p11 <- ggplot(cohens_d_results, aes(x = reorder(Method, Cohens_d), y = Cohens_d, fill = Method)) +
+  geom_bar(stat = "identity", width = 0.6) +
+  geom_hline(yintercept = 0.5, linetype = "dashed", color = "black") +
+  coord_flip() +
+  scale_fill_manual(values = method_colors) +
+  labs(title = "Cohen's d: Mutant vs WT separation by scoring method",
+       x = NULL, y = "Cohen's d") +
+  ylim(0, 1) +
+  theme_classic() +
+  theme(legend.position = "none",
+        axis.text.y  = element_text(size = 12),
+        axis.text.x  = element_text(size = 11),
+        axis.title.x = element_text(size = 12),
+        plot.title   = element_text(size = 13, face = "bold"))
+
+p10; p11
+

+
+
+
+

Sensitivity Analysis 2 — Effect of Distance Method +

+
+score_manhattan <- ComputeCellData(matrix_24h, pathwaystat_24h,
+                                   distance.method = "manhattan")
+score_euclidean <- ComputeCellData(matrix_24h, pathwaystat_24h,
+                                   distance.method = "euclidean")
+
+cor_dist <- cor(score_manhattan, score_euclidean, method = "spearman")
+cat("Spearman correlation (manhattan vs euclidean):", round(cor_dist, 3), "\n")
+#> Spearman correlation (manhattan vs euclidean): 0.942
+
+plotdata_manhattan <- PreparePlotData(synthetic_test_metadata, score_manhattan,
+                                      group = "genotype")
+plotdata_euclidean <- PreparePlotData(synthetic_test_metadata, score_euclidean,
+                                      group = "genotype")
+
+pct_manhattan <- CalculatePercentage(plotdata_manhattan, group_var = "genotype")
+pct_euclidean <- CalculatePercentage(plotdata_euclidean, group_var = "genotype")
+
+distance_comparison <- data.frame(
+  method     = c("Manhattan", "Euclidean"),
+  cohens_d   = c(pct_manhattan$cohens_d[1],  pct_euclidean$cohens_d[1]),
+  p_value    = c(pct_manhattan$p_value[1],   pct_euclidean$p_value[1]),
+  pct_on_wt  = c(pct_manhattan$percentage_on[pct_manhattan$group == "WT"],
+                  pct_euclidean$percentage_on[pct_euclidean$group == "WT"]),
+  pct_on_mut = c(pct_manhattan$percentage_on[pct_manhattan$group == "Mutant"],
+                  pct_euclidean$percentage_on[pct_euclidean$group == "Mutant"])
+)
+print(distance_comparison)
+#>      method   cohens_d      p_value pct_on_wt pct_on_mut
+#> 1 Manhattan -0.3791102 2.479654e-20      40.3       58.7
+#> 2 Euclidean -0.4669349 3.968028e-32      38.5       63.9
+
+dist_df <- data.frame(manhattan = as.numeric(score_manhattan),
+                       euclidean = as.numeric(score_euclidean),
+                       row.names = names(score_manhattan))
+
+p_scatter <- ggplot(dist_df, aes(x = manhattan, y = euclidean)) +
+  geom_point(alpha = 0.4, size = 1.2, color = "#534AB7") +
+  geom_smooth(method = "lm", color = "#E24B4A", linewidth = 0.8, se = TRUE) +
+  labs(title = sprintf("Manhattan vs Euclidean (rho = %.3f)", cor_dist),
+       x = "Manhattan score", y = "Euclidean score") +
+  theme_minimal()
+
+p_man_plot <- PlotPathway(plotdata_manhattan, "Wnt 24h — Manhattan",
+                           "genotype", c("#ae282c", "#2066a8"))
+p_euc_plot <- PlotPathway(plotdata_euclidean, "Wnt 24h — Euclidean",
+                           "genotype", c("#ae282c", "#2066a8"))
+
+p_scatter / (p_man_plot + p_euc_plot) +
+  plot_annotation(title = "Sensitivity to Distance Method")
+

+
+
+
+ + + +
+ + + +
+
+ + + + + + + diff --git a/docs/articles/examples_updated.md b/docs/articles/examples_updated.md new file mode 100644 index 0000000..0f2c7e4 --- /dev/null +++ b/docs/articles/examples_updated.md @@ -0,0 +1,876 @@ +# Toy Set + +## Overview + +This vignette demonstrates how to use the PathwayEmbed package to +compute and visualize pathway activation using single-cell +transcriptomic data. We use the example dataset +`synthetic_test_object_100` included with the package. + +------------------------------------------------------------------------ + +## Load Packages and Data + +``` r +library(PathwayEmbed) +library(Seurat) +library(dplyr) +library(tidyr) +library(ggplot2) +library(ggridges) +library(patchwork) +library(pheatmap) +library(progeny) +library(pROC) + +data("synthetic_test_object_100") +data("synthetic_test_metadata") +``` + +------------------------------------------------------------------------ + +## Helper: Annotation Label Builder + +``` r +make_label <- function(stats, group1, group2) { + d <- round(stats$cohens_d[1], 3) + p <- formatC(stats$p_value[1], format = "e", digits = 2) + on1 <- stats$percentage_on[stats$group == group1] + off1 <- stats$percentage_off[stats$group == group1] + on2 <- stats$percentage_on[stats$group == group2] + off2 <- stats$percentage_off[stats$group == group2] + paste0( + group1, ": ON=", on1, "%, OFF=", off1, "%\n", + group2, ": ON=", on2, "%, OFF=", off2, "%\n", + "Cohen's d = ", d, "\n", + "p = ", p + ) +} +``` + +------------------------------------------------------------------------ + +## Load Pathway Databases + +``` r +ListPathway() +#> # A tibble: 17 × 8 +#> Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes +#> +#> 1 HIF1A Hypoxia_6hr GSE227502 Hypoxia … Primary hu… Human 21 +#> 2 HIF1A Hypoxia_24hr GSE227502 Hypoxia … Primary hu… Human 18 +#> 3 HIF1A Hypoxia_5Day GSE227502 Hypoxia … Primary hu… Human 10 +#> 4 HIPPO HIPPO_heat GSE133251 Heat str… B16-OVA me… Mouse 40 +#> 5 NOTCH NOTCH_JAG1 GSE223734 rJAG1 li… Mouse embr… Mouse 5 +#> 6 NOTCH NOTCH_CB103_IN… GSE221577 CB-103 N… RPMI-8402 … Human 46 +#> 7 NOTCH NOTCH_LY_INHIB… GSE221577 LY411575… RPMI-8402 … Human 46 +#> 8 NOTCH NOTCH_JAG1_2H GSE235637 JAG1 sti… SVG-A cells Human 11 +#> 9 NOTCH NOTCH_JAG1_4H GSE235637 JAG1 sti… SVG-A cells Human 11 +#> 10 NOTCH NOTCH_JAG1_24H GSE235637 JAG1 sti… SVG-A cells Human 11 +#> 11 TGFB TGFB_Human_D1 GSE110021 TGF-β1 t… WI-38 fibr… Human 35 +#> 12 TGFB TGFB_Human_D20 GSE110021 TGF-β1 t… WI-38 fibr… Human 39 +#> 13 TGFB TGFB_Mouse GSE246932 TGF-β1 t… T Cells Mouse 9 +#> 14 WNT WNT3A_12H_ACTI… GSE103175 WNT3A tr… Human Embr… Human 90 +#> 15 WNT WNT3A_24H_ACTI… GSE103175 WNT3A tr… Human Embr… Human 88 +#> 16 WNT WNT3A_48H_ACTI… GSE103175 WNT3A tr… Human Embr… Human 90 +#> 17 WNT WNT3A_SLOPE_AC… GSE103175 WNT3A tr… Human Embr… Human 90 +#> # ℹ 1 more variable: Notes +ListPathway("Pathway") +#> [1] "HIF1A" "HIPPO" "NOTCH" "TGFB" "WNT" +ListPathway("WNT") +#> # A tibble: 4 × 8 +#> Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes +#> +#> 1 WNT WNT3A_12H… GSE103175 WNT3A tr… Human Embr… Human 90 NA +#> 2 WNT WNT3A_24H… GSE103175 WNT3A tr… Human Embr… Human 88 NA +#> 3 WNT WNT3A_48H… GSE103175 WNT3A tr… Human Embr… Human 90 NA +#> 4 WNT WNT3A_SLO… GSE103175 WNT3A tr… Human Embr… Human 90 NA + +Wnt_12h <- LoadPathway("WNT3A_12H_ACTIVATION", "mouse") +Wnt_24h <- LoadPathway("WNT3A_24H_ACTIVATION", "mouse") +Wnt_48h <- LoadPathway("WNT3A_48H_ACTIVATION", "mouse") +Wnt_slope <- LoadPathway("WNT3A_SLOPE_ACTIVATION", "mouse") +``` + +------------------------------------------------------------------------ + +## Preprocessing and Pathway Reference States + +``` r +matrix_12h <- DataPreProcess(synthetic_test_object_100, Wnt_12h, Seurat.object = TRUE) +matrix_24h <- DataPreProcess(synthetic_test_object_100, Wnt_24h, Seurat.object = TRUE) +matrix_48h <- DataPreProcess(synthetic_test_object_100, Wnt_48h, Seurat.object = TRUE) +matrix_slope <- DataPreProcess(synthetic_test_object_100, Wnt_slope, Seurat.object = TRUE) + +pathwaystat_12h <- PathwayMaxMin(matrix_12h, Wnt_12h) +pathwaystat_24h <- PathwayMaxMin(matrix_24h, Wnt_24h) +pathwaystat_48h <- PathwayMaxMin(matrix_48h, Wnt_48h) +pathwaystat_slope <- PathwayMaxMin(matrix_slope, Wnt_slope) +``` + +------------------------------------------------------------------------ + +## Compute Pathway Scores + +``` r +score_12h <- ComputeCellData(matrix_12h, pathwaystat_12h) +score_24h <- ComputeCellData(matrix_24h, pathwaystat_24h) +score_48h <- ComputeCellData(matrix_48h, pathwaystat_48h) +score_slope <- ComputeCellData(matrix_slope, pathwaystat_slope) +``` + +------------------------------------------------------------------------ + +## Prepare Plot Data and Calculate Group Statistics + +``` r +plot_data_12h <- PreparePlotData(synthetic_test_metadata, score_12h, group = "genotype") +plot_data_24h <- PreparePlotData(synthetic_test_metadata, score_24h, group = "genotype") +plot_data_48h <- PreparePlotData(synthetic_test_metadata, score_48h, group = "genotype") +plot_data_slope <- PreparePlotData(synthetic_test_metadata, score_slope, group = "genotype") + +pct_12h <- CalculatePercentage(to.plot = plot_data_12h, group_var = "genotype") +pct_24h <- CalculatePercentage(to.plot = plot_data_24h, group_var = "genotype") +pct_48h <- CalculatePercentage(to.plot = plot_data_48h, group_var = "genotype") +pct_slope <- CalculatePercentage(to.plot = plot_data_slope, group_var = "genotype") + +pct_12h; pct_24h; pct_48h; pct_slope +#> # A tibble: 2 × 5 +#> group percentage_on percentage_off cohens_d p_value +#> +#> 1 WT 41.5 58.5 -0.431 5.08e-25 +#> 2 Mutant 61.7 38.3 -0.431 5.08e-25 +#> # A tibble: 2 × 5 +#> group percentage_on percentage_off cohens_d p_value +#> +#> 1 WT 40.3 59.7 -0.379 2.48e-20 +#> 2 Mutant 58.7 41.3 -0.379 2.48e-20 +#> # A tibble: 2 × 5 +#> group percentage_on percentage_off cohens_d p_value +#> +#> 1 WT 46 54 -0.187 0.00000376 +#> 2 Mutant 53.9 46.1 -0.187 0.00000376 +#> # A tibble: 2 × 5 +#> group percentage_on percentage_off cohens_d p_value +#> +#> 1 WT 45.2 54.8 -0.149 0.000119 +#> 2 Mutant 52 48 -0.149 0.000119 +``` + +------------------------------------------------------------------------ + +## Visualization 1 — Density Plots + +``` r +p1 <- PlotPathway(plot_data_12h, "12hr Wnt", "genotype", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_12h, "WT", "Mutant"), size = 3.5, color = "black") + +p2 <- PlotPathway(plot_data_24h, "24hr Wnt", "genotype", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_24h, "WT", "Mutant"), size = 3.5, color = "black") + +p3 <- PlotPathway(plot_data_48h, "48hr Wnt", "genotype", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_48h, "WT", "Mutant"), size = 3.5, color = "black") + +p4 <- PlotPathway(plot_data_slope, "Wnt (slope)", "genotype", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_slope, "WT", "Mutant"), size = 3.5, color = "black") + +p1; p2; p3; p4 +``` + +![](examples_updated_files/figure-html/density-plots-1.png)![](examples_updated_files/figure-html/density-plots-2.png)![](examples_updated_files/figure-html/density-plots-3.png)![](examples_updated_files/figure-html/density-plots-4.png) + +------------------------------------------------------------------------ + +## Visualization 2 — Violin + Jitter Plot + +``` r +p5 <- ggplot(plot_data_12h, + aes(x = genotype, y = scale, fill = genotype, color = genotype)) + + geom_violin(alpha = 0.5, trim = FALSE) + + geom_jitter(width = 0.15, size = 0.6, alpha = 0.3) + + geom_hline(yintercept = 0, linetype = "dotted", color = "black", linewidth = 0.5) + + scale_fill_manual(values = c("#ae282c", "#2066a8")) + + scale_color_manual(values = c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_12h, "WT", "Mutant"), size = 3.5, color = "black") + + labs(title = "12hr WNT Pathway Activation", + x = NULL, y = "Relative Transduction State (z-score)") + + theme_classic() + + theme(legend.position = "none") +p5 +``` + +![](examples_updated_files/figure-html/violin-1.png) + +------------------------------------------------------------------------ + +## Visualization 3 — Waterfall Plot + +``` r +waterfall_data <- plot_data_12h %>% + group_by(genotype) %>% + arrange(scale, .by_group = TRUE) %>% + mutate(rank = row_number(), + state = ifelse(scale >= 0, "ON", "OFF")) %>% + ungroup() + +annotation_df <- pct_12h %>% + mutate( + label = paste0("Cohen's d = ", round(cohens_d, 3), "\n", + "p = ", formatC(p_value, format = "e", digits = 2), "\n", + "ON = ", percentage_on, "%\n", + "OFF = ", percentage_off, "%"), + genotype = group + ) + +p6 <- ggplot(waterfall_data, aes(x = rank, y = scale, fill = state)) + + geom_bar(stat = "identity", width = 1) + + facet_wrap(~ genotype, scales = "free_x") + + scale_fill_manual(values = c("ON" = "#ae282c", "OFF" = "#2066a8")) + + geom_hline(yintercept = 0, color = "black", linewidth = 0.4) + + geom_text(data = annotation_df, + aes(x = Inf, y = Inf, label = label), + hjust = 1.1, vjust = 1.5, size = 3, color = "black", + inherit.aes = FALSE) + + labs(title = "Waterfall Plot of Cell Activation", + x = "Cells (ranked by activation)", + y = "Relative Transduction State (z-score)", + fill = "State") + + theme_classic() + + theme(axis.text.x = element_blank(), axis.ticks.x = element_blank(), + strip.background = element_rect(fill = "grey90", color = NA)) +p6 +``` + +![](examples_updated_files/figure-html/waterfall-1.png) + +------------------------------------------------------------------------ + +## Customize Pathway Input + +``` r +# Customize the wnt pathway using coefficients defined by us +Wnt.molecules <- c('Lgr5','Rnf43','Lrp5', + 'Lrp6','Fzd6','Ctnnb1', + 'Gsk3b','Ccnd1','Axin2', + 'Myc','Lef1','Tcf7', + 'Tcf7l1','Tcf7l2','Tle1', + 'Apc','Csnk1a1','Dvl1') +Wnt.cof <- c(1,1,-1,-1,-1,-1, 1,1,1, 1,1,1, 1,1,1, -1,-1,-1) +Wnt_df <- data.frame( + Gene_Symbol = Wnt.molecules, + Coefficient = Wnt.cof) + +print(Wnt_df) +#> Gene_Symbol Coefficient +#> 1 Lgr5 1 +#> 2 Rnf43 1 +#> 3 Lrp5 -1 +#> 4 Lrp6 -1 +#> 5 Fzd6 -1 +#> 6 Ctnnb1 -1 +#> 7 Gsk3b 1 +#> 8 Ccnd1 1 +#> 9 Axin2 1 +#> 10 Myc 1 +#> 11 Lef1 1 +#> 12 Tcf7 1 +#> 13 Tcf7l1 1 +#> 14 Tcf7l2 1 +#> 15 Tle1 1 +#> 16 Apc -1 +#> 17 Csnk1a1 -1 +#> 18 Dvl1 -1 + +# Calculate score using customized pathway data +matrix_df <- DataPreProcess(synthetic_test_object_100, Wnt_df, Seurat.object = TRUE) +pathwaystat_df <- PathwayMaxMin(matrix_df, Wnt_df) +score_df <- ComputeCellData(matrix_df, pathwaystat_df) +plot_data_df <- PreparePlotData(synthetic_test_metadata, score_df, group = "genotype") +pct_df <- CalculatePercentage(to.plot = plot_data_df, group_var = "genotype") +PlotPathway(plot_data_df, "Customized Wnt", "genotype", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_df, "WT", "Mutant"), size = 3.5, color = "black") +``` + +![](examples_updated_files/figure-html/self-defined%20pathway-1.png) + +## Null Distribution — Random Gene Sets + +``` r +set.seed(123) + +real_n_genes <- nrow(matrix_12h) +real_cohens_d <- pct_12h$cohens_d[1] +n_reps <- 20 + +# Sparse size grid covering the relevant range, always including real n +size_grid <- sort(unique(c( + seq(5, 50, by = 5), + seq(60, 200, by = 20), + real_n_genes +))) + +all_genes_pool <- rownames( + GetAssayData(synthetic_test_object_100, assay = "RNA", layer = "data") +) +size_grid <- size_grid[size_grid <= length(all_genes_pool)] + +cohens_d_random <- data.frame() + +for (i in size_grid) { + for (rep in seq_len(n_reps)) { + sampled_genes <- sample(all_genes_pool, i) + fake_pathway <- data.frame( + Gene_Symbol = sampled_genes, + Coefficient = sample(c(-1L, 1L), i, replace = TRUE) + ) + expr_matrix <- DataPreProcess(synthetic_test_object_100, fake_pathway, + Seurat.object = TRUE) + pathwaystat_rand <- PathwayMaxMin(expr_matrix, fake_pathway) + score_rand <- ComputeCellData(expr_matrix, pathwaystat_rand) + plot_data_rand <- PreparePlotData(synthetic_test_metadata, score_rand, + group = "genotype") + outcome_rand <- CalculatePercentage(plot_data_rand, group_var = "genotype") + + cohens_d_random <- rbind(cohens_d_random, data.frame( + n_genes = i, + rep = rep, + cohens_d = outcome_rand$cohens_d[1] + )) + } +} + +cohens_d_summary_rand <- cohens_d_random %>% + group_by(n_genes) %>% + summarise(mean_d = mean(cohens_d, na.rm = TRUE), + sd_d = sd(cohens_d, na.rm = TRUE), + .groups = "drop") + +null_at_real_n <- cohens_d_random %>% filter(n_genes == real_n_genes) +emp_p <- mean(abs(null_at_real_n$cohens_d) >= abs(real_cohens_d), na.rm = TRUE) + +cat("Real pathway Cohen's d: ", round(real_cohens_d, 3), "\n") +#> Real pathway Cohen's d: -0.431 +cat("Null mean at same n genes: ", round(mean(null_at_real_n$cohens_d, na.rm = TRUE), 3), "\n") +#> Null mean at same n genes: -0.082 +cat("Null SD at same n genes: ", round(sd(null_at_real_n$cohens_d, na.rm = TRUE), 3), "\n") +#> Null SD at same n genes: 0.328 +cat("Empirical p-value: ", round(emp_p, 3), "\n") +#> Empirical p-value: 0.25 + +p7 <- ggplot() + + geom_hline(yintercept = 0, linetype = "solid", color = "#888780", linewidth = 0.4) + + geom_hline(yintercept = 0.8, linetype = "dashed", color = "#E24B4A", linewidth = 0.5) + + geom_hline(yintercept = -0.8, linetype = "dashed", color = "#E24B4A", linewidth = 0.5) + + geom_hline(yintercept = 0.5, linetype = "dashed", color = "#EF9F27", linewidth = 0.5) + + geom_hline(yintercept = -0.5, linetype = "dashed", color = "#EF9F27", linewidth = 0.5) + + geom_point(data = cohens_d_random, + aes(x = n_genes, y = cohens_d), + color = "#534AB7", alpha = 0.25, size = 1.2) + + geom_ribbon(data = cohens_d_summary_rand, + aes(x = n_genes, ymin = mean_d - sd_d, ymax = mean_d + sd_d), + fill = "#534AB7", alpha = 0.15) + + geom_line(data = cohens_d_summary_rand, + aes(x = n_genes, y = mean_d), + color = "#534AB7", linewidth = 0.9) + + geom_point(aes(x = real_n_genes, y = real_cohens_d), + color = "#E24B4A", size = 3, shape = 18) + + geom_vline(xintercept = real_n_genes, color = "#E24B4A", + linetype = "dashed", linewidth = 0.5) + + annotate("text", x = real_n_genes, y = Inf, + label = paste0("Real pathway\nn = ", real_n_genes, + "\nd = ", round(real_cohens_d, 3), + "\nemp. p = ", round(emp_p, 3)), + hjust = -0.1, vjust = 1.5, size = 3, color = "#E24B4A") + + annotate("text", x = max(cohens_d_summary_rand$n_genes), y = 0.82, + label = "large (+0.8)", hjust = 1, size = 3, color = "#E24B4A") + + annotate("text", x = max(cohens_d_summary_rand$n_genes), y = -0.82, + label = "large (-0.8)", hjust = 1, size = 3, color = "#E24B4A") + + annotate("text", x = max(cohens_d_summary_rand$n_genes), y = 0.52, + label = "medium (+0.5)", hjust = 1, size = 3, color = "#EF9F27") + + annotate("text", x = max(cohens_d_summary_rand$n_genes), y = -0.52, + label = "medium (-0.5)", hjust = 1, size = 3, color = "#EF9F27") + + labs(title = "Null Distribution — Cohen's d by Gene Set Size", + x = "Number of genes", y = "Cohen's d") + + theme_minimal() +p7 +``` + +![](examples_updated_files/figure-html/null-random-1.png) + +------------------------------------------------------------------------ + +## Null Distribution — Within Pathway Gene Pool + +``` r +set.seed(123) + +all_genes <- rownames(matrix_12h) +n_genes <- length(all_genes) +n_reps <- 10 + +cohens_d_pathway <- data.frame() + +for (i in 2:n_genes) { + for (rep in seq_len(n_reps)) { + sampled_genes <- sample(all_genes, i) + expr_matrix <- matrix_12h[sampled_genes, , drop = FALSE] + pathwaystat_rand <- PathwayMaxMin(expr_matrix, Wnt_12h) + score_rand <- ComputeCellData(expr_matrix, pathwaystat_rand) + plot_data_rand <- PreparePlotData(synthetic_test_metadata, score_rand, + group = "genotype") + outcome_rand <- CalculatePercentage(to.plot = plot_data_rand, + group_var = "genotype") + cohens_d_pathway <- rbind(cohens_d_pathway, data.frame( + n_genes = i, + rep = rep, + cohens_d = outcome_rand$cohens_d[1] + )) + } +} + +cohens_d_summary_pw <- cohens_d_pathway %>% + group_by(n_genes) %>% + summarise(mean_d = mean(cohens_d, na.rm = TRUE), + sd_d = sd(cohens_d, na.rm = TRUE), + .groups = "drop") + +null_at_real_n_pw <- cohens_d_pathway %>% filter(n_genes == real_n_genes) +emp_p_pw <- mean(abs(null_at_real_n_pw$cohens_d) >= abs(real_cohens_d), na.rm = TRUE) + +cat("Real pathway Cohen's d: ", round(real_cohens_d, 3), "\n") +#> Real pathway Cohen's d: -0.431 +cat("Null mean at same n genes: ", round(mean(null_at_real_n_pw$cohens_d, na.rm = TRUE), 3), "\n") +#> Null mean at same n genes: -0.431 +cat("Null SD at same n genes: ", round(sd(null_at_real_n_pw$cohens_d, na.rm = TRUE), 3), "\n") +#> Null SD at same n genes: 0 +cat("Empirical p-value: ", round(emp_p_pw, 3), "\n") +#> Empirical p-value: 0.6 + +p_null <- ggplot() + + geom_hline(yintercept = 0, linetype = "solid", color = "#888780", linewidth = 0.4) + + geom_hline(yintercept = 0.8, linetype = "dashed", color = "#E24B4A", linewidth = 0.5) + + geom_hline(yintercept = -0.8, linetype = "dashed", color = "#E24B4A", linewidth = 0.5) + + geom_hline(yintercept = 0.5, linetype = "dashed", color = "#EF9F27", linewidth = 0.5) + + geom_hline(yintercept = -0.5, linetype = "dashed", color = "#EF9F27", linewidth = 0.5) + + geom_point(data = cohens_d_pathway, + aes(x = n_genes, y = cohens_d), + color = "#534AB7", alpha = 0.25, size = 1.2) + + geom_ribbon(data = cohens_d_summary_pw, + aes(x = n_genes, ymin = mean_d - sd_d, ymax = mean_d + sd_d), + fill = "#534AB7", alpha = 0.15) + + geom_line(data = cohens_d_summary_pw, + aes(x = n_genes, y = mean_d), + color = "#534AB7", linewidth = 0.9) + + geom_point(aes(x = real_n_genes, y = real_cohens_d), + color = "#E24B4A", size = 3, shape = 18) + + geom_vline(xintercept = real_n_genes, color = "#E24B4A", + linetype = "dashed", linewidth = 0.5) + + annotate("text", x = real_n_genes, y = Inf, + label = paste0("Real pathway\nn = ", real_n_genes, + "\nd = ", round(real_cohens_d, 3)), + hjust = -0.1, vjust = 1.5, size = 3, color = "#E24B4A") + + labs(title = "Null Distribution — Cohen's d by Gene Set Size (10 reps each)", + x = "Number of genes", y = "Cohen's d") + + theme_minimal() +p_null +``` + +![](examples_updated_files/figure-html/null-pathway-genes-1.png) + +------------------------------------------------------------------------ + +## Sensitivity Analysis 1 — Effect of Input Matrix Type + +``` r +data("synthetic_test_matrix_100") + +matrix_raw <- synthetic_test_matrix_100 +lib_size <- colSums(synthetic_test_matrix_100) +matrix_lognorm <- log1p(sweep(synthetic_test_matrix_100, 2, lib_size, "/") * 1e4) +matrix_norm <- sweep(synthetic_test_matrix_100, 2, lib_size, "/") * 1e4 +gene_var <- apply(matrix_lognorm, 1, var) +hvg_genes <- names(sort(gene_var, decreasing = TRUE))[ + 1:ceiling(nrow(matrix_lognorm) * 0.5)] +matrix_hvg <- matrix_lognorm[hvg_genes, ] + +run_pipeline <- function(expr_mat, pathwaydata, metadata, group, + scale.data = TRUE) { + mat <- DataPreProcess(expr_mat, pathwaydata, scale.data = scale.data) + pstat <- PathwayMaxMin(mat, pathwaydata) + score <- ComputeCellData(mat, pstat) + plotdata <- PreparePlotData(metadata, score, group = group) + outcome <- CalculatePercentage(plotdata, group_var = group) + list(score = score, plotdata = plotdata, outcome = outcome) +} + +result_raw <- run_pipeline(matrix_raw, Wnt_12h, synthetic_test_metadata, "genotype") +result_lognorm <- run_pipeline(matrix_lognorm, Wnt_12h, synthetic_test_metadata, "genotype") +result_norm <- run_pipeline(matrix_norm, Wnt_12h, synthetic_test_metadata, "genotype") +result_hvg <- run_pipeline(matrix_hvg, Wnt_12h, synthetic_test_metadata, "genotype") +result_raw_noscale <- run_pipeline(matrix_raw, Wnt_12h, synthetic_test_metadata, "genotype", scale.data = FALSE) +result_lognorm_noscale <- run_pipeline(matrix_lognorm, Wnt_12h, synthetic_test_metadata, "genotype", scale.data = FALSE) +result_norm_noscale <- run_pipeline(matrix_norm, Wnt_12h, synthetic_test_metadata, "genotype", scale.data = FALSE) +result_hvg_noscale <- run_pipeline(matrix_hvg, Wnt_12h, synthetic_test_metadata, "genotype", scale.data = FALSE) + +input_labels <- c("Raw", "Log-norm", "Norm", "HVG", + "Raw (noscale)", "Log-norm (noscale)", + "Norm (noscale)", "HVG (noscale)") +results_list <- list(result_raw, result_lognorm, result_norm, result_hvg, + result_raw_noscale, result_lognorm_noscale, + result_norm_noscale, result_hvg_noscale) + +cohens_d_input <- data.frame( + input_type = input_labels, + cohens_d = sapply(results_list, function(r) r$outcome$cohens_d[1]), + p_value = sapply(results_list, function(r) r$outcome$p_value[1]) +) +print(cohens_d_input) +#> input_type cohens_d p_value +#> 1 Raw -0.80105995 1.120664e-65 +#> 2 Log-norm -0.43058889 5.083976e-25 +#> 3 Norm -0.38149058 2.648944e-18 +#> 4 HVG -0.02940827 5.222419e-01 +#> 5 Raw (noscale) -0.99496812 9.932645e-94 +#> 6 Log-norm (noscale) -0.22648846 5.743074e-07 +#> 7 Norm (noscale) -0.42743835 2.281451e-22 +#> 8 HVG (noscale) -0.02943217 5.259599e-01 + +score_df_sens <- as.data.frame( + setNames(lapply(results_list, function(r) as.numeric(r$score)), input_labels), + row.names = names(results_list[[1]]$score) +) + +score_cor <- cor(score_df_sens, method = "spearman", use = "pairwise.complete.obs") +p12 <- pheatmap(score_cor, + color = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100), + breaks = seq(-1, 1, length.out = 101), + display_numbers = TRUE, number_format = "%.2f", + fontsize_number = 9, + main = "Score Correlation Across Input Matrix Types — Spearman") + +named_results <- list(Raw = result_raw, `Log-norm` = result_lognorm, + Norm = result_norm, HVG = result_hvg) +density_plots <- lapply( + names(named_results), + function(nm) PlotPathway(named_results[[nm]]$plotdata, + paste("Wnt 12h —", nm), "genotype", + c("#ae282c", "#2066a8")) +) +p13 <- wrap_plots(density_plots, ncol = 2) + + plot_annotation(title = "Pathway Activation by Input Matrix Type") + +p12; p13 +``` + +![](examples_updated_files/figure-html/sensitivity-input-1.png)![](examples_updated_files/figure-html/sensitivity-input-2.png) + +------------------------------------------------------------------------ + +## Correlation with Technical Confounders + +``` r +normalized_mat <- GetAssayData(synthetic_test_object_100, assay = "RNA", layer = "data") +common_genes <- intersect(rownames(normalized_mat), Wnt_12h$Gene_Symbol) +gene_matrix <- as.matrix(normalized_mat[common_genes, ]) + +mean_expr <- colMeans(gene_matrix, na.rm = TRUE) +zscore_mean_per_cell <- colMeans(t(scale(t(gene_matrix))), na.rm = TRUE) +seurat_meta <- synthetic_test_object_100@meta.data + +make_scatter <- function(df, x_col, x_label) { + r <- cor(df$embed_score, df[[x_col]], method = "spearman", use = "complete.obs") + ggplot(df, aes(x = .data[[x_col]], y = embed_score)) + + geom_point(alpha = 0.4, size = 1.2, color = "#534AB7") + + geom_smooth(method = "lm", color = "#E24B4A", linewidth = 0.8, se = TRUE) + + labs(title = sprintf("%s (rho = %.3f)", x_label, r), + x = x_label, y = "PathwayEmbed score") + + theme_minimal() +} + +confounder_df_norm <- data.frame( + cell = names(score_12h), + embed_score = as.numeric(score_12h), + mean_expr = mean_expr[names(score_12h)], + zscore_expr = zscore_mean_per_cell[names(score_12h)], + nCount_RNA = seurat_meta[names(score_12h), "nCount_RNA"], + nFeature_RNA = seurat_meta[names(score_12h), "nFeature_RNA"] +) + +for (cov in c("mean_expr", "zscore_expr", "nCount_RNA", "nFeature_RNA")) { + r <- cor(confounder_df_norm$embed_score, confounder_df_norm[[cov]], + method = "spearman", use = "complete.obs") + cat(sprintf("Spearman vs %-20s : %.3f\n", cov, r)) +} +#> Spearman vs mean_expr : 0.163 +#> Spearman vs zscore_expr : 0.280 +#> Spearman vs nCount_RNA : 0.089 +#> Spearman vs nFeature_RNA : -0.145 + +p_nor <- (make_scatter(confounder_df_norm, "mean_expr", "Mean expression") + + make_scatter(confounder_df_norm, "zscore_expr", "Z-score mean")) / + (make_scatter(confounder_df_norm, "nCount_RNA", "nCount_RNA") + + make_scatter(confounder_df_norm, "nFeature_RNA", "nFeature_RNA")) +p_nor +``` + +![](examples_updated_files/figure-html/confounders-normalized-1.png) + +## Correlation with Technical Confounders — Raw Counts + +``` r +common_genes_raw <- intersect(rownames(matrix_raw), Wnt_12h$Gene_Symbol) +gene_matrix_raw <- as.matrix(matrix_raw[common_genes_raw, ]) + +mean_expr_raw <- colMeans(gene_matrix_raw, na.rm = TRUE) +zscore_mean_per_cell_raw <- colMeans(t(scale(t(gene_matrix_raw))), na.rm = TRUE) +score_raw_12h <- result_raw$score + +confounder_df_raw <- data.frame( + cell = names(score_raw_12h), + embed_score = as.numeric(score_raw_12h), + mean_expr = mean_expr_raw[names(score_raw_12h)], + zscore_expr = zscore_mean_per_cell_raw[names(score_raw_12h)], + nCount_RNA = seurat_meta[names(score_raw_12h), "nCount_RNA"], + nFeature_RNA = seurat_meta[names(score_raw_12h), "nFeature_RNA"] +) + +for (cov in c("mean_expr", "zscore_expr", "nCount_RNA", "nFeature_RNA")) { + r <- cor(confounder_df_raw$embed_score, confounder_df_raw[[cov]], + method = "spearman", use = "complete.obs") + cat(sprintf("Spearman vs %-20s : %.3f\n", cov, r)) +} +#> Spearman vs mean_expr : 0.411 +#> Spearman vs zscore_expr : 0.406 +#> Spearman vs nCount_RNA : 0.335 +#> Spearman vs nFeature_RNA : -0.024 + +p_raw <- (make_scatter(confounder_df_raw, "mean_expr", "Mean expression") + + make_scatter(confounder_df_raw, "zscore_expr", "Z-score mean")) / + (make_scatter(confounder_df_raw, "nCount_RNA", "nCount_RNA") + + make_scatter(confounder_df_raw, "nFeature_RNA", "nFeature_RNA")) +p_raw +``` + +![](examples_updated_files/figure-html/confounders-raw-1.png) + +------------------------------------------------------------------------ + +## Benchmark Against PROGENy and AddModuleScore + +``` r +normalized_mat_dense <- as.matrix(normalized_mat) + +progeny_scores <- progeny( + normalized_mat_dense, + scale = TRUE, + organism = "Mouse", + top = 100, + perm = 1 +) +progeny_wnt <- setNames(as.numeric(progeny_scores[, "WNT"]), + rownames(progeny_scores)) + +wnt_features <- rownames(matrix_24h) +synthetic_test_object_100 <- AddModuleScore( + object = synthetic_test_object_100, + features = list(wnt_features), + name = "WNT_ModuleScore", + ctrl = 5, + nbin = 10 +) +module_score <- setNames( + synthetic_test_object_100@meta.data$WNT_ModuleScore1, + rownames(synthetic_test_object_100@meta.data) +) + +cells <- names(score_24h) +benchmark_df <- data.frame( + PathwayEmbed = as.numeric(score_24h), + PROGENy = as.numeric(progeny_wnt[cells]), + AddModuleScore = as.numeric(module_score[cells]), + mean_expr = as.numeric(mean_expr[cells]), + zscore_expr = as.numeric(zscore_mean_per_cell[cells]), + row.names = cells +) + +benchmark_cor <- cor(benchmark_df, method = "spearman", + use = "pairwise.complete.obs") +print(round(benchmark_cor, 3)) +#> PathwayEmbed PROGENy AddModuleScore mean_expr zscore_expr +#> PathwayEmbed 1.000 0.042 -0.049 -0.078 -0.082 +#> PROGENy 0.042 1.000 0.028 0.046 0.137 +#> AddModuleScore -0.049 0.028 1.000 0.625 0.440 +#> mean_expr -0.078 0.046 0.625 1.000 0.807 +#> zscore_expr -0.082 0.137 0.440 0.807 1.000 + +p9 <- pheatmap( + benchmark_cor, + color = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100), + breaks = seq(-1, 1, length.out = 101), + display_numbers = TRUE, number_format = "%.2f", + fontsize_number = 9, + main = "Method Benchmark — Spearman Correlation" +) +p9 +``` + +![](examples_updated_files/figure-html/benchmark-1.png) + +``` r + +genotype_label <- ifelse( + synthetic_test_metadata[cells, "genotype"] == "Mutant", 1L, 0L +) + +compute_auroc <- function(scores, labels) { + r <- roc(labels, scores, quiet = TRUE) + auc_val <- as.numeric(auc(r)) + if (auc_val < 0.5) auc_val <- 1 - auc_val + auc_val +} + +auroc_results <- data.frame( + Method = colnames(benchmark_df), + AUROC = sapply(benchmark_df, compute_auroc, labels = genotype_label) +) +auroc_results <- auroc_results[order(-auroc_results$AUROC), ] +print(auroc_results) +#> Method AUROC +#> zscore_expr zscore_expr 0.755310 +#> PROGENy PROGENy 0.656320 +#> mean_expr mean_expr 0.626260 +#> PathwayEmbed PathwayEmbed 0.619310 +#> AddModuleScore AddModuleScore 0.526651 + +compute_cohens_d_method <- function(scores, metadata, group_col) { + scores <- setNames(as.numeric(scores), names(scores)) + pd <- PreparePlotData(metadata, scores, group = group_col) + pct <- CalculatePercentage(pd, group_var = group_col) + abs(pct$cohens_d[1]) +} + +cohens_d_results <- data.frame( + Method = colnames(benchmark_df), + Cohens_d = sapply( + colnames(benchmark_df), + function(m) compute_cohens_d_method( + setNames(benchmark_df[[m]], rownames(benchmark_df)), + synthetic_test_metadata, "genotype" + ) + ) +) +cohens_d_results <- cohens_d_results[order(-cohens_d_results$Cohens_d), ] +print(cohens_d_results) +#> Method Cohens_d +#> zscore_expr zscore_expr 0.94892009 +#> mean_expr mean_expr 0.44722384 +#> PathwayEmbed PathwayEmbed 0.37911019 +#> AddModuleScore AddModuleScore 0.07942301 +#> PROGENy PROGENy 0.07087977 + +method_colors <- c( + "PathwayEmbed" = "#534AB7", + "PROGENy" = "#E24B4A", + "AddModuleScore" = "#EF9F27", + "mean_expr" = "#888780", + "zscore_expr" = "#B4B2A9" +) + +p10 <- ggplot(auroc_results, aes(x = reorder(Method, AUROC), y = AUROC, fill = Method)) + + geom_bar(stat = "identity", width = 0.6) + + geom_hline(yintercept = 0.5, linetype = "dashed", color = "black") + + coord_flip() + + scale_fill_manual(values = method_colors) + + labs(title = "AUROC: Mutant vs WT separation by scoring method", + x = NULL, y = "AUROC") + + ylim(0, 1) + + theme_classic() + + theme(legend.position = "none", + axis.text.y = element_text(size = 12), + axis.text.x = element_text(size = 11), + axis.title.x = element_text(size = 12), + plot.title = element_text(size = 13, face = "bold")) + +p11 <- ggplot(cohens_d_results, aes(x = reorder(Method, Cohens_d), y = Cohens_d, fill = Method)) + + geom_bar(stat = "identity", width = 0.6) + + geom_hline(yintercept = 0.5, linetype = "dashed", color = "black") + + coord_flip() + + scale_fill_manual(values = method_colors) + + labs(title = "Cohen's d: Mutant vs WT separation by scoring method", + x = NULL, y = "Cohen's d") + + ylim(0, 1) + + theme_classic() + + theme(legend.position = "none", + axis.text.y = element_text(size = 12), + axis.text.x = element_text(size = 11), + axis.title.x = element_text(size = 12), + plot.title = element_text(size = 13, face = "bold")) + +p10; p11 +``` + +![](examples_updated_files/figure-html/benchmark-2.png)![](examples_updated_files/figure-html/benchmark-3.png) + +------------------------------------------------------------------------ + +## Sensitivity Analysis 2 — Effect of Distance Method + +``` r +score_manhattan <- ComputeCellData(matrix_24h, pathwaystat_24h, + distance.method = "manhattan") +score_euclidean <- ComputeCellData(matrix_24h, pathwaystat_24h, + distance.method = "euclidean") + +cor_dist <- cor(score_manhattan, score_euclidean, method = "spearman") +cat("Spearman correlation (manhattan vs euclidean):", round(cor_dist, 3), "\n") +#> Spearman correlation (manhattan vs euclidean): 0.942 + +plotdata_manhattan <- PreparePlotData(synthetic_test_metadata, score_manhattan, + group = "genotype") +plotdata_euclidean <- PreparePlotData(synthetic_test_metadata, score_euclidean, + group = "genotype") + +pct_manhattan <- CalculatePercentage(plotdata_manhattan, group_var = "genotype") +pct_euclidean <- CalculatePercentage(plotdata_euclidean, group_var = "genotype") + +distance_comparison <- data.frame( + method = c("Manhattan", "Euclidean"), + cohens_d = c(pct_manhattan$cohens_d[1], pct_euclidean$cohens_d[1]), + p_value = c(pct_manhattan$p_value[1], pct_euclidean$p_value[1]), + pct_on_wt = c(pct_manhattan$percentage_on[pct_manhattan$group == "WT"], + pct_euclidean$percentage_on[pct_euclidean$group == "WT"]), + pct_on_mut = c(pct_manhattan$percentage_on[pct_manhattan$group == "Mutant"], + pct_euclidean$percentage_on[pct_euclidean$group == "Mutant"]) +) +print(distance_comparison) +#> method cohens_d p_value pct_on_wt pct_on_mut +#> 1 Manhattan -0.3791102 2.479654e-20 40.3 58.7 +#> 2 Euclidean -0.4669349 3.968028e-32 38.5 63.9 + +dist_df <- data.frame(manhattan = as.numeric(score_manhattan), + euclidean = as.numeric(score_euclidean), + row.names = names(score_manhattan)) + +p_scatter <- ggplot(dist_df, aes(x = manhattan, y = euclidean)) + + geom_point(alpha = 0.4, size = 1.2, color = "#534AB7") + + geom_smooth(method = "lm", color = "#E24B4A", linewidth = 0.8, se = TRUE) + + labs(title = sprintf("Manhattan vs Euclidean (rho = %.3f)", cor_dist), + x = "Manhattan score", y = "Euclidean score") + + theme_minimal() + +p_man_plot <- PlotPathway(plotdata_manhattan, "Wnt 24h — Manhattan", + "genotype", c("#ae282c", "#2066a8")) +p_euc_plot <- PlotPathway(plotdata_euclidean, "Wnt 24h — Euclidean", + "genotype", c("#ae282c", "#2066a8")) + +p_scatter / (p_man_plot + p_euc_plot) + + plot_annotation(title = "Sensitivity to Distance Method") +``` + +![](examples_updated_files/figure-html/sensitivity-distance-1.png) diff --git a/docs/articles/examples_updated_files/figure-html/benchmark-1.png b/docs/articles/examples_updated_files/figure-html/benchmark-1.png new file mode 100644 index 0000000..e49bf8f Binary files /dev/null and b/docs/articles/examples_updated_files/figure-html/benchmark-1.png differ diff --git a/docs/articles/examples_updated_files/figure-html/benchmark-2.png b/docs/articles/examples_updated_files/figure-html/benchmark-2.png new file mode 100644 index 0000000..a9cdfb4 Binary files /dev/null and b/docs/articles/examples_updated_files/figure-html/benchmark-2.png differ diff --git a/docs/articles/examples_updated_files/figure-html/benchmark-3.png b/docs/articles/examples_updated_files/figure-html/benchmark-3.png new file mode 100644 index 0000000..7b6833d Binary files /dev/null and b/docs/articles/examples_updated_files/figure-html/benchmark-3.png differ diff --git a/docs/articles/examples_updated_files/figure-html/confounders-normalized-1.png b/docs/articles/examples_updated_files/figure-html/confounders-normalized-1.png new file mode 100644 index 0000000..8bf0c06 Binary files /dev/null and b/docs/articles/examples_updated_files/figure-html/confounders-normalized-1.png differ diff --git a/docs/articles/examples_updated_files/figure-html/confounders-raw-1.png b/docs/articles/examples_updated_files/figure-html/confounders-raw-1.png new file mode 100644 index 0000000..27ab103 Binary files /dev/null and b/docs/articles/examples_updated_files/figure-html/confounders-raw-1.png differ diff --git a/docs/articles/examples_updated_files/figure-html/density-plots-1.png b/docs/articles/examples_updated_files/figure-html/density-plots-1.png new file mode 100644 index 0000000..adb9c97 Binary files /dev/null and b/docs/articles/examples_updated_files/figure-html/density-plots-1.png differ diff --git a/docs/articles/examples_updated_files/figure-html/density-plots-2.png b/docs/articles/examples_updated_files/figure-html/density-plots-2.png new file mode 100644 index 0000000..4d6f206 Binary files /dev/null and b/docs/articles/examples_updated_files/figure-html/density-plots-2.png differ diff --git a/docs/articles/examples_updated_files/figure-html/density-plots-3.png b/docs/articles/examples_updated_files/figure-html/density-plots-3.png new file mode 100644 index 0000000..e8a0ba2 Binary files /dev/null and b/docs/articles/examples_updated_files/figure-html/density-plots-3.png differ diff --git a/docs/articles/examples_updated_files/figure-html/density-plots-4.png b/docs/articles/examples_updated_files/figure-html/density-plots-4.png new file mode 100644 index 0000000..8bbdaec Binary files /dev/null and b/docs/articles/examples_updated_files/figure-html/density-plots-4.png differ diff --git a/docs/articles/examples_updated_files/figure-html/null-pathway-genes-1.png b/docs/articles/examples_updated_files/figure-html/null-pathway-genes-1.png new file mode 100644 index 0000000..fa57f49 Binary files /dev/null and b/docs/articles/examples_updated_files/figure-html/null-pathway-genes-1.png differ diff --git a/docs/articles/examples_updated_files/figure-html/null-random-1.png b/docs/articles/examples_updated_files/figure-html/null-random-1.png new file mode 100644 index 0000000..1f7d07d Binary files /dev/null and b/docs/articles/examples_updated_files/figure-html/null-random-1.png differ diff --git a/docs/articles/examples_updated_files/figure-html/self-defined pathway-1.png b/docs/articles/examples_updated_files/figure-html/self-defined pathway-1.png new file mode 100644 index 0000000..22effd5 Binary files /dev/null and b/docs/articles/examples_updated_files/figure-html/self-defined pathway-1.png differ diff --git a/docs/articles/examples_updated_files/figure-html/sensitivity-distance-1.png b/docs/articles/examples_updated_files/figure-html/sensitivity-distance-1.png new file mode 100644 index 0000000..83fcb2f Binary files /dev/null and b/docs/articles/examples_updated_files/figure-html/sensitivity-distance-1.png differ diff --git a/docs/articles/examples_updated_files/figure-html/sensitivity-input-1.png b/docs/articles/examples_updated_files/figure-html/sensitivity-input-1.png new file mode 100644 index 0000000..a1cb78e Binary files /dev/null and b/docs/articles/examples_updated_files/figure-html/sensitivity-input-1.png differ diff --git a/docs/articles/examples_updated_files/figure-html/sensitivity-input-2.png b/docs/articles/examples_updated_files/figure-html/sensitivity-input-2.png new file mode 100644 index 0000000..b894d43 Binary files /dev/null and b/docs/articles/examples_updated_files/figure-html/sensitivity-input-2.png differ diff --git a/docs/articles/examples_updated_files/figure-html/violin-1.png b/docs/articles/examples_updated_files/figure-html/violin-1.png new file mode 100644 index 0000000..05f1585 Binary files /dev/null and b/docs/articles/examples_updated_files/figure-html/violin-1.png differ diff --git a/docs/articles/examples_updated_files/figure-html/waterfall-1.png b/docs/articles/examples_updated_files/figure-html/waterfall-1.png new file mode 100644 index 0000000..bbb902d Binary files /dev/null and b/docs/articles/examples_updated_files/figure-html/waterfall-1.png differ diff --git a/docs/articles/index.html b/docs/articles/index.html index 8b234d8..9e1e5b8 100644 --- a/docs/articles/index.html +++ b/docs/articles/index.html @@ -1,83 +1,69 @@ -Articles • PathwayEmbed - - -
-
+
+
+
+
-
- +
diff --git a/docs/articles/index.md b/docs/articles/index.md new file mode 100644 index 0000000..1c954b0 --- /dev/null +++ b/docs/articles/index.md @@ -0,0 +1,13 @@ +# Articles + +### All vignettes + +- [Beta-Catenin Knockout Analysis with + PathwayEmbed](https://raredonlab.github.io/PathwayEmbed/articles/beta_catenin_ko_updated.md): +- [Toy + Set](https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.md): +- [Notch_Analysis](https://raredonlab.github.io/PathwayEmbed/articles/Notch_Analysis_updated.md): +- [Spatial Pathway + Visualization](https://raredonlab.github.io/PathwayEmbed/articles/spatial_pathway_updated.md): +- [TGF-β Pathway Database + Construction](https://raredonlab.github.io/PathwayEmbed/articles/TGFB_database_construction.md): diff --git a/docs/articles/spatial_pathway.html b/docs/articles/spatial_pathway.html deleted file mode 100644 index 821784c..0000000 --- a/docs/articles/spatial_pathway.html +++ /dev/null @@ -1,314 +0,0 @@ - - - - - - - -Spatial Pathway Visualization • PathwayEmbed - - - - - - - - - - - -
-
- - - - -
-
- - - - -
-knitr::opts_chunk$set(echo = TRUE)
-
-# load library
-library(PathwayEmbed)
-library(Seurat)
-
## Loading required package: SeuratObject
-
## Loading required package: sp
-
## 'SeuratObject' was built under R 4.4.1 but the current version is
-## 4.4.2; it is recomended that you reinstall 'SeuratObject' as the ABI
-## for R may have changed
-
## 
-## Attaching package: 'SeuratObject'
-
## The following objects are masked from 'package:base':
-## 
-##     intersect, t
- -
## Loading required package: viridisLite
- -
-

Spatial data load and process -

-

The files can be downloaded from figshare via below link:

-

Huang, Yaqing (2025). dat3.with.niches.norm.Robj. figshare. Dataset. -https://doi.org/10.6084/m9.figshare.29649995.v1

-

Huang, Yaqing (2025). dat4.with.niches.norm.Robj. figshare. Dataset. -https://doi.org/10.6084/m9.figshare.29649989.v1

-

Huang, Yaqing (2025). dat1.with.niches.norm.Robj. figshare. Dataset. -https://doi.org/10.6084/m9.figshare.29649992.v1

-

Huang, Yaqing (2025). dat2.with.niches.norm.Robj. figshare. Dataset. -https://doi.org/10.6084/m9.figshare.29649986.v1

-
-# load data
-load("dat1.with.niches.norm.Robj")
-load("dat2.with.niches.norm.Robj")
-load("dat3.with.niches.norm.Robj")
-load("dat4.with.niches.norm.Robj")
-
-# Merge together
-merged_spatial <- merge(
-  dat1, y = c(dat2, dat3, dat4))
-
-# Set Default Assay to be "RNA"
-DefaultAssay(merged_spatial) <- "RNA"
-
-
-

Compute pathway score -

-

Compute score for Wnt, Notch, Hippo, Tgfb, and HIF-1a pathways for -the merged subject using ‘ComputeCellData’ in PathwayEmbed

-
-# Compute the score for each pathway
-Wnt_mds <- ComputeCellData(merged_spatial, "Wnt", "manhattan", batch.size = 1000)
-Notch_mds <- ComputeCellData(merged_spatial, "Notch", "manhattan", batch.size = 1000)
-Hippo_mds <- ComputeCellData(merged_spatial, "Hippo", "manhattan", batch.size = 1000)
-Tgfb_mds <- ComputeCellData(merged_spatial, "Tgfb", "manhattan", batch.size = 1000)
-HIF1a_mds <- ComputeCellData(merged_spatial, "HIF-1a", "manhattan", batch.size = 1000)
-
-# Process the mds
-Wnt_to.plot <- PreparePlotData(merged_spatial, Wnt_mds, "timepoint")
-Notch_to.plot <- PreparePlotData(merged_spatial, Notch_mds, "timepoint")
-Hippo_to.plot <- PreparePlotData(merged_spatial, Hippo_mds, "timepoint")
-Tgfb_to.plot <- PreparePlotData(merged_spatial, Tgfb_mds, "timepoint")
-HIF1a_to.plot <- PreparePlotData(merged_spatial, HIF1a_mds, "timepoint")
-
-# Combine to list
-pathway_list <- list(
-  Wnt = Wnt_to.plot,
-  Notch = Notch_to.plot,
-  Hippo = Hippo_to.plot,
-  Tgfb = Tgfb_to.plot,
-  HIF1a = HIF1a_to.plot
-)
-
-
-

Preparation for groups -

-
-# Color set-up
-magma_colors <- c("#000004FF", "#721F81FF", "#F1605DFF", "#5A90E6")
-
-# Desired timepoint order
-ordered_timepoints <- c("E9.5", "E10.5", "E11.5", "E12.5")
-
-# Reorder timepoint levels
-for (name in names(pathway_list)) {
-  pathway_list[[name]]$timepoint <- factor(pathway_list[[name]]$timepoint, levels = ordered_timepoints)
-}
-
-
-

Plot across different timepoints -

-
-# Loop through each pathway and generate/save the plot
-for (i in seq_along(pathway_list)) {
-  # Generate the plot
-  p <- PlotPathway(pathway_list[[i]], names(pathway_list)[i], "timepoint", magma_colors) +
-    facet_wrap(~timepoint, ncol = 1)
-  print(p)
-}
-

-
-
-

Merge score with original metadata -

-
-# Step 1: Create named score vectors for each pathway
-score_list <- lapply(pathway_list, function(df) {
-  s <- df$scale
-  names(s) <- rownames(df)
-  return(s)
-})
-
-# Step 2: Add each pathway score to dat1–dat4
-for (i in 1:4) {
-  dat <- get(paste0("dat", i))  # get dat1, dat2, ...
-  
-  for (pathway_name in names(score_list)) {
-    score_vec <- score_list[[pathway_name]]
-    dat[[paste0(pathway_name, "_score")]] <- score_vec[colnames(dat)]
-  }
-  
-  assign(paste0("dat", i), dat)  # assign back to dat1, dat2, etc.
-}
-
-
-# List of Seurat objects
-dat_list <- list(dat1, dat2, dat3, dat4)
-names(dat_list) <- paste0("dat", 1:4)
-
-# List of pathways
-pathways <- names(pathway_list)  # e.g., "Wnt", "Notch", etc.
-
-
-

Extract the coordinates -

-
-# Function to extract 
-extract_pathway_df <- function(seu, pathway, sample_name = "sample") {
-  coords <- as.data.frame(Embeddings(seu[["spatial"]]))
-  colnames(coords) <- c("x", "y")
-  coords$score <- seu[[paste0(pathway, "_score")]][rownames(coords), 1]
-  coords$sample <- sample_name
-  return(coords)
-}
-
-# Set list to save the coordinates
-combined_df_lists <- list()
-
-# For loop for all pathways 
-for (pathway in pathways) {
-  pathway_df_list <- mapply(
-    FUN = extract_pathway_df,
-    seu = dat_list,
-    sample_name = names(dat_list),
-    MoreArgs = list(pathway = pathway),
-    SIMPLIFY = FALSE
-  )
-  
-  combined_df <- do.call(rbind, pathway_df_list)
-  combined_df_lists[[pathway]] <- combined_df
-}
-
-
-

Plot the spatial data -

-
-limits_list <- list(
-  Wnt = c(-3, 4),
-  Notch = c(-3, 4),
-  Hippo = c(-2, 3),
-  Tgfb = c(-2, 3),
-  HIF1a = c(-3, 5)
-)
-
-for (pathway in names(combined_df_lists)) {
-  combined_df <- combined_df_lists[[pathway]]
-  selected_limits <- limits_list[[pathway]]
-  
-  p <- ggplot(combined_df, aes(x = x, y = y, color = score)) +
-    geom_point(size = 0.3) +
-    scale_color_viridis_c(
-      option = "magma",
-      name = paste0(pathway, "_score"),
-      limits = selected_limits,
-      oob = scales::squish
-    ) +
-    scale_y_reverse() +
-    coord_fixed() +
-    theme_void() +
-    theme(legend.position = "right")
-  
-  print(p)
-}
-

-
-
- - - -
- - - -
- -
-

-

Site built with pkgdown 2.1.3.

-
- -
-
- - - - - - - - diff --git a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-2-1.png b/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-2-1.png deleted file mode 100644 index 670a554..0000000 Binary files a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-2-1.png and /dev/null differ diff --git a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-2-2.png b/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-2-2.png deleted file mode 100644 index 7af9f14..0000000 Binary files a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-2-2.png and /dev/null differ diff --git a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-2-3.png b/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-2-3.png deleted file mode 100644 index 1d22763..0000000 Binary files a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-2-3.png and /dev/null differ diff --git a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-2-4.png b/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-2-4.png deleted file mode 100644 index 2f6e7bd..0000000 Binary files a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-2-4.png and /dev/null differ diff --git a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-2-5.png b/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-2-5.png deleted file mode 100644 index aef9bf2..0000000 Binary files a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-2-5.png and /dev/null differ diff --git a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-6-1.png b/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-6-1.png deleted file mode 100644 index 6204dfd..0000000 Binary files a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-6-1.png and /dev/null differ diff --git a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-6-2.png b/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-6-2.png deleted file mode 100644 index b2bf452..0000000 Binary files a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-6-2.png and /dev/null differ diff --git a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-6-3.png b/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-6-3.png deleted file mode 100644 index c590552..0000000 Binary files a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-6-3.png and /dev/null differ diff --git a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-6-4.png b/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-6-4.png deleted file mode 100644 index b07441d..0000000 Binary files a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-6-4.png and /dev/null differ diff --git a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-6-5.png b/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-6-5.png deleted file mode 100644 index 2864ce0..0000000 Binary files a/docs/articles/spatial_pathway_files/figure-html/unnamed-chunk-6-5.png and /dev/null differ diff --git a/docs/articles/spatial_pathway_updated.html b/docs/articles/spatial_pathway_updated.html new file mode 100644 index 0000000..e809a7e --- /dev/null +++ b/docs/articles/spatial_pathway_updated.html @@ -0,0 +1,926 @@ + + + + + + + +Spatial Pathway Visualization • PathwayEmbed + + + + + + + + Skip to contents + + +
+ + + + +
+
+ + + +
+

Overview +

+

This vignette demonstrates the application of PathwayEmbed in mouse +embryo spatial data (E9.5 - E12.5). With curated pathway database, we +examined and compared Wnt, Notch, TGFb, Hippo, and HIF-1a signaling +transduction states across spatial and temporal development. Reference +for the initial data: Chen et al. Spatiotemporal transcriptomic atlas of +mouse organogenesis using DNA nanoball-patterned arrays, Cell, Volume +185, Issue 10, 2022, Pages 1777-1792.e21.

+
+knitr::opts_chunk$set(
+  echo = TRUE,
+  collapse = TRUE,
+  warning = FALSE,
+  message = FALSE,
+  comment = "#>",
+  fig.width = 8,
+  fig.height = 6
+)
+
+# load library
+library(PathwayEmbed)
+library(Seurat)
+
## Warning: package 'Seurat' was built under R version 4.4.3
+
## Loading required package: SeuratObject
+
## Warning: package 'SeuratObject' was built under R version 4.4.3
+
## Loading required package: sp
+
## Warning: package 'sp' was built under R version 4.4.3
+
## 
+## Attaching package: 'SeuratObject'
+
## The following objects are masked from 'package:base':
+## 
+##     intersect, t
+ +
## Warning: package 'ggplot2' was built under R version 4.4.3
+ +
## Loading required package: viridisLite
+
## Warning: package 'viridisLite' was built under R version 4.4.3
+ +
## Warning: package 'dplyr' was built under R version 4.4.3
+
## 
+## Attaching package: 'dplyr'
+
## The following objects are masked from 'package:stats':
+## 
+##     filter, lag
+
## The following objects are masked from 'package:base':
+## 
+##     intersect, setdiff, setequal, union
+ +
## Warning: package 'Hmisc' was built under R version 4.4.3
+
## 
+## Attaching package: 'Hmisc'
+
## The following objects are masked from 'package:dplyr':
+## 
+##     src, summarize
+
## The following object is masked from 'package:Seurat':
+## 
+##     Key
+
## The following object is masked from 'package:SeuratObject':
+## 
+##     Key
+
## The following objects are masked from 'package:base':
+## 
+##     format.pval, units
+ +
## corrplot 0.95 loaded
+ +
## Warning: package 'tibble' was built under R version 4.4.3
+ +
## Warning: package 'tidyr' was built under R version 4.4.3
+
+
+

Spatial data load and process +

+

The files can be downloaded from figshare via below link:

+

Huang, Yaqing (2025). dat3.with.niches.norm.Robj. figshare. Dataset. +https://doi.org/10.6084/m9.figshare.29649995.v1

+

Huang, Yaqing (2025). dat4.with.niches.norm.Robj. figshare. Dataset. +https://doi.org/10.6084/m9.figshare.29649989.v1

+

Huang, Yaqing (2025). dat1.with.niches.norm.Robj. figshare. Dataset. +https://doi.org/10.6084/m9.figshare.29649992.v1

+

Huang, Yaqing (2025). dat2.with.niches.norm.Robj. figshare. Dataset. +https://doi.org/10.6084/m9.figshare.29649986.v1

+
+# load data
+load("dat1.with.niches.norm.Robj")
+load("dat2.with.niches.norm.Robj")
+load("dat3.with.niches.norm.Robj")
+load("dat4.with.niches.norm.Robj")
+
+# Merge together
+merged_spatial <- merge(
+  dat1, y = c(dat2, dat3, dat4))
+
+# Set Default Assay to be "RNA"
+DefaultAssay(merged_spatial) <- "RNA"
+
+# Get genes x cell matrix
+merged_spatial_matrix <- as.matrix(GetAssayData(merged_spatial, assay = "RNA", layer = "data"))
+
+# Get metadata matrix
+merged_spatial_metadata <- merged_spatial@meta.data
+
+
+

Get Pathway Data for Each Pathway first +

+
+
+# All Pathways
+ListPathway("Pathway")
+#> [1] "HIF1A" "HIPPO" "NOTCH" "TGFB"  "WNT"
+ListPathway("HIF1A") # Pick Hypoxia_24hr
+#> # A tibble: 3 × 8
+#>   Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes
+#>   <chr>   <chr>      <chr>         <chr>     <chr>       <chr>       <dbl> <chr>
+#> 1 HIF1A   Hypoxia_6… GSE227502     Hypoxia … Primary hu… Human          21 NA   
+#> 2 HIF1A   Hypoxia_2… GSE227502     Hypoxia … Primary hu… Human          18 NA   
+#> 3 HIF1A   Hypoxia_5… GSE227502     Hypoxia … Primary hu… Human          10 NA
+ListPathway("HIPPO") # Only one: HIPPO_heat
+#> # A tibble: 1 × 8
+#>   Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes
+#>   <chr>   <chr>      <chr>         <chr>     <chr>       <chr>       <dbl> <chr>
+#> 1 HIPPO   HIPPO_heat GSE133251     Heat str… B16-OVA me… Mouse          40 NA
+ListPathway("NOTCH") # Use NOTCH_JAG1_24H -> validated in another datasets
+#> # A tibble: 6 × 8
+#>   Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes
+#>   <chr>   <chr>      <chr>         <chr>     <chr>       <chr>       <dbl> <chr>
+#> 1 NOTCH   NOTCH_JAG1 GSE223734     rJAG1 li… Mouse embr… Mouse           5 NA   
+#> 2 NOTCH   NOTCH_CB1… GSE221577     CB-103 N… RPMI-8402 … Human          46 NA   
+#> 3 NOTCH   NOTCH_LY_… GSE221577     LY411575… RPMI-8402 … Human          46 NA   
+#> 4 NOTCH   NOTCH_JAG… GSE235637     JAG1 sti… SVG-A cells Human          11 NA   
+#> 5 NOTCH   NOTCH_JAG… GSE235637     JAG1 sti… SVG-A cells Human          11 NA   
+#> 6 NOTCH   NOTCH_JAG… GSE235637     JAG1 sti… SVG-A cells Human          11 NA
+ListPathway("TGFB") # Use TGFB_Mouse since this is the only Ms dataset 
+#> # A tibble: 3 × 8
+#>   Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes
+#>   <chr>   <chr>      <chr>         <chr>     <chr>       <chr>       <dbl> <chr>
+#> 1 TGFB    TGFB_Huma… GSE110021     TGF-β1 t… WI-38 fibr… Human          35 NA   
+#> 2 TGFB    TGFB_Huma… GSE110021     TGF-β1 t… WI-38 fibr… Human          39 NA   
+#> 3 TGFB    TGFB_Mouse GSE246932     TGF-β1 t… T Cells     Mouse           9 NA
+ListPathway("WNT") # Use WNT3A_SLOPE_ACTIVATION
+#> # A tibble: 4 × 8
+#>   Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes
+#>   <chr>   <chr>      <chr>         <chr>     <chr>       <chr>       <dbl> <chr>
+#> 1 WNT     WNT3A_12H… GSE103175     WNT3A tr… Human Embr… Human          90 NA   
+#> 2 WNT     WNT3A_24H… GSE103175     WNT3A tr… Human Embr… Human          88 NA   
+#> 3 WNT     WNT3A_48H… GSE103175     WNT3A tr… Human Embr… Human          90 NA   
+#> 4 WNT     WNT3A_SLO… GSE103175     WNT3A tr… Human Embr… Human          90 NA
+
+# Load Each Pathwaydatabase
+HIf1a_pathwaydata <- LoadPathway("Hypoxia_24hr", "mouse")
+Hippo_pathwaydata <- LoadPathway("HIPPO_heat", "mouse")
+Notch_pathwaydata <- LoadPathway("NOTCH_JAG1_24H", "mouse")
+TGFb_pathwaydata <- LoadPathway("TGFB_Mouse", "mouse")
+Wnt_pathwaydata <- LoadPathway("WNT3A_SLOPE_ACTIVATION", "mouse")
+
+
+

Calculation +

+

Using Matrix extracted to avoid large size data object, compute score +for Wnt, Notch, Hippo, Tgfb, and HIF-1a pathways for the merged subject +using ‘ComputeCellData’ in PathwayEmbed

+
+
+
+# DataPreProcess
+matrix_HIf1a <- DataPreProcess(merged_spatial_matrix, HIf1a_pathwaydata, Seurat.object = FALSE)
+matrix_Hippo <- DataPreProcess(merged_spatial_matrix, Hippo_pathwaydata, Seurat.object = FALSE)
+matrix_Notch <- DataPreProcess(merged_spatial_matrix, Notch_pathwaydata, Seurat.object = FALSE)
+matrix_TGFb <- DataPreProcess(merged_spatial_matrix, TGFb_pathwaydata, Seurat.object = FALSE)
+matrix_Wnt <- DataPreProcess(merged_spatial_matrix, Wnt_pathwaydata, Seurat.object = FALSE)
+
+# PathwayMaxMin
+pathwaystat_HIf1a <- PathwayMaxMin(matrix_HIf1a, HIf1a_pathwaydata)
+pathwaystat_Hippo <- PathwayMaxMin(matrix_Hippo, Hippo_pathwaydata)
+pathwaystat_Notch <- PathwayMaxMin(matrix_Notch, Notch_pathwaydata)
+pathwaystat_TGFb <- PathwayMaxMin(matrix_TGFb, TGFb_pathwaydata)
+pathwaystat_Wnt <- PathwayMaxMin(matrix_Wnt, Wnt_pathwaydata)
+
+# Computing Score
+HIf1a_score <- ComputeCellData(matrix_HIf1a, pathwaystat_HIf1a)
+Hippo_score <- ComputeCellData(matrix_Hippo, pathwaystat_Hippo)
+Notch_score <- ComputeCellData(matrix_Notch, pathwaystat_Notch)
+TGFb_score <- ComputeCellData(matrix_TGFb, pathwaystat_TGFb)
+Wnt_score <- ComputeCellData(matrix_Wnt, pathwaystat_Wnt)
+
+
+

Prepare plot data +

+

Map Timepoints back to the data

+
+
+# Compute the score for each pathway
+Wnt_to.plot <- PreparePlotData(merged_spatial_metadata, Wnt_score, "timepoint", Seurat.object = FALSE)
+Notch_to.plot <- PreparePlotData(merged_spatial_metadata, Notch_score, "timepoint", Seurat.object = FALSE)
+Hippo_to.plot <- PreparePlotData(merged_spatial_metadata, Hippo_score, "timepoint", Seurat.object = FALSE)
+Tgfb_to.plot <- PreparePlotData(merged_spatial_metadata, TGFb_score, "timepoint", Seurat.object = FALSE)
+HIF1a_to.plot <- PreparePlotData(merged_spatial_metadata, HIf1a_score,"timepoint", Seurat.object = FALSE)
+
+
+# Combine to list
+pathway_timepoint <- list(
+  Wnt = Wnt_to.plot,
+  Notch = Notch_to.plot,
+  Hippo = Hippo_to.plot,
+  Tgfb = Tgfb_to.plot,
+  HIF1a = HIF1a_to.plot
+)
+
+
+

Preparation for groups +

+
#> /private/var/folders/dy/dxff9z6j5cdd5sqsvz2l5ngc0000gn/T/RtmpAOrgi8/temp_libpath3ff17d773dd5/PathwayEmbed/extdata/pathway_list_timepoint.rds
+#> /private/var/folders/dy/dxff9z6j5cdd5sqsvz2l5ngc0000gn/T/RtmpAOrgi8/temp_libpath3ff17d773dd5 /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/library
+
+# Color set-up
+magma_colors <- c("#000004FF", "#721F81FF", "#F1605DFF", "#5A90E6")
+
+# Desired timepoint order
+ordered_timepoints <- c("E9.5", "E10.5", "E11.5", "E12.5")
+
+# Reorder timepoint levels
+for (name in names(pathway_timepoint)) {
+  pathway_timepoint[[name]]$timepoint <- factor(pathway_timepoint[[name]]$timepoint, levels = ordered_timepoints)
+}
+
+
+

Plot across different timepoints +

+
+# Calculation
+
+stats <- list()
+# Loop through each pathway and generate/save the plot
+for (i in seq_along(pathway_timepoint)) {
+  stats[[i]] <- CalculatePercentage(pathway_timepoint[[i]], "timepoint")
+  
+  df_stats <- stats[[i]]
+  
+  df_stats <- stats[[i]] %>%
+  dplyr::distinct(group, .keep_all = TRUE) %>%
+  dplyr::rename(timepoint = group)
+
+p <- PlotPathway(
+  pathway_timepoint[[i]],
+  names(pathway_timepoint)[i],
+  "timepoint",
+  magma_colors
+) +
+  facet_wrap(~factor(timepoint, levels = ordered_timepoints), ncol = 1) +
+  geom_text(
+    data = df_stats %>%
+      mutate(timepoint = factor(timepoint, levels = ordered_timepoints)),
+    aes(
+      x = Inf,
+      y = Inf,
+      label = sprintf(
+        "ON: %.1f%%\nOFF: %.1f%%\np = %.2g",
+        percentage_on, percentage_off, kruskal_p
+      )
+    ),
+    hjust = 1.1,
+    vjust = 1.1,
+    size = 3,
+    inherit.aes = FALSE
+  )
+  
+  print(p)
+  # ggsave(
+  #   filename = paste0(names(pathway_timepoint)[i], "_timepoint_plot.png"),
+  #   plot = p,
+  #   width = 6,
+  #   height = 8,
+  #   dpi = 300
+#  )
+}
+

+
+
+

Merge score with original metadata +

+
+# Step 1: Create named score vectors for each pathway
+score_list <- lapply(pathway_list, function(df) {
+  s <- df$scale
+  names(s) <- rownames(df)
+  return(s)
+})
+
+# Step 2: Add each pathway score to dat1–dat4
+for (i in 1:4) {
+  dat <- get(paste0("dat", i))  # get dat1, dat2, ...
+  
+  for (pathway_name in names(score_list)) {
+    score_vec <- score_list[[pathway_name]]
+    dat[[paste0(pathway_name, "_score")]] <- score_vec[colnames(dat)]
+  }
+  
+  assign(paste0("dat", i), dat)  # assign back to dat1, dat2, etc.
+}
+
+
+# List of Seurat objects
+dat_list <- list(dat1, dat2, dat3, dat4)
+names(dat_list) <- paste0("dat", 1:4)
+
+# List of pathways
+pathways <- names(pathway_list)  # e.g., "Wnt", "Notch", etc.
+
+
+

Extract the coordinates +

+
+# Function to extract 
+extract_pathway_df <- function(seu, pathway, sample_name = "sample") {
+  coords <- as.data.frame(Embeddings(seu[["spatial"]]))
+  colnames(coords) <- c("x", "y")
+  coords$score <- seu[[paste0(pathway, "_score")]][rownames(coords), 1]
+  coords$sample <- sample_name
+  return(coords)
+}
+
+# Set list to save the coordinates
+combined_df_lists <- list()
+
+# For loop for all pathways 
+for (pathway in pathways) {
+  pathway_df_list <- mapply(
+    FUN = extract_pathway_df,
+    seu = dat_list,
+    sample_name = names(dat_list),
+    MoreArgs = list(pathway = pathway),
+    SIMPLIFY = FALSE
+  )
+  
+  combined_df <- do.call(rbind, pathway_df_list)
+  combined_df_lists[[pathway]] <- combined_df
+}
+
+
+

Plot the spatial data +

+
+# Compute global symmetric limits (recommended)
+all_values <- unlist(lapply(combined_df_lists, function(df) df$scale))
+q <- quantile(all_values, c(0.02, 0.98), na.rm = TRUE)
+max_abs <- max(abs(q))
+global_limits <- c(-max_abs, max_abs)
+
+for (pathway in names(combined_df_lists)) {
+  
+  combined_df <- combined_df_lists[[pathway]]
+  # randomize the plot
+  combined_df <- combined_df[sample(nrow(combined_df)), ]
+  
+  p <- ggplot(combined_df, aes(x = x, y = y, color = scale)) +
+    geom_point(size = 0.01) +
+    scale_color_viridis_c(
+      option = "magma",      
+      limits = global_limits,  # symmetric across all pathways
+      oob = scales::squish,
+      name = paste0(pathway, "_score")
+    ) +
+    scale_y_reverse() +
+    coord_fixed() +
+    theme_void() +
+    theme(
+      legend.position = "right",
+      plot.title = element_text(hjust = 0.5, face = "bold")
+    ) +
+    ggtitle(pathway)
+  
+  print(p)
+}
+

+## Spatial Correlation Analysis using Moran’s I

+
+library(spdep)
+
+# Global Moran's I
+
+compute_morans_I <- function(df, k = 6) {
+  
+  coords <- as.matrix(df[, c("x", "y")])
+  
+  # k-nearest neighbors graph
+  knn <- knearneigh(coords, k = k)
+  nb  <- knn2nb(knn)
+  lw  <- nb2listw(nb, style = "W")
+  
+  # Moran’s I test
+  moran.test(df$scale, lw)
+}
+
+moran_results <- lapply(names(combined_df_lists), function(pw) {
+  
+  df <- combined_df_lists[[pw]]
+  res <- compute_morans_I(df)
+  
+  data.frame(
+    pathway = pw,
+    morans_I = res$estimate[["Moran I statistic"]],
+    p_value  = res$p.value
+  )
+})
+moran_results <- do.call(rbind, moran_results)
+
+print(moran_results)
+#>   pathway   morans_I p_value
+#> 1     Wnt 0.08640729       0
+#> 2   Notch 0.21093640       0
+#> 3   Hippo 0.09334557       0
+#> 4    Tgfb 0.12592755       0
+#> 5   HIF1a 0.25478622       0
+
+# compute neighbor Moran's I for pathways with high spatial autocorrelation
+compute_local_moran <- function(df, lw, pathway_name) {
+  
+  local <- localmoran(df$scale, lw)
+  
+  transform(
+    df,
+    local_I = local[, 1],
+    z_score = local[, 4],
+    p_value = local[, 5],
+    pathway = pathway_name
+  )
+}
+
+# Apply to selected pathways
+selected_pathways <- c("Notch", "HIF1a")
+
+df_plot <- do.call(rbind, lapply(selected_pathways, function(pw) {
+  compute_local_moran(combined_df_lists_updated[[pw]], lw, pw)
+}))
+
+library(ggplot2)
+library(viridis)
+
+# 🔀 Randomize plotting order
+df_plot <- df_plot[sample(nrow(df_plot)), ]
+
+df_plot$cluster <- "Not significant"
+
+df_plot$cluster[df_plot$p_value < 0.05 & df_plot$local_I > 0] <- "High-High"
+df_plot$cluster[df_plot$p_value < 0.05 & df_plot$local_I < 0] <- "Low-Low"
+
+df_plot$cluster <- factor(df_plot$cluster,
+                          levels = c("High-High", "Low-Low", "Not significant"))
+
+df_plot <- df_plot[sample(nrow(df_plot)), ]
+
+p_cluster <- ggplot(df_plot, aes(x = x, y = y, color = cluster)) +
+  geom_point(size = 0.001) +
+  scale_color_manual(values = c(
+    "High-High" = "#d73027",   # red = hotspot
+    "Low-Low"   = "#4575b4",   # blue = coldspot
+    "Not significant" = "grey80"
+  )) +
+  scale_y_reverse() +
+  coord_fixed() +
+  facet_wrap(~ pathway) +
+  theme_void() +
+  labs(title = "Local Moran’s I Clusters",
+       color = "Cluster")
+
+print(p_cluster)
+

+
+
+

Benchmark towards Progeny +

+

Benchmark + Technical Confounding Factors

+
+set.seed(123)
+# Load all required libraries
+  library(progeny)
+  library(ggplot2)
+  library(dplyr)
+  library(tidyr)
+  library(patchwork)
+  library(corrplot)
+  library(Hmisc)
+  library(Matrix)
+  library(tibble)
+library(tidyr)
+
+# Explicitly import pipe in case dplyr loaded partially
+`%>%` <- dplyr::`%>%`
+
+# ----Progeny-----
+
+merged_spatial_matrix <- readRDS("merged_spatial_matrix.rds")
+
+progeny_scores <- progeny(
+  merged_spatial_matrix,
+  scale    = TRUE,
+  organism = "Mouse",
+  top      = 100,
+  perm     = 1
+)
+
+# Extract pathways — check column names exist first
+print(colnames(progeny_scores))
+#>  [1] "Androgen" "EGFR"     "Estrogen" "Hypoxia"  "JAK-STAT" "MAPK"    
+#>  [7] "NFkB"     "p53"      "PI3K"     "TGFb"     "TNFa"     "Trail"   
+#> [13] "VEGF"     "WNT"
+
+# Extract existed pathways
+progeny_wnt     <- progeny_scores[, "WNT"]
+progeny_hypoxia <- progeny_scores[, "Hypoxia"]
+progeny_tgfb    <- progeny_scores[, "TGFb"]
+
+# correlation with Progeny score
+cor_wnt  <- cor(Wnt_score,   progeny_wnt,     use = "complete.obs", method = "spearman")
+cor_tgfb <- cor(TGFb_score,  progeny_tgfb,    use = "complete.obs", method = "spearman")
+cor_hif  <- cor(HIf1a_score, progeny_hypoxia, use = "complete.obs", method = "spearman")
+
+cor_results <- data.frame(
+  comparison  = c("Wnt vs PROGENy WNT", "TGFb vs PROGENy TGFb", "HIf1a vs PROGENy Hypoxia"),
+  spearman_r  = round(c(cor_wnt, cor_tgfb, cor_hif), 4),
+  pathway_our = c("Wnt_score", "TGFb_score", "HIf1a_score"),
+  pathway_ref = c("WNT", "TGFb", "Hypoxia")
+)
+
+df_all <- rbind(
+  data.frame(our = Wnt_score,   progeny = progeny_wnt,     pathway = "WNT"),
+  data.frame(our = TGFb_score,  progeny = progeny_tgfb,    pathway = "TGFb"),
+  data.frame(our = HIf1a_score, progeny = progeny_hypoxia, pathway = "Hypoxia")
+)
+
+label_df <- cor_results %>%
+  mutate(pathway = c("WNT", "TGFb", "Hypoxia"),
+         label   = paste0("r = ", round(spearman_r, 3)))
+
+p_benchmark <- ggplot(df_all, aes(x = our, y = progeny)) +
+  
+  geom_point(alpha = 0.3, size = 0.8, color = "grey30") +
+
+  geom_smooth(method = "lm", se = TRUE,
+              color = "#E24B4A", fill = "#FAD4D4",
+              linewidth = 0.8) +
+  geom_text(
+    data = label_df,
+    aes(label = label),
+    x = -Inf, y = Inf,
+    hjust = -0.1, vjust = 1.2,
+    size = 5,
+    fontface = "bold",
+    inherit.aes = FALSE
+  ) +
+  facet_wrap(~ pathway, ncol = 1, scales = "free_x") +
+  labs(
+    title = "Benchmark: Our Scores vs PROGENy",
+    x = "Our pathway score",
+    y = "PROGENy score"
+  ) +
+  theme_classic(base_size = 15) +
+  theme(
+    strip.background = element_rect(fill = "grey95", color = NA),
+    strip.text = element_text(face = "bold"),
+    plot.title = element_text(hjust = 0.5, face = "bold"),
+    axis.title = element_text(face = "bold")
+  )
+
+p_benchmark
+
+
+

+ +

+
+
+

Cross-pathway Spearman Correlation matrix +

+
+score_df <- data.frame(
+  HIf1a = HIf1a_score,
+  Hippo = Hippo_score,
+  Notch = Notch_score,
+  TGFb  = TGFb_score,
+  Wnt   = Wnt_score
+)
+
+cor_matrix <- cor(score_df, method = "spearman", use = "complete.obs")
+
+cor_test <- Hmisc::rcorr(as.matrix(score_df), type = "spearman")
+p_matrix <- cor_test$P
+diag(p_matrix) <- 0  # rcorr sets diagonal to NA; corrplot requires numeric diagonal
+print(round(cor_matrix, 3))
+#>        HIf1a  Hippo  Notch   TGFb    Wnt
+#> HIf1a  1.000 -0.088  0.118  0.078  0.033
+#> Hippo -0.088  1.000 -0.041 -0.093 -0.036
+#> Notch  0.118 -0.041  1.000  0.099  0.041
+#> TGFb   0.078 -0.093  0.099  1.000  0.031
+#> Wnt    0.033 -0.036  0.041  0.031  1.000
+
+# Correlation heatmap
+
+corrplot::corrplot(cor_matrix,
+         method = "color", type = "upper",
+         addCoef.col = "black", number.cex = 0.8,
+         tl.col = "black", tl.srt = 45,
+         p.mat = p_matrix, sig.level = 0.05, insig = "blank",
+         title = "Pathway Spearman Correlations",
+         mar   = c(0, 0, 2, 0))
+

+
+
+
+

Technical Cofounders +

+
+#---Basic QC metrics from the raw count matrix ----
+# merged_spatial_matrix is genes x spots (dense or sparse both work here)
+nCount   <- Matrix::colSums(merged_spatial_matrix)
+nFeature <- Matrix::colSums(merged_spatial_matrix > 0)
+
+# Mitochondrial genes — mouse mt genes start with "mt-" (lowercase)
+mt_genes  <- grep("^mt-", rownames(merged_spatial_matrix),
+                  value = TRUE, ignore.case = TRUE)
+if (length(mt_genes) == 0) {
+  warning("No mitochondrial genes found. Check rowname format (expected 'mt-*').")
+  pct_mt <- rep(NA_real_, ncol(merged_spatial_matrix))
+} else {
+  mt_counts <- Matrix::colSums(merged_spatial_matrix[mt_genes, , drop = FALSE])
+  pct_mt    <- 100 * mt_counts / nCount
+}
+
+
+
+#---Cell Cycle Scoring----
+
+# Strategy: compute the mean z-scored expression of S-phase genes and G2M
+# genes per spot as module scores, then correlate with pathway scores.
+# This is equivalent to Seurat's AddModuleScore but works on a plain matrix.
+
+# Mouse cell cycle gene sets (Tirosh et al. 2015, mouse-converted)
+s_genes_mouse <- c(
+  "Mcm5", "Pcna", "Tyms", "Fen1", "Mcm7", "Mcm4", "Rrm1", "Ung",
+  "Gins2", "Mcm6", "Cdca7", "Dtl", "Prim1", "Uhrf1", "Cenpu",
+  "Hells", "Rfc2", "Rad51ap1", "Gmnn", "Wdc", "Slbp", "Ccne2",
+  "Ubr7", "Pold3", "Msh2", "Atad2", "Rad51", "Rrm2", "Cdc45",
+  "Cdc6", "Exo1", "Tipin", "Dscc1", "Blm", "Casp8ap2", "Usp1",
+  "Clspn", "Pola1", "Chaf1b", "Brip1", "E2f8"
+)
+
+g2m_genes_mouse <- c(
+  "Hmgb2", "Cdk1", "Nusap1", "Ube2c", "Birc5", "Tpx2", "Top2a",
+  "Ndc80", "Cks2", "Nuf2", "Cks1b", "Mki67", "Ckap2l", "Ckap2",
+  "Aurkb", "Bub1", "Kif11", "Anp32e", "Tubb4b", "Gtse1", "Kif20b",
+  "Hjurp", "Cdca3", "Hn1", "Cdc20", "Ttk", "Cdc25c", "Kif2c",
+  "Rangap1", "Ncapd2", "Dlgap5", "Cdca2", "Cdca8", "Ect2", "Kif23",
+  "Hmmr", "Aurka", "Psrc1", "Anln", "Lbr", "Ckap5", "Cenpe",
+  "Ctcf", "Nek2", "G2e3", "Gas2l3", "Cbx5", "Cenpa"
+)
+
+# Helper: compute mean z-scored module score per spot for a gene set.
+# Works on a genes x spots matrix (dense or sparse).
+# Returns a named numeric vector of length = ncol(mat).
+compute_module_score <- function(mat, gene_set) {
+  genes_present <- intersect(gene_set, rownames(mat))
+  if (length(genes_present) == 0) {
+    warning("No genes from gene set found in matrix.")
+    return(rep(NA_real_, ncol(mat)))
+  }
+  if (length(genes_present) < length(gene_set)) {
+    message("  Using ", length(genes_present), " / ", length(gene_set),
+            " genes from gene set.")
+  }
+  sub_mat <- as.matrix(mat[genes_present, , drop = FALSE])
+  # Row-wise z-score (across spots), then average per spot
+  sub_z <- t(scale(t(sub_mat)))
+  sub_z[is.nan(sub_z)] <- 0   # genes with zero variance -> score 0
+  colMeans(sub_z, na.rm = TRUE)
+}
+
+s_score   <- compute_module_score(merged_spatial_matrix, s_genes_mouse)
+g2m_score <- compute_module_score(merged_spatial_matrix, g2m_genes_mouse)
+cc_score  <- s_score - g2m_score   # signed cell-cycle activity index
+
+
+# ---- Stress / Immediate-Early Gene Score---
+# Immediate-early response genes (Fos, Jun family, Hsps, Atf3, Ddit3) are
+# strongly induced by dissociation stress and ambient RNA contamination.
+# A high correlation between a pathway score and this module raises a red flag.
+
+stress_genes_mouse <- c(
+  # IEG
+  "Fos","Jun","Junb","Atf3","Egr1",
+  
+  # ER stress / UPR
+  "Ddit3","Atf4","Xbp1","Hspa5",
+  
+  # heat shock
+  "Hspa1a","Hspa1b","Hsp90aa1",
+  
+  # oxidative
+  "Gadd45a","Gadd45b","Gadd45g"
+)
+
+stress_score <- compute_module_score(merged_spatial_matrix, stress_genes_mouse)
+
+
+# --Assemble confounder data frame---
+
+spot_names <- names(Wnt_score)   # canonical spot order from PathwayEmbed scores
+
+confounder_df <- data.frame(
+  spot        = spot_names,
+  # PathwayEmbed scores
+  Wnt         = Wnt_score[spot_names],
+  TGFb        = TGFb_score[spot_names],
+  HIf1a       = HIf1a_score[spot_names],
+  Hippo       = Hippo_score[spot_names],
+  Notch       = Notch_score[spot_names],
+  # QC metrics
+  nCount      = nCount[spot_names],
+  nFeature    = nFeature[spot_names],
+  pct_mt      = pct_mt[spot_names],
+  # Module scores
+  S_score     = s_score[spot_names],
+  G2M_score   = g2m_score[spot_names],
+  CC_score    = cc_score[spot_names],
+  Stress      = stress_score[spot_names],
+  row.names   = spot_names,
+  stringsAsFactors = FALSE)
+
+pathway_cols    <- c("Wnt", "TGFb", "HIf1a", "Hippo", "Notch")
+confounder_cols <- c("nCount", "nFeature", "pct_mt",
+                     "S_score", "G2M_score", "CC_score", "Stress")
+
+# Build a long-form correlation table
+cor_rows <- lapply(pathway_cols, function(pw) {
+  lapply(confounder_cols, function(cov) {
+    complete_idx <- complete.cases(confounder_df[[pw]], confounder_df[[cov]])
+    r <- cor(confounder_df[[pw]][complete_idx],
+             confounder_df[[cov]][complete_idx],
+             method = "spearman")
+    # Two-sided p-value via t-approximation (valid for large n)
+    n   <- sum(complete_idx)
+    t_stat <- r * sqrt((n - 2) / (1 - r^2))
+    pv <- 2 * pt(-abs(t_stat), df = n - 2)
+    data.frame(pathway = pw, covariate = cov,
+               spearman_r = round(r, 4),
+               p_value    = pv,
+               n_spots    = n,
+               stringsAsFactors = FALSE)
+  })
+})
+cor_table <- do.call(rbind, do.call(c, cor_rows))
+
+# FDR correction across all pathway-covariate pairs
+cor_table$p_adj_BH <- p.adjust(cor_table$p_value, method = "BH")
+cor_table$significant <- cor_table$p_adj_BH < 0.05
+print(cor_table[, c("pathway", "covariate", "spearman_r", "p_adj_BH", "significant")])
+#>    pathway covariate spearman_r      p_adj_BH significant
+#> 1      Wnt    nCount     0.0433  4.415180e-45        TRUE
+#> 2      Wnt  nFeature     0.0426  1.536189e-43        TRUE
+#> 3      Wnt    pct_mt     0.0125  5.228341e-05        TRUE
+#> 4      Wnt   S_score     0.0735 1.130319e-126        TRUE
+#> 5      Wnt G2M_score     0.0871 6.075138e-177        TRUE
+#> 6      Wnt  CC_score    -0.0199  9.980877e-11        TRUE
+#> 7      Wnt    Stress     0.0684 8.929403e-110        TRUE
+#> 8     TGFb    nCount     0.2328  0.000000e+00        TRUE
+#> 9     TGFb  nFeature     0.2108  0.000000e+00        TRUE
+#> 10    TGFb    pct_mt    -0.0755 1.735223e-133        TRUE
+#> 11    TGFb   S_score     0.2074  0.000000e+00        TRUE
+#> 12    TGFb G2M_score     0.2050  0.000000e+00        TRUE
+#> 13    TGFb  CC_score     0.0002  9.384768e-01       FALSE
+#> 14    TGFb    Stress     0.0996 2.252103e-231        TRUE
+#> 15   HIf1a    nCount     0.4212  0.000000e+00        TRUE
+#> 16   HIf1a  nFeature     0.3167  0.000000e+00        TRUE
+#> 17   HIf1a    pct_mt    -0.3226  0.000000e+00        TRUE
+#> 18   HIf1a   S_score     0.3803  0.000000e+00        TRUE
+#> 19   HIf1a G2M_score     0.3572  0.000000e+00        TRUE
+#> 20   HIf1a  CC_score     0.0261  2.706127e-17        TRUE
+#> 21   HIf1a    Stress     0.2466  0.000000e+00        TRUE
+#> 22   Hippo    nCount    -0.1506  0.000000e+00        TRUE
+#> 23   Hippo  nFeature    -0.1228  0.000000e+00        TRUE
+#> 24   Hippo    pct_mt     0.1003 2.944881e-234        TRUE
+#> 25   Hippo   S_score    -0.1268  0.000000e+00        TRUE
+#> 26   Hippo G2M_score    -0.1192  0.000000e+00        TRUE
+#> 27   Hippo  CC_score     0.0047  1.274208e-01       FALSE
+#> 28   Hippo    Stress    -0.0960 8.909423e-215        TRUE
+#> 29   Notch    nCount     0.3083  0.000000e+00        TRUE
+#> 30   Notch  nFeature     0.2871  0.000000e+00        TRUE
+#> 31   Notch    pct_mt    -0.2177  0.000000e+00        TRUE
+#> 32   Notch   S_score     0.2753  0.000000e+00        TRUE
+#> 33   Notch G2M_score     0.2975  0.000000e+00        TRUE
+#> 34   Notch  CC_score    -0.0247  9.902323e-16        TRUE
+#> 35   Notch    Stress     0.1689  0.000000e+00        TRUE
+
+cor_wide <- cor_table %>%
+  select(pathway, covariate, spearman_r) %>%
+  tidyr::pivot_wider(names_from = covariate, values_from = spearman_r) %>%
+  tibble::column_to_rownames("pathway") %>%
+  as.matrix()
+
+sig_wide <- cor_table %>%
+  select(pathway, covariate, significant) %>%
+  tidyr::pivot_wider(names_from = covariate, values_from = significant) %>%
+  tibble::column_to_rownames("pathway") %>%
+  as.matrix()
+
+# Build asterisk annotation matrix: * = FDR < 0.05, blank otherwise
+annot_wide <- ifelse(sig_wide, "*", "")
+
+# Use corrplot for the heatmap (consistent with cross-pathway section)
+
+corrplot::corrplot(
+  cor_wide,
+  method      = "color",
+  is.corr     = FALSE,           # raw values, not a correlation matrix
+  col         = colorRampPalette(c("#2066a8", "white", "#ae282c"))(200),
+  cl.lim      = c(-1, 1),
+  addCoef.col = "black",
+  number.cex  = 0.7,
+  tl.col      = "black",
+  tl.srt      = 45,
+  title       = "Pathway scores vs technical confounders (Spearman rho)",
+  mar         = c(0, 0, 2, 0)
+)
+

+
+
+
+ + + +
+ + + +
+
+ + + + + + + diff --git a/docs/articles/spatial_pathway_updated.md b/docs/articles/spatial_pathway_updated.md new file mode 100644 index 0000000..c9855af --- /dev/null +++ b/docs/articles/spatial_pathway_updated.md @@ -0,0 +1,897 @@ +# Spatial Pathway Visualization + +## Overview + +This vignette demonstrates the application of PathwayEmbed in mouse +embryo spatial data (E9.5 - E12.5). With curated pathway database, we +examined and compared Wnt, Notch, TGFb, Hippo, and HIF-1a signaling +transduction states across spatial and temporal development. Reference +for the initial data: Chen et al. Spatiotemporal transcriptomic atlas of +mouse organogenesis using DNA nanoball-patterned arrays, Cell, Volume +185, Issue 10, 2022, Pages 1777-1792.e21. + +``` r +knitr::opts_chunk$set( + echo = TRUE, + collapse = TRUE, + warning = FALSE, + message = FALSE, + comment = "#>", + fig.width = 8, + fig.height = 6 +) + +# load library +library(PathwayEmbed) +library(Seurat) +``` + + ## Warning: package 'Seurat' was built under R version 4.4.3 + + ## Loading required package: SeuratObject + + ## Warning: package 'SeuratObject' was built under R version 4.4.3 + + ## Loading required package: sp + + ## Warning: package 'sp' was built under R version 4.4.3 + + ## + ## Attaching package: 'SeuratObject' + + ## The following objects are masked from 'package:base': + ## + ## intersect, t + +``` r +library(ggplot2) +``` + + ## Warning: package 'ggplot2' was built under R version 4.4.3 + +``` r +library(viridis) +``` + + ## Loading required package: viridisLite + + ## Warning: package 'viridisLite' was built under R version 4.4.3 + +``` r +library(cowplot) +library(dplyr) +``` + + ## Warning: package 'dplyr' was built under R version 4.4.3 + + ## + ## Attaching package: 'dplyr' + + ## The following objects are masked from 'package:stats': + ## + ## filter, lag + + ## The following objects are masked from 'package:base': + ## + ## intersect, setdiff, setequal, union + +``` r +library(Hmisc) +``` + + ## Warning: package 'Hmisc' was built under R version 4.4.3 + + ## + ## Attaching package: 'Hmisc' + + ## The following objects are masked from 'package:dplyr': + ## + ## src, summarize + + ## The following object is masked from 'package:Seurat': + ## + ## Key + + ## The following object is masked from 'package:SeuratObject': + ## + ## Key + + ## The following objects are masked from 'package:base': + ## + ## format.pval, units + +``` r +library(corrplot) +``` + + ## corrplot 0.95 loaded + +``` r +library(tibble) +``` + + ## Warning: package 'tibble' was built under R version 4.4.3 + +``` r +library(tidyr) +``` + + ## Warning: package 'tidyr' was built under R version 4.4.3 + +## Spatial data load and process + +The files can be downloaded from figshare via below link: + +Huang, Yaqing (2025). dat3.with.niches.norm.Robj. figshare. Dataset. + + +Huang, Yaqing (2025). dat4.with.niches.norm.Robj. figshare. Dataset. + + +Huang, Yaqing (2025). dat1.with.niches.norm.Robj. figshare. Dataset. + + +Huang, Yaqing (2025). dat2.with.niches.norm.Robj. figshare. Dataset. + + +``` r +# load data +load("dat1.with.niches.norm.Robj") +load("dat2.with.niches.norm.Robj") +load("dat3.with.niches.norm.Robj") +load("dat4.with.niches.norm.Robj") + +# Merge together +merged_spatial <- merge( + dat1, y = c(dat2, dat3, dat4)) + +# Set Default Assay to be "RNA" +DefaultAssay(merged_spatial) <- "RNA" + +# Get genes x cell matrix +merged_spatial_matrix <- as.matrix(GetAssayData(merged_spatial, assay = "RNA", layer = "data")) + +# Get metadata matrix +merged_spatial_metadata <- merged_spatial@meta.data +``` + +## Get Pathway Data for Each Pathway first + +``` r + +# All Pathways +ListPathway("Pathway") +#> [1] "HIF1A" "HIPPO" "NOTCH" "TGFB" "WNT" +ListPathway("HIF1A") # Pick Hypoxia_24hr +#> # A tibble: 3 × 8 +#> Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes +#> +#> 1 HIF1A Hypoxia_6… GSE227502 Hypoxia … Primary hu… Human 21 NA +#> 2 HIF1A Hypoxia_2… GSE227502 Hypoxia … Primary hu… Human 18 NA +#> 3 HIF1A Hypoxia_5… GSE227502 Hypoxia … Primary hu… Human 10 NA +ListPathway("HIPPO") # Only one: HIPPO_heat +#> # A tibble: 1 × 8 +#> Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes +#> +#> 1 HIPPO HIPPO_heat GSE133251 Heat str… B16-OVA me… Mouse 40 NA +ListPathway("NOTCH") # Use NOTCH_JAG1_24H -> validated in another datasets +#> # A tibble: 6 × 8 +#> Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes +#> +#> 1 NOTCH NOTCH_JAG1 GSE223734 rJAG1 li… Mouse embr… Mouse 5 NA +#> 2 NOTCH NOTCH_CB1… GSE221577 CB-103 N… RPMI-8402 … Human 46 NA +#> 3 NOTCH NOTCH_LY_… GSE221577 LY411575… RPMI-8402 … Human 46 NA +#> 4 NOTCH NOTCH_JAG… GSE235637 JAG1 sti… SVG-A cells Human 11 NA +#> 5 NOTCH NOTCH_JAG… GSE235637 JAG1 sti… SVG-A cells Human 11 NA +#> 6 NOTCH NOTCH_JAG… GSE235637 JAG1 sti… SVG-A cells Human 11 NA +ListPathway("TGFB") # Use TGFB_Mouse since this is the only Ms dataset +#> # A tibble: 3 × 8 +#> Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes +#> +#> 1 TGFB TGFB_Huma… GSE110021 TGF-β1 t… WI-38 fibr… Human 35 NA +#> 2 TGFB TGFB_Huma… GSE110021 TGF-β1 t… WI-38 fibr… Human 39 NA +#> 3 TGFB TGFB_Mouse GSE246932 TGF-β1 t… T Cells Mouse 9 NA +ListPathway("WNT") # Use WNT3A_SLOPE_ACTIVATION +#> # A tibble: 4 × 8 +#> Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes +#> +#> 1 WNT WNT3A_12H… GSE103175 WNT3A tr… Human Embr… Human 90 NA +#> 2 WNT WNT3A_24H… GSE103175 WNT3A tr… Human Embr… Human 88 NA +#> 3 WNT WNT3A_48H… GSE103175 WNT3A tr… Human Embr… Human 90 NA +#> 4 WNT WNT3A_SLO… GSE103175 WNT3A tr… Human Embr… Human 90 NA + +# Load Each Pathwaydatabase +HIf1a_pathwaydata <- LoadPathway("Hypoxia_24hr", "mouse") +Hippo_pathwaydata <- LoadPathway("HIPPO_heat", "mouse") +Notch_pathwaydata <- LoadPathway("NOTCH_JAG1_24H", "mouse") +TGFb_pathwaydata <- LoadPathway("TGFB_Mouse", "mouse") +Wnt_pathwaydata <- LoadPathway("WNT3A_SLOPE_ACTIVATION", "mouse") +``` + +## Calculation + +Using Matrix extracted to avoid large size data object, compute score +for Wnt, Notch, Hippo, Tgfb, and HIF-1a pathways for the merged subject +using ‘ComputeCellData’ in PathwayEmbed + +``` r + + +# DataPreProcess +matrix_HIf1a <- DataPreProcess(merged_spatial_matrix, HIf1a_pathwaydata, Seurat.object = FALSE) +matrix_Hippo <- DataPreProcess(merged_spatial_matrix, Hippo_pathwaydata, Seurat.object = FALSE) +matrix_Notch <- DataPreProcess(merged_spatial_matrix, Notch_pathwaydata, Seurat.object = FALSE) +matrix_TGFb <- DataPreProcess(merged_spatial_matrix, TGFb_pathwaydata, Seurat.object = FALSE) +matrix_Wnt <- DataPreProcess(merged_spatial_matrix, Wnt_pathwaydata, Seurat.object = FALSE) + +# PathwayMaxMin +pathwaystat_HIf1a <- PathwayMaxMin(matrix_HIf1a, HIf1a_pathwaydata) +pathwaystat_Hippo <- PathwayMaxMin(matrix_Hippo, Hippo_pathwaydata) +pathwaystat_Notch <- PathwayMaxMin(matrix_Notch, Notch_pathwaydata) +pathwaystat_TGFb <- PathwayMaxMin(matrix_TGFb, TGFb_pathwaydata) +pathwaystat_Wnt <- PathwayMaxMin(matrix_Wnt, Wnt_pathwaydata) + +# Computing Score +HIf1a_score <- ComputeCellData(matrix_HIf1a, pathwaystat_HIf1a) +Hippo_score <- ComputeCellData(matrix_Hippo, pathwaystat_Hippo) +Notch_score <- ComputeCellData(matrix_Notch, pathwaystat_Notch) +TGFb_score <- ComputeCellData(matrix_TGFb, pathwaystat_TGFb) +Wnt_score <- ComputeCellData(matrix_Wnt, pathwaystat_Wnt) +``` + +## Prepare plot data + +Map Timepoints back to the data + +``` r + +# Compute the score for each pathway +Wnt_to.plot <- PreparePlotData(merged_spatial_metadata, Wnt_score, "timepoint", Seurat.object = FALSE) +Notch_to.plot <- PreparePlotData(merged_spatial_metadata, Notch_score, "timepoint", Seurat.object = FALSE) +Hippo_to.plot <- PreparePlotData(merged_spatial_metadata, Hippo_score, "timepoint", Seurat.object = FALSE) +Tgfb_to.plot <- PreparePlotData(merged_spatial_metadata, TGFb_score, "timepoint", Seurat.object = FALSE) +HIF1a_to.plot <- PreparePlotData(merged_spatial_metadata, HIf1a_score,"timepoint", Seurat.object = FALSE) + + +# Combine to list +pathway_timepoint <- list( + Wnt = Wnt_to.plot, + Notch = Notch_to.plot, + Hippo = Hippo_to.plot, + Tgfb = Tgfb_to.plot, + HIF1a = HIF1a_to.plot +) +``` + +## Preparation for groups + + #> /private/var/folders/dy/dxff9z6j5cdd5sqsvz2l5ngc0000gn/T/RtmpAOrgi8/temp_libpath3ff17d773dd5/PathwayEmbed/extdata/pathway_list_timepoint.rds + #> /private/var/folders/dy/dxff9z6j5cdd5sqsvz2l5ngc0000gn/T/RtmpAOrgi8/temp_libpath3ff17d773dd5 /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/library + +``` r +# Color set-up +magma_colors <- c("#000004FF", "#721F81FF", "#F1605DFF", "#5A90E6") + +# Desired timepoint order +ordered_timepoints <- c("E9.5", "E10.5", "E11.5", "E12.5") + +# Reorder timepoint levels +for (name in names(pathway_timepoint)) { + pathway_timepoint[[name]]$timepoint <- factor(pathway_timepoint[[name]]$timepoint, levels = ordered_timepoints) +} +``` + +## Plot across different timepoints + +``` r +# Calculation + +stats <- list() +# Loop through each pathway and generate/save the plot +for (i in seq_along(pathway_timepoint)) { + stats[[i]] <- CalculatePercentage(pathway_timepoint[[i]], "timepoint") + + df_stats <- stats[[i]] + + df_stats <- stats[[i]] %>% + dplyr::distinct(group, .keep_all = TRUE) %>% + dplyr::rename(timepoint = group) + +p <- PlotPathway( + pathway_timepoint[[i]], + names(pathway_timepoint)[i], + "timepoint", + magma_colors +) + + facet_wrap(~factor(timepoint, levels = ordered_timepoints), ncol = 1) + + geom_text( + data = df_stats %>% + mutate(timepoint = factor(timepoint, levels = ordered_timepoints)), + aes( + x = Inf, + y = Inf, + label = sprintf( + "ON: %.1f%%\nOFF: %.1f%%\np = %.2g", + percentage_on, percentage_off, kruskal_p + ) + ), + hjust = 1.1, + vjust = 1.1, + size = 3, + inherit.aes = FALSE + ) + + print(p) + # ggsave( + # filename = paste0(names(pathway_timepoint)[i], "_timepoint_plot.png"), + # plot = p, + # width = 6, + # height = 8, + # dpi = 300 +# ) +} +``` + +![](spatial_pathway_updated_files/figure-html/unnamed-chunk-3-1.png)![](spatial_pathway_updated_files/figure-html/unnamed-chunk-3-2.png)![](spatial_pathway_updated_files/figure-html/unnamed-chunk-3-3.png)![](spatial_pathway_updated_files/figure-html/unnamed-chunk-3-4.png)![](spatial_pathway_updated_files/figure-html/unnamed-chunk-3-5.png) + +## Merge score with original metadata + +``` r +# Step 1: Create named score vectors for each pathway +score_list <- lapply(pathway_list, function(df) { + s <- df$scale + names(s) <- rownames(df) + return(s) +}) + +# Step 2: Add each pathway score to dat1–dat4 +for (i in 1:4) { + dat <- get(paste0("dat", i)) # get dat1, dat2, ... + + for (pathway_name in names(score_list)) { + score_vec <- score_list[[pathway_name]] + dat[[paste0(pathway_name, "_score")]] <- score_vec[colnames(dat)] + } + + assign(paste0("dat", i), dat) # assign back to dat1, dat2, etc. +} + + +# List of Seurat objects +dat_list <- list(dat1, dat2, dat3, dat4) +names(dat_list) <- paste0("dat", 1:4) + +# List of pathways +pathways <- names(pathway_list) # e.g., "Wnt", "Notch", etc. +``` + +## Extract the coordinates + +``` r +# Function to extract +extract_pathway_df <- function(seu, pathway, sample_name = "sample") { + coords <- as.data.frame(Embeddings(seu[["spatial"]])) + colnames(coords) <- c("x", "y") + coords$score <- seu[[paste0(pathway, "_score")]][rownames(coords), 1] + coords$sample <- sample_name + return(coords) +} + +# Set list to save the coordinates +combined_df_lists <- list() + +# For loop for all pathways +for (pathway in pathways) { + pathway_df_list <- mapply( + FUN = extract_pathway_df, + seu = dat_list, + sample_name = names(dat_list), + MoreArgs = list(pathway = pathway), + SIMPLIFY = FALSE + ) + + combined_df <- do.call(rbind, pathway_df_list) + combined_df_lists[[pathway]] <- combined_df +} +``` + +## Plot the spatial data + +``` r +# Compute global symmetric limits (recommended) +all_values <- unlist(lapply(combined_df_lists, function(df) df$scale)) +q <- quantile(all_values, c(0.02, 0.98), na.rm = TRUE) +max_abs <- max(abs(q)) +global_limits <- c(-max_abs, max_abs) + +for (pathway in names(combined_df_lists)) { + + combined_df <- combined_df_lists[[pathway]] + # randomize the plot + combined_df <- combined_df[sample(nrow(combined_df)), ] + + p <- ggplot(combined_df, aes(x = x, y = y, color = scale)) + + geom_point(size = 0.01) + + scale_color_viridis_c( + option = "magma", + limits = global_limits, # symmetric across all pathways + oob = scales::squish, + name = paste0(pathway, "_score") + ) + + scale_y_reverse() + + coord_fixed() + + theme_void() + + theme( + legend.position = "right", + plot.title = element_text(hjust = 0.5, face = "bold") + ) + + ggtitle(pathway) + + print(p) +} +``` + +![](spatial_pathway_updated_files/figure-html/unnamed-chunk-7-1.png)![](spatial_pathway_updated_files/figure-html/unnamed-chunk-7-2.png)![](spatial_pathway_updated_files/figure-html/unnamed-chunk-7-3.png)![](spatial_pathway_updated_files/figure-html/unnamed-chunk-7-4.png)![](spatial_pathway_updated_files/figure-html/unnamed-chunk-7-5.png) +\## Spatial Correlation Analysis using Moran’s I + +``` r +library(spdep) + +# Global Moran's I + +compute_morans_I <- function(df, k = 6) { + + coords <- as.matrix(df[, c("x", "y")]) + + # k-nearest neighbors graph + knn <- knearneigh(coords, k = k) + nb <- knn2nb(knn) + lw <- nb2listw(nb, style = "W") + + # Moran’s I test + moran.test(df$scale, lw) +} + +moran_results <- lapply(names(combined_df_lists), function(pw) { + + df <- combined_df_lists[[pw]] + res <- compute_morans_I(df) + + data.frame( + pathway = pw, + morans_I = res$estimate[["Moran I statistic"]], + p_value = res$p.value + ) +}) +moran_results <- do.call(rbind, moran_results) +``` + +``` r +print(moran_results) +#> pathway morans_I p_value +#> 1 Wnt 0.08640729 0 +#> 2 Notch 0.21093640 0 +#> 3 Hippo 0.09334557 0 +#> 4 Tgfb 0.12592755 0 +#> 5 HIF1a 0.25478622 0 +``` + +``` r +# compute neighbor Moran's I for pathways with high spatial autocorrelation +compute_local_moran <- function(df, lw, pathway_name) { + + local <- localmoran(df$scale, lw) + + transform( + df, + local_I = local[, 1], + z_score = local[, 4], + p_value = local[, 5], + pathway = pathway_name + ) +} + +# Apply to selected pathways +selected_pathways <- c("Notch", "HIF1a") + +df_plot <- do.call(rbind, lapply(selected_pathways, function(pw) { + compute_local_moran(combined_df_lists_updated[[pw]], lw, pw) +})) +``` + +``` r +library(ggplot2) +library(viridis) + +# 🔀 Randomize plotting order +df_plot <- df_plot[sample(nrow(df_plot)), ] + +df_plot$cluster <- "Not significant" + +df_plot$cluster[df_plot$p_value < 0.05 & df_plot$local_I > 0] <- "High-High" +df_plot$cluster[df_plot$p_value < 0.05 & df_plot$local_I < 0] <- "Low-Low" + +df_plot$cluster <- factor(df_plot$cluster, + levels = c("High-High", "Low-Low", "Not significant")) + +df_plot <- df_plot[sample(nrow(df_plot)), ] + +p_cluster <- ggplot(df_plot, aes(x = x, y = y, color = cluster)) + + geom_point(size = 0.001) + + scale_color_manual(values = c( + "High-High" = "#d73027", # red = hotspot + "Low-Low" = "#4575b4", # blue = coldspot + "Not significant" = "grey80" + )) + + scale_y_reverse() + + coord_fixed() + + facet_wrap(~ pathway) + + theme_void() + + labs(title = "Local Moran’s I Clusters", + color = "Cluster") + +print(p_cluster) +``` + +![](spatial_pathway_updated_files/figure-html/plot%20local%20morans%20I-1.png) + +## Benchmark towards Progeny + +Benchmark + Technical Confounding Factors + +``` r +set.seed(123) +# Load all required libraries + library(progeny) + library(ggplot2) + library(dplyr) + library(tidyr) + library(patchwork) + library(corrplot) + library(Hmisc) + library(Matrix) + library(tibble) +library(tidyr) + +# Explicitly import pipe in case dplyr loaded partially +`%>%` <- dplyr::`%>%` + +# ----Progeny----- + +merged_spatial_matrix <- readRDS("merged_spatial_matrix.rds") + +progeny_scores <- progeny( + merged_spatial_matrix, + scale = TRUE, + organism = "Mouse", + top = 100, + perm = 1 +) +``` + +``` r +# Extract pathways — check column names exist first +print(colnames(progeny_scores)) +#> [1] "Androgen" "EGFR" "Estrogen" "Hypoxia" "JAK-STAT" "MAPK" +#> [7] "NFkB" "p53" "PI3K" "TGFb" "TNFa" "Trail" +#> [13] "VEGF" "WNT" + +# Extract existed pathways +progeny_wnt <- progeny_scores[, "WNT"] +progeny_hypoxia <- progeny_scores[, "Hypoxia"] +progeny_tgfb <- progeny_scores[, "TGFb"] + +# correlation with Progeny score +cor_wnt <- cor(Wnt_score, progeny_wnt, use = "complete.obs", method = "spearman") +cor_tgfb <- cor(TGFb_score, progeny_tgfb, use = "complete.obs", method = "spearman") +cor_hif <- cor(HIf1a_score, progeny_hypoxia, use = "complete.obs", method = "spearman") + +cor_results <- data.frame( + comparison = c("Wnt vs PROGENy WNT", "TGFb vs PROGENy TGFb", "HIf1a vs PROGENy Hypoxia"), + spearman_r = round(c(cor_wnt, cor_tgfb, cor_hif), 4), + pathway_our = c("Wnt_score", "TGFb_score", "HIf1a_score"), + pathway_ref = c("WNT", "TGFb", "Hypoxia") +) + +df_all <- rbind( + data.frame(our = Wnt_score, progeny = progeny_wnt, pathway = "WNT"), + data.frame(our = TGFb_score, progeny = progeny_tgfb, pathway = "TGFb"), + data.frame(our = HIf1a_score, progeny = progeny_hypoxia, pathway = "Hypoxia") +) + +label_df <- cor_results %>% + mutate(pathway = c("WNT", "TGFb", "Hypoxia"), + label = paste0("r = ", round(spearman_r, 3))) + +p_benchmark <- ggplot(df_all, aes(x = our, y = progeny)) + + + geom_point(alpha = 0.3, size = 0.8, color = "grey30") + + + geom_smooth(method = "lm", se = TRUE, + color = "#E24B4A", fill = "#FAD4D4", + linewidth = 0.8) + + geom_text( + data = label_df, + aes(label = label), + x = -Inf, y = Inf, + hjust = -0.1, vjust = 1.2, + size = 5, + fontface = "bold", + inherit.aes = FALSE + ) + + facet_wrap(~ pathway, ncol = 1, scales = "free_x") + + labs( + title = "Benchmark: Our Scores vs PROGENy", + x = "Our pathway score", + y = "PROGENy score" + ) + + theme_classic(base_size = 15) + + theme( + strip.background = element_rect(fill = "grey95", color = NA), + strip.text = element_text(face = "bold"), + plot.title = element_text(hjust = 0.5, face = "bold"), + axis.title = element_text(face = "bold") + ) + +p_benchmark +``` + +## ![](spatial_pathway_updated_files/figure-html/unnamed-chunk-14-1.png) + +## Cross-pathway Spearman Correlation matrix + +``` r +score_df <- data.frame( + HIf1a = HIf1a_score, + Hippo = Hippo_score, + Notch = Notch_score, + TGFb = TGFb_score, + Wnt = Wnt_score +) + +cor_matrix <- cor(score_df, method = "spearman", use = "complete.obs") + +cor_test <- Hmisc::rcorr(as.matrix(score_df), type = "spearman") +p_matrix <- cor_test$P +diag(p_matrix) <- 0 # rcorr sets diagonal to NA; corrplot requires numeric diagonal +print(round(cor_matrix, 3)) +#> HIf1a Hippo Notch TGFb Wnt +#> HIf1a 1.000 -0.088 0.118 0.078 0.033 +#> Hippo -0.088 1.000 -0.041 -0.093 -0.036 +#> Notch 0.118 -0.041 1.000 0.099 0.041 +#> TGFb 0.078 -0.093 0.099 1.000 0.031 +#> Wnt 0.033 -0.036 0.041 0.031 1.000 + +# Correlation heatmap + +corrplot::corrplot(cor_matrix, + method = "color", type = "upper", + addCoef.col = "black", number.cex = 0.8, + tl.col = "black", tl.srt = 45, + p.mat = p_matrix, sig.level = 0.05, insig = "blank", + title = "Pathway Spearman Correlations", + mar = c(0, 0, 2, 0)) +``` + +![](spatial_pathway_updated_files/figure-html/cross-pathway%20spearman%20correlation%20matrix-1.png) + +------------------------------------------------------------------------ + +## Technical Cofounders + +``` r +#---Basic QC metrics from the raw count matrix ---- +# merged_spatial_matrix is genes x spots (dense or sparse both work here) +nCount <- Matrix::colSums(merged_spatial_matrix) +nFeature <- Matrix::colSums(merged_spatial_matrix > 0) + +# Mitochondrial genes — mouse mt genes start with "mt-" (lowercase) +mt_genes <- grep("^mt-", rownames(merged_spatial_matrix), + value = TRUE, ignore.case = TRUE) +if (length(mt_genes) == 0) { + warning("No mitochondrial genes found. Check rowname format (expected 'mt-*').") + pct_mt <- rep(NA_real_, ncol(merged_spatial_matrix)) +} else { + mt_counts <- Matrix::colSums(merged_spatial_matrix[mt_genes, , drop = FALSE]) + pct_mt <- 100 * mt_counts / nCount +} + + + +#---Cell Cycle Scoring---- + +# Strategy: compute the mean z-scored expression of S-phase genes and G2M +# genes per spot as module scores, then correlate with pathway scores. +# This is equivalent to Seurat's AddModuleScore but works on a plain matrix. + +# Mouse cell cycle gene sets (Tirosh et al. 2015, mouse-converted) +s_genes_mouse <- c( + "Mcm5", "Pcna", "Tyms", "Fen1", "Mcm7", "Mcm4", "Rrm1", "Ung", + "Gins2", "Mcm6", "Cdca7", "Dtl", "Prim1", "Uhrf1", "Cenpu", + "Hells", "Rfc2", "Rad51ap1", "Gmnn", "Wdc", "Slbp", "Ccne2", + "Ubr7", "Pold3", "Msh2", "Atad2", "Rad51", "Rrm2", "Cdc45", + "Cdc6", "Exo1", "Tipin", "Dscc1", "Blm", "Casp8ap2", "Usp1", + "Clspn", "Pola1", "Chaf1b", "Brip1", "E2f8" +) + +g2m_genes_mouse <- c( + "Hmgb2", "Cdk1", "Nusap1", "Ube2c", "Birc5", "Tpx2", "Top2a", + "Ndc80", "Cks2", "Nuf2", "Cks1b", "Mki67", "Ckap2l", "Ckap2", + "Aurkb", "Bub1", "Kif11", "Anp32e", "Tubb4b", "Gtse1", "Kif20b", + "Hjurp", "Cdca3", "Hn1", "Cdc20", "Ttk", "Cdc25c", "Kif2c", + "Rangap1", "Ncapd2", "Dlgap5", "Cdca2", "Cdca8", "Ect2", "Kif23", + "Hmmr", "Aurka", "Psrc1", "Anln", "Lbr", "Ckap5", "Cenpe", + "Ctcf", "Nek2", "G2e3", "Gas2l3", "Cbx5", "Cenpa" +) + +# Helper: compute mean z-scored module score per spot for a gene set. +# Works on a genes x spots matrix (dense or sparse). +# Returns a named numeric vector of length = ncol(mat). +compute_module_score <- function(mat, gene_set) { + genes_present <- intersect(gene_set, rownames(mat)) + if (length(genes_present) == 0) { + warning("No genes from gene set found in matrix.") + return(rep(NA_real_, ncol(mat))) + } + if (length(genes_present) < length(gene_set)) { + message(" Using ", length(genes_present), " / ", length(gene_set), + " genes from gene set.") + } + sub_mat <- as.matrix(mat[genes_present, , drop = FALSE]) + # Row-wise z-score (across spots), then average per spot + sub_z <- t(scale(t(sub_mat))) + sub_z[is.nan(sub_z)] <- 0 # genes with zero variance -> score 0 + colMeans(sub_z, na.rm = TRUE) +} + +s_score <- compute_module_score(merged_spatial_matrix, s_genes_mouse) +g2m_score <- compute_module_score(merged_spatial_matrix, g2m_genes_mouse) +cc_score <- s_score - g2m_score # signed cell-cycle activity index + + +# ---- Stress / Immediate-Early Gene Score--- +# Immediate-early response genes (Fos, Jun family, Hsps, Atf3, Ddit3) are +# strongly induced by dissociation stress and ambient RNA contamination. +# A high correlation between a pathway score and this module raises a red flag. + +stress_genes_mouse <- c( + # IEG + "Fos","Jun","Junb","Atf3","Egr1", + + # ER stress / UPR + "Ddit3","Atf4","Xbp1","Hspa5", + + # heat shock + "Hspa1a","Hspa1b","Hsp90aa1", + + # oxidative + "Gadd45a","Gadd45b","Gadd45g" +) + +stress_score <- compute_module_score(merged_spatial_matrix, stress_genes_mouse) + + +# --Assemble confounder data frame--- + +spot_names <- names(Wnt_score) # canonical spot order from PathwayEmbed scores + +confounder_df <- data.frame( + spot = spot_names, + # PathwayEmbed scores + Wnt = Wnt_score[spot_names], + TGFb = TGFb_score[spot_names], + HIf1a = HIf1a_score[spot_names], + Hippo = Hippo_score[spot_names], + Notch = Notch_score[spot_names], + # QC metrics + nCount = nCount[spot_names], + nFeature = nFeature[spot_names], + pct_mt = pct_mt[spot_names], + # Module scores + S_score = s_score[spot_names], + G2M_score = g2m_score[spot_names], + CC_score = cc_score[spot_names], + Stress = stress_score[spot_names], + row.names = spot_names, + stringsAsFactors = FALSE) +``` + +``` r +pathway_cols <- c("Wnt", "TGFb", "HIf1a", "Hippo", "Notch") +confounder_cols <- c("nCount", "nFeature", "pct_mt", + "S_score", "G2M_score", "CC_score", "Stress") + +# Build a long-form correlation table +cor_rows <- lapply(pathway_cols, function(pw) { + lapply(confounder_cols, function(cov) { + complete_idx <- complete.cases(confounder_df[[pw]], confounder_df[[cov]]) + r <- cor(confounder_df[[pw]][complete_idx], + confounder_df[[cov]][complete_idx], + method = "spearman") + # Two-sided p-value via t-approximation (valid for large n) + n <- sum(complete_idx) + t_stat <- r * sqrt((n - 2) / (1 - r^2)) + pv <- 2 * pt(-abs(t_stat), df = n - 2) + data.frame(pathway = pw, covariate = cov, + spearman_r = round(r, 4), + p_value = pv, + n_spots = n, + stringsAsFactors = FALSE) + }) +}) +cor_table <- do.call(rbind, do.call(c, cor_rows)) + +# FDR correction across all pathway-covariate pairs +cor_table$p_adj_BH <- p.adjust(cor_table$p_value, method = "BH") +cor_table$significant <- cor_table$p_adj_BH < 0.05 +print(cor_table[, c("pathway", "covariate", "spearman_r", "p_adj_BH", "significant")]) +#> pathway covariate spearman_r p_adj_BH significant +#> 1 Wnt nCount 0.0433 4.415180e-45 TRUE +#> 2 Wnt nFeature 0.0426 1.536189e-43 TRUE +#> 3 Wnt pct_mt 0.0125 5.228341e-05 TRUE +#> 4 Wnt S_score 0.0735 1.130319e-126 TRUE +#> 5 Wnt G2M_score 0.0871 6.075138e-177 TRUE +#> 6 Wnt CC_score -0.0199 9.980877e-11 TRUE +#> 7 Wnt Stress 0.0684 8.929403e-110 TRUE +#> 8 TGFb nCount 0.2328 0.000000e+00 TRUE +#> 9 TGFb nFeature 0.2108 0.000000e+00 TRUE +#> 10 TGFb pct_mt -0.0755 1.735223e-133 TRUE +#> 11 TGFb S_score 0.2074 0.000000e+00 TRUE +#> 12 TGFb G2M_score 0.2050 0.000000e+00 TRUE +#> 13 TGFb CC_score 0.0002 9.384768e-01 FALSE +#> 14 TGFb Stress 0.0996 2.252103e-231 TRUE +#> 15 HIf1a nCount 0.4212 0.000000e+00 TRUE +#> 16 HIf1a nFeature 0.3167 0.000000e+00 TRUE +#> 17 HIf1a pct_mt -0.3226 0.000000e+00 TRUE +#> 18 HIf1a S_score 0.3803 0.000000e+00 TRUE +#> 19 HIf1a G2M_score 0.3572 0.000000e+00 TRUE +#> 20 HIf1a CC_score 0.0261 2.706127e-17 TRUE +#> 21 HIf1a Stress 0.2466 0.000000e+00 TRUE +#> 22 Hippo nCount -0.1506 0.000000e+00 TRUE +#> 23 Hippo nFeature -0.1228 0.000000e+00 TRUE +#> 24 Hippo pct_mt 0.1003 2.944881e-234 TRUE +#> 25 Hippo S_score -0.1268 0.000000e+00 TRUE +#> 26 Hippo G2M_score -0.1192 0.000000e+00 TRUE +#> 27 Hippo CC_score 0.0047 1.274208e-01 FALSE +#> 28 Hippo Stress -0.0960 8.909423e-215 TRUE +#> 29 Notch nCount 0.3083 0.000000e+00 TRUE +#> 30 Notch nFeature 0.2871 0.000000e+00 TRUE +#> 31 Notch pct_mt -0.2177 0.000000e+00 TRUE +#> 32 Notch S_score 0.2753 0.000000e+00 TRUE +#> 33 Notch G2M_score 0.2975 0.000000e+00 TRUE +#> 34 Notch CC_score -0.0247 9.902323e-16 TRUE +#> 35 Notch Stress 0.1689 0.000000e+00 TRUE + +cor_wide <- cor_table %>% + select(pathway, covariate, spearman_r) %>% + tidyr::pivot_wider(names_from = covariate, values_from = spearman_r) %>% + tibble::column_to_rownames("pathway") %>% + as.matrix() + +sig_wide <- cor_table %>% + select(pathway, covariate, significant) %>% + tidyr::pivot_wider(names_from = covariate, values_from = significant) %>% + tibble::column_to_rownames("pathway") %>% + as.matrix() + +# Build asterisk annotation matrix: * = FDR < 0.05, blank otherwise +annot_wide <- ifelse(sig_wide, "*", "") + +# Use corrplot for the heatmap (consistent with cross-pathway section) + +corrplot::corrplot( + cor_wide, + method = "color", + is.corr = FALSE, # raw values, not a correlation matrix + col = colorRampPalette(c("#2066a8", "white", "#ae282c"))(200), + cl.lim = c(-1, 1), + addCoef.col = "black", + number.cex = 0.7, + tl.col = "black", + tl.srt = 45, + title = "Pathway scores vs technical confounders (Spearman rho)", + mar = c(0, 0, 2, 0) +) +``` + +![](spatial_pathway_updated_files/figure-html/unnamed-chunk-17-1.png) diff --git a/docs/articles/spatial_pathway_updated_files/figure-html/cross-pathway spearman correlation matrix-1.png b/docs/articles/spatial_pathway_updated_files/figure-html/cross-pathway spearman correlation matrix-1.png new file mode 100644 index 0000000..33bb3d4 Binary files /dev/null and b/docs/articles/spatial_pathway_updated_files/figure-html/cross-pathway spearman correlation matrix-1.png differ diff --git a/docs/articles/spatial_pathway_updated_files/figure-html/plot local morans I-1.png b/docs/articles/spatial_pathway_updated_files/figure-html/plot local morans I-1.png new file mode 100644 index 0000000..b59f081 Binary files /dev/null and b/docs/articles/spatial_pathway_updated_files/figure-html/plot local morans I-1.png differ diff --git a/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-14-1.png b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-14-1.png new file mode 100644 index 0000000..371c88b Binary files /dev/null and b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-14-1.png differ diff --git a/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-17-1.png b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-17-1.png new file mode 100644 index 0000000..2a6411e Binary files /dev/null and b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-17-1.png differ diff --git a/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-1.png b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-1.png new file mode 100644 index 0000000..4714a37 Binary files /dev/null and b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-1.png differ diff --git a/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-2.png b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-2.png new file mode 100644 index 0000000..12380aa Binary files /dev/null and b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-2.png differ diff --git a/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-3.png b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-3.png new file mode 100644 index 0000000..ca774d0 Binary files /dev/null and b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-3.png differ diff --git a/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-4.png b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-4.png new file mode 100644 index 0000000..d569041 Binary files /dev/null and b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-4.png differ diff --git a/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-5.png b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-5.png new file mode 100644 index 0000000..2080534 Binary files /dev/null and b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-5.png differ diff --git a/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-1.png b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-1.png new file mode 100644 index 0000000..bf80757 Binary files /dev/null and b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-1.png differ diff --git a/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-2.png b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-2.png new file mode 100644 index 0000000..27cb725 Binary files /dev/null and b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-2.png differ diff --git a/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-3.png b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-3.png new file mode 100644 index 0000000..c1b7e1a Binary files /dev/null and b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-3.png differ diff --git a/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-4.png b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-4.png new file mode 100644 index 0000000..a9fc74b Binary files /dev/null and b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-4.png differ diff --git a/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-5.png b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-5.png new file mode 100644 index 0000000..7415878 Binary files /dev/null and b/docs/articles/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-5.png differ diff --git a/docs/authors.html b/docs/authors.html index 73f678e..05d81d0 100644 --- a/docs/authors.html +++ b/docs/authors.html @@ -1,100 +1,81 @@ -Authors and Citation • PathwayEmbed - - -
-
+
+
+
-
-
- +

Authors and Citation

+
+
+

Authors

  • Yaqing Huang. Author, maintainer.

-
-
-

Citation

- -
-
+
+

Citation

+

-

Huang Y (2025). +

Huang Y (2026). PathwayEmbed: Tools for Pathway-Level Embedding and Visualization in Single-Cell Data. -R package version 0.0.0.9000. +R package version 0.0.0.9000, https://raredonlab.github.io/PathwayEmbed.

-
@Manual{,
+      
@Manual{,
   title = {PathwayEmbed: Tools for Pathway-Level Embedding and Visualization in Single-Cell Data},
   author = {Yaqing Huang},
-  year = {2025},
+  year = {2026},
   note = {R package version 0.0.0.9000},
+  url = {https://raredonlab.github.io/PathwayEmbed},
 }
+
-
- -
- +
-
- +
diff --git a/docs/authors.md b/docs/authors.md new file mode 100644 index 0000000..d6bbb55 --- /dev/null +++ b/docs/authors.md @@ -0,0 +1,19 @@ +# Authors and Citation + +## Authors + +- **Yaqing Huang**. Author, maintainer. + +## Citation + +Huang Y (2026). *PathwayEmbed: Tools for Pathway-Level Embedding and +Visualization in Single-Cell Data*. R package version 0.0.0.9000, +. + + @Manual{, + title = {PathwayEmbed: Tools for Pathway-Level Embedding and Visualization in Single-Cell Data}, + author = {Yaqing Huang}, + year = {2026}, + note = {R package version 0.0.0.9000}, + url = {https://raredonlab.github.io/PathwayEmbed}, + } diff --git a/docs/bootstrap-toc.css b/docs/bootstrap-toc.css deleted file mode 100644 index 5a85941..0000000 --- a/docs/bootstrap-toc.css +++ /dev/null @@ -1,60 +0,0 @@ -/*! - * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) - * Copyright 2015 Aidan Feldman - * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ - -/* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ - -/* All levels of nav */ -nav[data-toggle='toc'] .nav > li > a { - display: block; - padding: 4px 20px; - font-size: 13px; - font-weight: 500; - color: #767676; -} -nav[data-toggle='toc'] .nav > li > a:hover, -nav[data-toggle='toc'] .nav > li > a:focus { - padding-left: 19px; - color: #563d7c; - text-decoration: none; - background-color: transparent; - border-left: 1px solid #563d7c; -} -nav[data-toggle='toc'] .nav > .active > a, -nav[data-toggle='toc'] .nav > .active:hover > a, -nav[data-toggle='toc'] .nav > .active:focus > a { - padding-left: 18px; - font-weight: bold; - color: #563d7c; - background-color: transparent; - border-left: 2px solid #563d7c; -} - -/* Nav: second level (shown on .active) */ -nav[data-toggle='toc'] .nav .nav { - display: none; /* Hide by default, but at >768px, show it */ - padding-bottom: 10px; -} -nav[data-toggle='toc'] .nav .nav > li > a { - padding-top: 1px; - padding-bottom: 1px; - padding-left: 30px; - font-size: 12px; - font-weight: normal; -} -nav[data-toggle='toc'] .nav .nav > li > a:hover, -nav[data-toggle='toc'] .nav .nav > li > a:focus { - padding-left: 29px; -} -nav[data-toggle='toc'] .nav .nav > .active > a, -nav[data-toggle='toc'] .nav .nav > .active:hover > a, -nav[data-toggle='toc'] .nav .nav > .active:focus > a { - padding-left: 28px; - font-weight: 500; -} - -/* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ -nav[data-toggle='toc'] .nav > .active > ul { - display: block; -} diff --git a/docs/bootstrap-toc.js b/docs/bootstrap-toc.js deleted file mode 100644 index 1cdd573..0000000 --- a/docs/bootstrap-toc.js +++ /dev/null @@ -1,159 +0,0 @@ -/*! - * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) - * Copyright 2015 Aidan Feldman - * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ -(function() { - 'use strict'; - - window.Toc = { - helpers: { - // return all matching elements in the set, or their descendants - findOrFilter: function($el, selector) { - // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/ - // http://stackoverflow.com/a/12731439/358804 - var $descendants = $el.find(selector); - return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); - }, - - generateUniqueIdBase: function(el) { - var text = $(el).text(); - var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); - return anchor || el.tagName.toLowerCase(); - }, - - generateUniqueId: function(el) { - var anchorBase = this.generateUniqueIdBase(el); - for (var i = 0; ; i++) { - var anchor = anchorBase; - if (i > 0) { - // add suffix - anchor += '-' + i; - } - // check if ID already exists - if (!document.getElementById(anchor)) { - return anchor; - } - } - }, - - generateAnchor: function(el) { - if (el.id) { - return el.id; - } else { - var anchor = this.generateUniqueId(el); - el.id = anchor; - return anchor; - } - }, - - createNavList: function() { - return $(''); - }, - - createChildNavList: function($parent) { - var $childList = this.createNavList(); - $parent.append($childList); - return $childList; - }, - - generateNavEl: function(anchor, text) { - var $a = $(''); - $a.attr('href', '#' + anchor); - $a.text(text); - var $li = $('
  • '); - $li.append($a); - return $li; - }, - - generateNavItem: function(headingEl) { - var anchor = this.generateAnchor(headingEl); - var $heading = $(headingEl); - var text = $heading.data('toc-text') || $heading.text(); - return this.generateNavEl(anchor, text); - }, - - // Find the first heading level (`

    `, then `

    `, etc.) that has more than one element. Defaults to 1 (for `

    `). - getTopLevel: function($scope) { - for (var i = 1; i <= 6; i++) { - var $headings = this.findOrFilter($scope, 'h' + i); - if ($headings.length > 1) { - return i; - } - } - - return 1; - }, - - // returns the elements for the top level, and the next below it - getHeadings: function($scope, topLevel) { - var topSelector = 'h' + topLevel; - - var secondaryLevel = topLevel + 1; - var secondarySelector = 'h' + secondaryLevel; - - return this.findOrFilter($scope, topSelector + ',' + secondarySelector); - }, - - getNavLevel: function(el) { - return parseInt(el.tagName.charAt(1), 10); - }, - - populateNav: function($topContext, topLevel, $headings) { - var $context = $topContext; - var $prevNav; - - var helpers = this; - $headings.each(function(i, el) { - var $newNav = helpers.generateNavItem(el); - var navLevel = helpers.getNavLevel(el); - - // determine the proper $context - if (navLevel === topLevel) { - // use top level - $context = $topContext; - } else if ($prevNav && $context === $topContext) { - // create a new level of the tree and switch to it - $context = helpers.createChildNavList($prevNav); - } // else use the current $context - - $context.append($newNav); - - $prevNav = $newNav; - }); - }, - - parseOps: function(arg) { - var opts; - if (arg.jquery) { - opts = { - $nav: arg - }; - } else { - opts = arg; - } - opts.$scope = opts.$scope || $(document.body); - return opts; - } - }, - - // accepts a jQuery object, or an options object - init: function(opts) { - opts = this.helpers.parseOps(opts); - - // ensure that the data attribute is in place for styling - opts.$nav.attr('data-toggle', 'toc'); - - var $topContext = this.helpers.createChildNavList(opts.$nav); - var topLevel = this.helpers.getTopLevel(opts.$scope); - var $headings = this.helpers.getHeadings(opts.$scope, topLevel); - this.helpers.populateNav($topContext, topLevel, $headings); - } - }; - - $(function() { - $('nav[data-toggle="toc"]').each(function(i, el) { - var $nav = $(el); - Toc.init($nav); - }); - }); -})(); diff --git a/docs/deps/bootstrap-5.3.1/bootstrap.bundle.min.js b/docs/deps/bootstrap-5.3.1/bootstrap.bundle.min.js new file mode 100644 index 0000000..e8f21f7 --- /dev/null +++ b/docs/deps/bootstrap-5.3.1/bootstrap.bundle.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v5.3.1 (https://getbootstrap.com/) + * Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),s=t=>{t.dispatchEvent(new Event(i))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,a=t=>{if(!o(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,f=[],p=()=>"rtl"===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of f)t()})),f.push(e)):e()},g=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,_=(t,e,n=!0)=>{if(!n)return void g(t);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),g(t))};e.addEventListener(i,a),setTimeout((()=>{r||s(e)}),o)},b=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,A={};let E=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${E++}`||t.uidEvent||E++}function x(t){const e=O(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function k(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function L(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=I(t);return C.has(o)||(o=t),[n,s,o]}function S(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=L(e,i,n);if(e in T){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=x(t),c=l[a]||(l[a]={}),h=k(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=O(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return P(s,{delegateTarget:r}),n.oneOff&&N.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return P(n,{delegateTarget:t}),i.oneOff&&N.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function D(t,e,i,n,s){const o=k(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function $(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&D(t,e,i,r.callable,r.delegationSelector)}function I(t){return t=t.replace(y,""),T[t]||t}const N={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=L(e,i,n),a=r!==e,l=x(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))$(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(w,"");a&&!e.includes(s)||D(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;D(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=u();let s=null,o=!0,r=!0,a=!1;e!==I(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=P(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function P(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function M(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function j(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const F={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${j(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${j(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=M(t.dataset[n])}return e},getDataAttribute:(t,e)=>M(t.getAttribute(`data-bs-${j(e)}`))};class H{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=o(e)?F.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...o(e)?F.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[n,s]of Object.entries(e)){const e=t[n],r=o(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(r))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${r}" but expected type "${s}".`)}var i}}class W extends H{constructor(t,i){super(),(t=r(t))&&(this._element=t,this._config=this._getConfig(i),e.set(this._element,this.constructor.DATA_KEY,this))}dispose(){e.remove(this._element,this.constructor.DATA_KEY),N.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){_(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return e.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.1"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const B=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return n(e)},z={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!l(t)&&a(t)))},getSelectorFromElement(t){const e=B(t);return e&&z.findOne(e)?e:null},getElementFromSelector(t){const e=B(t);return e?z.findOne(e):null},getMultipleElementsFromSelector(t){const e=B(t);return e?z.find(e):[]}},R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;N.on(document,i,`[data-bs-dismiss="${n}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),l(this))return;const s=z.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()}))},q=".bs.alert",V=`close${q}`,K=`closed${q}`;class Q extends W{static get NAME(){return"alert"}close(){if(N.trigger(this._element,V).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),N.trigger(this._element,K),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Q.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(Q,"close"),m(Q);const X='[data-bs-toggle="button"]';class Y extends W{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=Y.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}N.on(document,"click.bs.button.data-api",X,(t=>{t.preventDefault();const e=t.target.closest(X);Y.getOrCreateInstance(e).toggle()})),m(Y);const U=".bs.swipe",G=`touchstart${U}`,J=`touchmove${U}`,Z=`touchend${U}`,tt=`pointerdown${U}`,et=`pointerup${U}`,it={endCallback:null,leftCallback:null,rightCallback:null},nt={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class st extends H{constructor(t,e){super(),this._element=t,t&&st.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return it}static get DefaultType(){return nt}static get NAME(){return"swipe"}dispose(){N.off(this._element,U)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),g(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&g(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(N.on(this._element,tt,(t=>this._start(t))),N.on(this._element,et,(t=>this._end(t))),this._element.classList.add("pointer-event")):(N.on(this._element,G,(t=>this._start(t))),N.on(this._element,J,(t=>this._move(t))),N.on(this._element,Z,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const ot=".bs.carousel",rt=".data-api",at="next",lt="prev",ct="left",ht="right",dt=`slide${ot}`,ut=`slid${ot}`,ft=`keydown${ot}`,pt=`mouseenter${ot}`,mt=`mouseleave${ot}`,gt=`dragstart${ot}`,_t=`load${ot}${rt}`,bt=`click${ot}${rt}`,vt="carousel",yt="active",wt=".active",At=".carousel-item",Et=wt+At,Tt={ArrowLeft:ht,ArrowRight:ct},Ct={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Ot={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class xt extends W{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=z.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===vt&&this.cycle()}static get Default(){return Ct}static get DefaultType(){return Ot}static get NAME(){return"carousel"}next(){this._slide(at)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(lt)}pause(){this._isSliding&&s(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?N.one(this._element,ut,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void N.one(this._element,ut,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?at:lt;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&N.on(this._element,ft,(t=>this._keydown(t))),"hover"===this._config.pause&&(N.on(this._element,pt,(()=>this.pause())),N.on(this._element,mt,(()=>this._maybeEnableCycle()))),this._config.touch&&st.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of z.find(".carousel-item img",this._element))N.on(t,gt,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(ct)),rightCallback:()=>this._slide(this._directionToOrder(ht)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new st(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Tt[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=z.findOne(wt,this._indicatorsElement);e.classList.remove(yt),e.removeAttribute("aria-current");const i=z.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(yt),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===at,s=e||b(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>N.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(dt).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),d(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(yt),i.classList.remove(yt,c,l),this._isSliding=!1,r(ut)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return z.findOne(Et,this._element)}_getItems(){return z.find(At,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===ct?lt:at:t===ct?at:lt}_orderToDirection(t){return p()?t===lt?ct:ht:t===lt?ht:ct}static jQueryInterface(t){return this.each((function(){const e=xt.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}N.on(document,bt,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=z.getElementFromSelector(this);if(!e||!e.classList.contains(vt))return;t.preventDefault();const i=xt.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===F.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),N.on(window,_t,(()=>{const t=z.find('[data-bs-ride="carousel"]');for(const e of t)xt.getOrCreateInstance(e)})),m(xt);const kt=".bs.collapse",Lt=`show${kt}`,St=`shown${kt}`,Dt=`hide${kt}`,$t=`hidden${kt}`,It=`click${kt}.data-api`,Nt="show",Pt="collapse",Mt="collapsing",jt=`:scope .${Pt} .${Pt}`,Ft='[data-bs-toggle="collapse"]',Ht={parent:null,toggle:!0},Wt={parent:"(null|element)",toggle:"boolean"};class Bt extends W{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=z.find(Ft);for(const t of i){const e=z.getSelectorFromElement(t),i=z.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Ht}static get DefaultType(){return Wt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Bt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(N.trigger(this._element,Lt).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Pt),this._element.classList.add(Mt),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Mt),this._element.classList.add(Pt,Nt),this._element.style[e]="",N.trigger(this._element,St)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(N.trigger(this._element,Dt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,d(this._element),this._element.classList.add(Mt),this._element.classList.remove(Pt,Nt);for(const t of this._triggerArray){const e=z.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Mt),this._element.classList.add(Pt),N.trigger(this._element,$t)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(Nt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=r(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Ft);for(const e of t){const t=z.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=z.find(jt,this._config.parent);return z.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Bt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}N.on(document,It,Ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of z.getMultipleElementsFromSelector(this))Bt.getOrCreateInstance(t,{toggle:!1}).toggle()})),m(Bt);var zt="top",Rt="bottom",qt="right",Vt="left",Kt="auto",Qt=[zt,Rt,qt,Vt],Xt="start",Yt="end",Ut="clippingParents",Gt="viewport",Jt="popper",Zt="reference",te=Qt.reduce((function(t,e){return t.concat([e+"-"+Xt,e+"-"+Yt])}),[]),ee=[].concat(Qt,[Kt]).reduce((function(t,e){return t.concat([e,e+"-"+Xt,e+"-"+Yt])}),[]),ie="beforeRead",ne="read",se="afterRead",oe="beforeMain",re="main",ae="afterMain",le="beforeWrite",ce="write",he="afterWrite",de=[ie,ne,se,oe,re,ae,le,ce,he];function ue(t){return t?(t.nodeName||"").toLowerCase():null}function fe(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function pe(t){return t instanceof fe(t).Element||t instanceof Element}function me(t){return t instanceof fe(t).HTMLElement||t instanceof HTMLElement}function ge(t){return"undefined"!=typeof ShadowRoot&&(t instanceof fe(t).ShadowRoot||t instanceof ShadowRoot)}const _e={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];me(s)&&ue(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});me(n)&&ue(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function be(t){return t.split("-")[0]}var ve=Math.max,ye=Math.min,we=Math.round;function Ae(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map((function(t){return t.brand+"/"+t.version})).join(" "):navigator.userAgent}function Ee(){return!/^((?!chrome|android).)*safari/i.test(Ae())}function Te(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&me(t)&&(s=t.offsetWidth>0&&we(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&we(n.height)/t.offsetHeight||1);var r=(pe(t)?fe(t):window).visualViewport,a=!Ee()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function Ce(t){var e=Te(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Oe(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&ge(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function xe(t){return fe(t).getComputedStyle(t)}function ke(t){return["table","td","th"].indexOf(ue(t))>=0}function Le(t){return((pe(t)?t.ownerDocument:t.document)||window.document).documentElement}function Se(t){return"html"===ue(t)?t:t.assignedSlot||t.parentNode||(ge(t)?t.host:null)||Le(t)}function De(t){return me(t)&&"fixed"!==xe(t).position?t.offsetParent:null}function $e(t){for(var e=fe(t),i=De(t);i&&ke(i)&&"static"===xe(i).position;)i=De(i);return i&&("html"===ue(i)||"body"===ue(i)&&"static"===xe(i).position)?e:i||function(t){var e=/firefox/i.test(Ae());if(/Trident/i.test(Ae())&&me(t)&&"fixed"===xe(t).position)return null;var i=Se(t);for(ge(i)&&(i=i.host);me(i)&&["html","body"].indexOf(ue(i))<0;){var n=xe(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Ie(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function Ne(t,e,i){return ve(t,ye(e,i))}function Pe(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function Me(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const je={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=be(i.placement),l=Ie(a),c=[Vt,qt].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return Pe("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:Me(t,Qt))}(s.padding,i),d=Ce(o),u="y"===l?zt:Vt,f="y"===l?Rt:qt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=$e(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=Ne(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Oe(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Fe(t){return t.split("-")[1]}var He={top:"auto",right:"auto",bottom:"auto",left:"auto"};function We(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u,p=r.y,m=void 0===p?0:p,g="function"==typeof h?h({x:f,y:m}):{x:f,y:m};f=g.x,m=g.y;var _=r.hasOwnProperty("x"),b=r.hasOwnProperty("y"),v=Vt,y=zt,w=window;if(c){var A=$e(i),E="clientHeight",T="clientWidth";A===fe(i)&&"static"!==xe(A=Le(i)).position&&"absolute"===a&&(E="scrollHeight",T="scrollWidth"),(s===zt||(s===Vt||s===qt)&&o===Yt)&&(y=Rt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==Vt&&(s!==zt&&s!==Rt||o!==Yt)||(v=qt,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&He),x=!0===h?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:we(i*s)/s||0,y:we(n*s)/s||0}}({x:f,y:m},fe(i)):{x:f,y:m};return f=x.x,m=x.y,l?Object.assign({},O,((C={})[y]=b?"0":"",C[v]=_?"0":"",C.transform=(w.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",C)):Object.assign({},O,((e={})[y]=b?m+"px":"",e[v]=_?f+"px":"",e.transform="",e))}const Be={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:be(e.placement),variation:Fe(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,We(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,We(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var ze={passive:!0};const Re={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=fe(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,ze)})),a&&l.addEventListener("resize",i.update,ze),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,ze)})),a&&l.removeEventListener("resize",i.update,ze)}},data:{}};var qe={left:"right",right:"left",bottom:"top",top:"bottom"};function Ve(t){return t.replace(/left|right|bottom|top/g,(function(t){return qe[t]}))}var Ke={start:"end",end:"start"};function Qe(t){return t.replace(/start|end/g,(function(t){return Ke[t]}))}function Xe(t){var e=fe(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Ye(t){return Te(Le(t)).left+Xe(t).scrollLeft}function Ue(t){var e=xe(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ge(t){return["html","body","#document"].indexOf(ue(t))>=0?t.ownerDocument.body:me(t)&&Ue(t)?t:Ge(Se(t))}function Je(t,e){var i;void 0===e&&(e=[]);var n=Ge(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=fe(n),r=s?[o].concat(o.visualViewport||[],Ue(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Je(Se(r)))}function Ze(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function ti(t,e,i){return e===Gt?Ze(function(t,e){var i=fe(t),n=Le(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Ee();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+Ye(t),y:l}}(t,i)):pe(e)?function(t,e){var i=Te(t,!1,"fixed"===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):Ze(function(t){var e,i=Le(t),n=Xe(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ve(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ve(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Ye(t),l=-n.scrollTop;return"rtl"===xe(s||i).direction&&(a+=ve(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Le(t)))}function ei(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?be(s):null,r=s?Fe(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case zt:e={x:a,y:i.y-n.height};break;case Rt:e={x:a,y:i.y+i.height};break;case qt:e={x:i.x+i.width,y:l};break;case Vt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Ie(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case Xt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Yt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ii(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.strategy,r=void 0===o?t.strategy:o,a=i.boundary,l=void 0===a?Ut:a,c=i.rootBoundary,h=void 0===c?Gt:c,d=i.elementContext,u=void 0===d?Jt:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=Pe("number"!=typeof g?g:Me(g,Qt)),b=u===Jt?Zt:Jt,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=Je(Se(t)),i=["absolute","fixed"].indexOf(xe(t).position)>=0&&me(t)?$e(t):t;return pe(i)?e.filter((function(t){return pe(t)&&Oe(t,i)&&"body"!==ue(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=ti(t,i,n);return e.top=ve(s.top,e.top),e.right=ye(s.right,e.right),e.bottom=ye(s.bottom,e.bottom),e.left=ve(s.left,e.left),e}),ti(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(pe(y)?y:y.contextElement||Le(t.elements.popper),l,h,r),A=Te(t.elements.reference),E=ei({reference:A,element:v,strategy:"absolute",placement:s}),T=Ze(Object.assign({},v,E)),C=u===Jt?T:A,O={top:w.top-C.top+_.top,bottom:C.bottom-w.bottom+_.bottom,left:w.left-C.left+_.left,right:C.right-w.right+_.right},x=t.modifiersData.offset;if(u===Jt&&x){var k=x[s];Object.keys(O).forEach((function(t){var e=[qt,Rt].indexOf(t)>=0?1:-1,i=[zt,Rt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e}))}return O}function ni(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?ee:l,h=Fe(n),d=h?a?te:te.filter((function(t){return Fe(t)===h})):Qt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ii(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[be(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const si={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=be(g),b=l||(_!==g&&p?function(t){if(be(t)===Kt)return[];var e=Ve(t);return[Qe(t),e,Qe(e)]}(g):[Ve(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(be(i)===Kt?ni(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,A=new Map,E=!0,T=v[0],C=0;C=0,S=L?"width":"height",D=ii(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),$=L?k?qt:Vt:k?Rt:zt;y[S]>w[S]&&($=Ve($));var I=Ve($),N=[];if(o&&N.push(D[x]<=0),a&&N.push(D[$]<=0,D[I]<=0),N.every((function(t){return t}))){T=O,E=!1;break}A.set(O,N)}if(E)for(var P=function(t){var e=v.find((function(e){var i=A.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==P(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function oi(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ri(t){return[zt,qt,Rt,Vt].some((function(e){return t[e]>=0}))}const ai={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ii(e,{elementContext:"reference"}),a=ii(e,{altBoundary:!0}),l=oi(r,n),c=oi(a,s,o),h=ri(l),d=ri(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},li={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=ee.reduce((function(t,i){return t[i]=function(t,e,i){var n=be(t),s=[Vt,zt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[Vt,qt].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},ci={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=ei({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},hi={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ii(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=be(e.placement),b=Fe(e.placement),v=!b,y=Ie(_),w="x"===y?"y":"x",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,O="number"==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,S="y"===y?zt:Vt,D="y"===y?Rt:qt,$="y"===y?"height":"width",I=A[y],N=I+g[S],P=I-g[D],M=f?-T[$]/2:0,j=b===Xt?E[$]:T[$],F=b===Xt?-T[$]:-E[$],H=e.elements.arrow,W=f&&H?Ce(H):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},z=B[S],R=B[D],q=Ne(0,E[$],W[$]),V=v?E[$]/2-M-q-z-O.mainAxis:j-q-z-O.mainAxis,K=v?-E[$]/2+M+q+R+O.mainAxis:F+q+R+O.mainAxis,Q=e.elements.arrow&&$e(e.elements.arrow),X=Q?"y"===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=I+K-Y,G=Ne(f?ye(N,I+V-Y-X):N,I,f?ve(P,U):P);A[y]=G,k[y]=G-I}if(a){var J,Z="x"===y?zt:Vt,tt="x"===y?Rt:qt,et=A[w],it="y"===w?"height":"width",nt=et+g[Z],st=et-g[tt],ot=-1!==[zt,Vt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=Ne(t,e,i);return n>i?i:n}(at,et,lt):Ne(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:["offset"]};function di(t,e,i){void 0===i&&(i=!1);var n,s,o=me(e),r=me(e)&&function(t){var e=t.getBoundingClientRect(),i=we(e.width)/t.offsetWidth||1,n=we(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=Le(e),l=Te(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==ue(e)||Ue(a))&&(c=(n=e)!==fe(n)&&me(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Xe(n)),me(e)?((h=Te(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Ye(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function ui(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var fi={placement:"bottom",modifiers:[],strategy:"absolute"};function pi(){for(var t=arguments.length,e=new Array(t),i=0;iNumber.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(F.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...g(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=z.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>a(t)));i.length&&b(i,e,t===Ti,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=qi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=z.find(Ni);for(const i of e){const e=qi.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Ei,Ti].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Ii)?this:z.prev(this,Ii)[0]||z.next(this,Ii)[0]||z.findOne(Ii,t.delegateTarget.parentNode),o=qi.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}N.on(document,Si,Ii,qi.dataApiKeydownHandler),N.on(document,Si,Pi,qi.dataApiKeydownHandler),N.on(document,Li,qi.clearMenus),N.on(document,Di,qi.clearMenus),N.on(document,Li,Ii,(function(t){t.preventDefault(),qi.getOrCreateInstance(this).toggle()})),m(qi);const Vi="backdrop",Ki="show",Qi=`mousedown.bs.${Vi}`,Xi={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Yi={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Ui extends H{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Xi}static get DefaultType(){return Yi}static get NAME(){return Vi}show(t){if(!this._config.isVisible)return void g(t);this._append();const e=this._getElement();this._config.isAnimated&&d(e),e.classList.add(Ki),this._emulateAnimation((()=>{g(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(Ki),this._emulateAnimation((()=>{this.dispose(),g(t)}))):g(t)}dispose(){this._isAppended&&(N.off(this._element,Qi),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=r(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),N.on(t,Qi,(()=>{g(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const Gi=".bs.focustrap",Ji=`focusin${Gi}`,Zi=`keydown.tab${Gi}`,tn="backward",en={autofocus:!0,trapElement:null},nn={autofocus:"boolean",trapElement:"element"};class sn extends H{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return en}static get DefaultType(){return nn}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),N.off(document,Gi),N.on(document,Ji,(t=>this._handleFocusin(t))),N.on(document,Zi,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,N.off(document,Gi))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=z.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===tn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?tn:"forward")}}const on=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",rn=".sticky-top",an="padding-right",ln="margin-right";class cn{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,an,(e=>e+t)),this._setElementAttributes(on,an,(e=>e+t)),this._setElementAttributes(rn,ln,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,an),this._resetElementAttributes(on,an),this._resetElementAttributes(rn,ln)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&F.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=F.getDataAttribute(t,e);null!==i?(F.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(o(t))e(t);else for(const i of z.find(t,this._element))e(i)}}const hn=".bs.modal",dn=`hide${hn}`,un=`hidePrevented${hn}`,fn=`hidden${hn}`,pn=`show${hn}`,mn=`shown${hn}`,gn=`resize${hn}`,_n=`click.dismiss${hn}`,bn=`mousedown.dismiss${hn}`,vn=`keydown.dismiss${hn}`,yn=`click${hn}.data-api`,wn="modal-open",An="show",En="modal-static",Tn={backdrop:!0,focus:!0,keyboard:!0},Cn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class On extends W{constructor(t,e){super(t,e),this._dialog=z.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new cn,this._addEventListeners()}static get Default(){return Tn}static get DefaultType(){return Cn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||N.trigger(this._element,pn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(wn),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(N.trigger(this._element,dn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(An),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){N.off(window,hn),N.off(this._dialog,hn),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Ui({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=z.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),d(this._element),this._element.classList.add(An),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,N.trigger(this._element,mn,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){N.on(this._element,vn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),N.on(window,gn,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),N.on(this._element,bn,(t=>{N.one(this._element,_n,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(wn),this._resetAdjustments(),this._scrollBar.reset(),N.trigger(this._element,fn)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(N.trigger(this._element,un).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(En)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(En),this._queueCallback((()=>{this._element.classList.remove(En),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=On.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}N.on(document,yn,'[data-bs-toggle="modal"]',(function(t){const e=z.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),N.one(e,pn,(t=>{t.defaultPrevented||N.one(e,fn,(()=>{a(this)&&this.focus()}))}));const i=z.findOne(".modal.show");i&&On.getInstance(i).hide(),On.getOrCreateInstance(e).toggle(this)})),R(On),m(On);const xn=".bs.offcanvas",kn=".data-api",Ln=`load${xn}${kn}`,Sn="show",Dn="showing",$n="hiding",In=".offcanvas.show",Nn=`show${xn}`,Pn=`shown${xn}`,Mn=`hide${xn}`,jn=`hidePrevented${xn}`,Fn=`hidden${xn}`,Hn=`resize${xn}`,Wn=`click${xn}${kn}`,Bn=`keydown.dismiss${xn}`,zn={backdrop:!0,keyboard:!0,scroll:!1},Rn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class qn extends W{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return zn}static get DefaultType(){return Rn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||N.trigger(this._element,Nn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new cn).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(Dn),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(Sn),this._element.classList.remove(Dn),N.trigger(this._element,Pn,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(N.trigger(this._element,Mn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add($n),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(Sn,$n),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new cn).reset(),N.trigger(this._element,Fn)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Ui({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():N.trigger(this._element,jn)}:null})}_initializeFocusTrap(){return new sn({trapElement:this._element})}_addEventListeners(){N.on(this._element,Bn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():N.trigger(this._element,jn))}))}static jQueryInterface(t){return this.each((function(){const e=qn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}N.on(document,Wn,'[data-bs-toggle="offcanvas"]',(function(t){const e=z.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this))return;N.one(e,Fn,(()=>{a(this)&&this.focus()}));const i=z.findOne(In);i&&i!==e&&qn.getInstance(i).hide(),qn.getOrCreateInstance(e).toggle(this)})),N.on(window,Ln,(()=>{for(const t of z.find(In))qn.getOrCreateInstance(t).show()})),N.on(window,Hn,(()=>{for(const t of z.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&qn.getOrCreateInstance(t).hide()})),R(qn),m(qn);const Vn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Kn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Qn=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Xn=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Kn.has(i)||Boolean(Qn.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Yn={allowList:Vn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
    "},Un={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Gn={entry:"(string|element|function|null)",selector:"(string|element)"};class Jn extends H{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Yn}static get DefaultType(){return Un}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Gn)}_setContent(t,e,i){const n=z.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?o(e)?this._putElementInTemplate(r(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)Xn(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return g(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const Zn=new Set(["sanitize","allowList","sanitizeFn"]),ts="fade",es="show",is=".modal",ns="hide.bs.modal",ss="hover",os="focus",rs={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},as={allowList:Vn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},ls={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class cs extends W{constructor(t,e){if(void 0===vi)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return as}static get DefaultType(){return ls}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),N.off(this._element.closest(is),ns,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=N.trigger(this._element,this.constructor.eventName("show")),e=(c(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),N.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.on(t,"mouseover",h);this._queueCallback((()=>{N.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!N.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(es),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))N.off(t,"mouseover",h);this._activeTrigger.click=!1,this._activeTrigger[os]=!1,this._activeTrigger[ss]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),N.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(ts,es),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(ts),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Jn({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{".tooltip-inner":this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(ts)}_isShown(){return this.tip&&this.tip.classList.contains(es)}_createPopper(t){const e=g(this._config.placement,[this,t,this._element]),i=rs[e.toUpperCase()];return bi(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return g(t,[this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...g(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)N.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===ss?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===ss?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");N.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?os:ss]=!0,e._enter()})),N.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?os:ss]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},N.on(this._element.closest(is),ns,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=F.getDataAttributes(this._element);for(const t of Object.keys(e))Zn.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=cs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(cs);const hs={...cs.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},ds={...cs.DefaultType,content:"(null|string|element|function)"};class us extends cs{static get Default(){return hs}static get DefaultType(){return ds}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{".popover-header":this._getTitle(),".popover-body":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=us.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(us);const fs=".bs.scrollspy",ps=`activate${fs}`,ms=`click${fs}`,gs=`load${fs}.data-api`,_s="active",bs="[href]",vs=".nav-link",ys=`${vs}, .nav-item > ${vs}, .list-group-item`,ws={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},As={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Es extends W{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return ws}static get DefaultType(){return As}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=r(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(N.off(this._config.target,ms),N.on(this._config.target,ms,bs,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=z.find(bs,this._config.target);for(const e of t){if(!e.hash||l(e))continue;const t=z.findOne(decodeURI(e.hash),this._element);a(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(_s),this._activateParents(t),N.trigger(this._element,ps,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))z.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(_s);else for(const e of z.parents(t,".nav, .list-group"))for(const t of z.prev(e,ys))t.classList.add(_s)}_clearActiveClass(t){t.classList.remove(_s);const e=z.find(`${bs}.${_s}`,t);for(const t of e)t.classList.remove(_s)}static jQueryInterface(t){return this.each((function(){const e=Es.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(window,gs,(()=>{for(const t of z.find('[data-bs-spy="scroll"]'))Es.getOrCreateInstance(t)})),m(Es);const Ts=".bs.tab",Cs=`hide${Ts}`,Os=`hidden${Ts}`,xs=`show${Ts}`,ks=`shown${Ts}`,Ls=`click${Ts}`,Ss=`keydown${Ts}`,Ds=`load${Ts}`,$s="ArrowLeft",Is="ArrowRight",Ns="ArrowUp",Ps="ArrowDown",Ms="Home",js="End",Fs="active",Hs="fade",Ws="show",Bs=":not(.dropdown-toggle)",zs='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',Rs=`.nav-link${Bs}, .list-group-item${Bs}, [role="tab"]${Bs}, ${zs}`,qs=`.${Fs}[data-bs-toggle="tab"], .${Fs}[data-bs-toggle="pill"], .${Fs}[data-bs-toggle="list"]`;class Vs extends W{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),N.on(this._element,Ss,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?N.trigger(e,Cs,{relatedTarget:t}):null;N.trigger(t,xs,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(Fs),this._activate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),N.trigger(t,ks,{relatedTarget:e})):t.classList.add(Ws)}),t,t.classList.contains(Hs)))}_deactivate(t,e){t&&(t.classList.remove(Fs),t.blur(),this._deactivate(z.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),N.trigger(t,Os,{relatedTarget:e})):t.classList.remove(Ws)}),t,t.classList.contains(Hs)))}_keydown(t){if(![$s,Is,Ns,Ps,Ms,js].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!l(t)));let i;if([Ms,js].includes(t.key))i=e[t.key===Ms?0:e.length-1];else{const n=[Is,Ps].includes(t.key);i=b(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Vs.getOrCreateInstance(i).show())}_getChildren(){return z.find(Rs,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=z.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=z.findOne(t,i);s&&s.classList.toggle(n,e)};n(".dropdown-toggle",Fs),n(".dropdown-menu",Ws),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(Fs)}_getInnerElement(t){return t.matches(Rs)?t:z.findOne(Rs,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=Vs.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}N.on(document,Ls,zs,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this)||Vs.getOrCreateInstance(this).show()})),N.on(window,Ds,(()=>{for(const t of z.find(qs))Vs.getOrCreateInstance(t)})),m(Vs);const Ks=".bs.toast",Qs=`mouseover${Ks}`,Xs=`mouseout${Ks}`,Ys=`focusin${Ks}`,Us=`focusout${Ks}`,Gs=`hide${Ks}`,Js=`hidden${Ks}`,Zs=`show${Ks}`,to=`shown${Ks}`,eo="hide",io="show",no="showing",so={animation:"boolean",autohide:"boolean",delay:"number"},oo={animation:!0,autohide:!0,delay:5e3};class ro extends W{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return oo}static get DefaultType(){return so}static get NAME(){return"toast"}show(){N.trigger(this._element,Zs).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(eo),d(this._element),this._element.classList.add(io,no),this._queueCallback((()=>{this._element.classList.remove(no),N.trigger(this._element,to),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(N.trigger(this._element,Gs).defaultPrevented||(this._element.classList.add(no),this._queueCallback((()=>{this._element.classList.add(eo),this._element.classList.remove(no,io),N.trigger(this._element,Js)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(io),super.dispose()}isShown(){return this._element.classList.contains(io)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){N.on(this._element,Qs,(t=>this._onInteraction(t,!0))),N.on(this._element,Xs,(t=>this._onInteraction(t,!1))),N.on(this._element,Ys,(t=>this._onInteraction(t,!0))),N.on(this._element,Us,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=ro.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(ro),m(ro),{Alert:Q,Button:Y,Carousel:xt,Collapse:Bt,Dropdown:qi,Modal:On,Offcanvas:qn,Popover:us,ScrollSpy:Es,Tab:Vs,Toast:ro,Tooltip:cs}})); +//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/docs/deps/bootstrap-5.3.1/bootstrap.bundle.min.js.map b/docs/deps/bootstrap-5.3.1/bootstrap.bundle.min.js.map new file mode 100644 index 0000000..3863da8 --- /dev/null +++ b/docs/deps/bootstrap-5.3.1/bootstrap.bundle.min.js.map @@ -0,0 +1 @@ +{"version":3,"names":["elementMap","Map","Data","set","element","key","instance","has","instanceMap","get","size","console","error","Array","from","keys","remove","delete","TRANSITION_END","parseSelector","selector","window","CSS","escape","replace","match","id","triggerTransitionEnd","dispatchEvent","Event","isElement","object","jquery","nodeType","getElement","length","document","querySelector","isVisible","getClientRects","elementIsVisible","getComputedStyle","getPropertyValue","closedDetails","closest","summary","parentNode","isDisabled","Node","ELEMENT_NODE","classList","contains","disabled","hasAttribute","getAttribute","findShadowRoot","documentElement","attachShadow","getRootNode","root","ShadowRoot","noop","reflow","offsetHeight","getjQuery","jQuery","body","DOMContentLoadedCallbacks","isRTL","dir","defineJQueryPlugin","plugin","callback","$","name","NAME","JQUERY_NO_CONFLICT","fn","jQueryInterface","Constructor","noConflict","readyState","addEventListener","push","execute","possibleCallback","args","defaultValue","executeAfterTransition","transitionElement","waitForTransition","emulatedDuration","transitionDuration","transitionDelay","floatTransitionDuration","Number","parseFloat","floatTransitionDelay","split","getTransitionDurationFromElement","called","handler","target","removeEventListener","setTimeout","getNextActiveElement","list","activeElement","shouldGetNext","isCycleAllowed","listLength","index","indexOf","Math","max","min","namespaceRegex","stripNameRegex","stripUidRegex","eventRegistry","uidEvent","customEvents","mouseenter","mouseleave","nativeEvents","Set","makeEventUid","uid","getElementEvents","findHandler","events","callable","delegationSelector","Object","values","find","event","normalizeParameters","originalTypeEvent","delegationFunction","isDelegated","typeEvent","getTypeEvent","addHandler","oneOff","wrapFunction","relatedTarget","delegateTarget","call","this","handlers","previousFunction","domElements","querySelectorAll","domElement","hydrateObj","EventHandler","off","type","apply","bootstrapDelegationHandler","bootstrapHandler","removeHandler","Boolean","removeNamespacedHandlers","namespace","storeElementEvent","handlerKey","entries","includes","on","one","inNamespace","isNamespace","startsWith","elementEvent","slice","keyHandlers","trigger","jQueryEvent","bubbles","nativeDispatch","defaultPrevented","isPropagationStopped","isImmediatePropagationStopped","isDefaultPrevented","evt","cancelable","preventDefault","obj","meta","value","_unused","defineProperty","configurable","normalizeData","toString","JSON","parse","decodeURIComponent","normalizeDataKey","chr","toLowerCase","Manipulator","setDataAttribute","setAttribute","removeDataAttribute","removeAttribute","getDataAttributes","attributes","bsKeys","dataset","filter","pureKey","charAt","getDataAttribute","Config","Default","DefaultType","Error","_getConfig","config","_mergeConfigObj","_configAfterMerge","_typeCheckConfig","jsonConfig","constructor","configTypes","property","expectedTypes","valueType","prototype","RegExp","test","TypeError","toUpperCase","BaseComponent","super","_element","_config","DATA_KEY","dispose","EVENT_KEY","propertyName","getOwnPropertyNames","_queueCallback","isAnimated","getInstance","getOrCreateInstance","VERSION","eventName","getSelector","hrefAttribute","trim","SelectorEngine","concat","Element","findOne","children","child","matches","parents","ancestor","prev","previous","previousElementSibling","next","nextElementSibling","focusableChildren","focusables","map","join","el","getSelectorFromElement","getElementFromSelector","getMultipleElementsFromSelector","enableDismissTrigger","component","method","clickEvent","tagName","EVENT_CLOSE","EVENT_CLOSED","Alert","close","_destroyElement","each","data","undefined","SELECTOR_DATA_TOGGLE","Button","toggle","button","EVENT_TOUCHSTART","EVENT_TOUCHMOVE","EVENT_TOUCHEND","EVENT_POINTERDOWN","EVENT_POINTERUP","endCallback","leftCallback","rightCallback","Swipe","isSupported","_deltaX","_supportPointerEvents","PointerEvent","_initEvents","_start","_eventIsPointerPenTouch","clientX","touches","_end","_handleSwipe","_move","absDeltaX","abs","direction","add","pointerType","navigator","maxTouchPoints","DATA_API_KEY","ORDER_NEXT","ORDER_PREV","DIRECTION_LEFT","DIRECTION_RIGHT","EVENT_SLIDE","EVENT_SLID","EVENT_KEYDOWN","EVENT_MOUSEENTER","EVENT_MOUSELEAVE","EVENT_DRAG_START","EVENT_LOAD_DATA_API","EVENT_CLICK_DATA_API","CLASS_NAME_CAROUSEL","CLASS_NAME_ACTIVE","SELECTOR_ACTIVE","SELECTOR_ITEM","SELECTOR_ACTIVE_ITEM","KEY_TO_DIRECTION","ArrowLeft","ArrowRight","interval","keyboard","pause","ride","touch","wrap","Carousel","_interval","_activeElement","_isSliding","touchTimeout","_swipeHelper","_indicatorsElement","_addEventListeners","cycle","_slide","nextWhenVisible","hidden","_clearInterval","_updateInterval","setInterval","_maybeEnableCycle","to","items","_getItems","activeIndex","_getItemIndex","_getActive","order","defaultInterval","_keydown","_addTouchEventListeners","img","swipeConfig","_directionToOrder","endCallBack","clearTimeout","_setActiveIndicatorElement","activeIndicator","newActiveIndicator","elementInterval","parseInt","isNext","nextElement","nextElementIndex","triggerEvent","_orderToDirection","isCycling","directionalClassName","orderClassName","completeCallBack","_isAnimated","clearInterval","carousel","slideIndex","carousels","EVENT_SHOW","EVENT_SHOWN","EVENT_HIDE","EVENT_HIDDEN","CLASS_NAME_SHOW","CLASS_NAME_COLLAPSE","CLASS_NAME_COLLAPSING","CLASS_NAME_DEEPER_CHILDREN","parent","Collapse","_isTransitioning","_triggerArray","toggleList","elem","filterElement","foundElement","_initializeChildren","_addAriaAndCollapsedClass","_isShown","hide","show","activeChildren","_getFirstLevelChildren","activeInstance","dimension","_getDimension","style","scrollSize","complete","getBoundingClientRect","selected","triggerArray","isOpen","top","bottom","right","left","auto","basePlacements","start","end","clippingParents","viewport","popper","reference","variationPlacements","reduce","acc","placement","placements","beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite","modifierPhases","getNodeName","nodeName","getWindow","node","ownerDocument","defaultView","isHTMLElement","HTMLElement","isShadowRoot","applyStyles$1","enabled","phase","_ref","state","elements","forEach","styles","assign","effect","_ref2","initialStyles","position","options","strategy","margin","arrow","hasOwnProperty","attribute","requires","getBasePlacement","round","getUAString","uaData","userAgentData","brands","isArray","item","brand","version","userAgent","isLayoutViewport","includeScale","isFixedStrategy","clientRect","scaleX","scaleY","offsetWidth","width","height","visualViewport","addVisualOffsets","x","offsetLeft","y","offsetTop","getLayoutRect","rootNode","isSameNode","host","isTableElement","getDocumentElement","getParentNode","assignedSlot","getTrueOffsetParent","offsetParent","getOffsetParent","isFirefox","currentNode","css","transform","perspective","contain","willChange","getContainingBlock","getMainAxisFromPlacement","within","mathMax","mathMin","mergePaddingObject","paddingObject","expandToHashMap","hashMap","arrow$1","_state$modifiersData$","arrowElement","popperOffsets","modifiersData","basePlacement","axis","len","padding","rects","toPaddingObject","arrowRect","minProp","maxProp","endDiff","startDiff","arrowOffsetParent","clientSize","clientHeight","clientWidth","centerToReference","center","offset","axisProp","centerOffset","_options$element","requiresIfExists","getVariation","unsetSides","mapToStyles","_Object$assign2","popperRect","variation","offsets","gpuAcceleration","adaptive","roundOffsets","isFixed","_offsets$x","_offsets$y","_ref3","hasX","hasY","sideX","sideY","win","heightProp","widthProp","_Object$assign","commonStyles","_ref4","dpr","devicePixelRatio","roundOffsetsByDPR","computeStyles$1","_ref5","_options$gpuAccelerat","_options$adaptive","_options$roundOffsets","passive","eventListeners","_options$scroll","scroll","_options$resize","resize","scrollParents","scrollParent","update","hash","getOppositePlacement","matched","getOppositeVariationPlacement","getWindowScroll","scrollLeft","pageXOffset","scrollTop","pageYOffset","getWindowScrollBarX","isScrollParent","_getComputedStyle","overflow","overflowX","overflowY","getScrollParent","listScrollParents","_element$ownerDocumen","isBody","updatedList","rectToClientRect","rect","getClientRectFromMixedType","clippingParent","html","layoutViewport","getViewportRect","clientTop","clientLeft","getInnerBoundingClientRect","winScroll","scrollWidth","scrollHeight","getDocumentRect","computeOffsets","commonX","commonY","mainAxis","detectOverflow","_options","_options$placement","_options$strategy","_options$boundary","boundary","_options$rootBoundary","rootBoundary","_options$elementConte","elementContext","_options$altBoundary","altBoundary","_options$padding","altContext","clippingClientRect","mainClippingParents","clipperElement","getClippingParents","firstClippingParent","clippingRect","accRect","getClippingRect","contextElement","referenceClientRect","popperClientRect","elementClientRect","overflowOffsets","offsetData","multiply","computeAutoPlacement","flipVariations","_options$allowedAutoP","allowedAutoPlacements","allPlacements","allowedPlacements","overflows","sort","a","b","flip$1","_skip","_options$mainAxis","checkMainAxis","_options$altAxis","altAxis","checkAltAxis","specifiedFallbackPlacements","fallbackPlacements","_options$flipVariatio","preferredPlacement","oppositePlacement","getExpandedFallbackPlacements","referenceRect","checksMap","makeFallbackChecks","firstFittingPlacement","i","_basePlacement","isStartVariation","isVertical","mainVariationSide","altVariationSide","checks","every","check","_loop","_i","fittingPlacement","reset","getSideOffsets","preventedOffsets","isAnySideFullyClipped","some","side","hide$1","preventOverflow","referenceOverflow","popperAltOverflow","referenceClippingOffsets","popperEscapeOffsets","isReferenceHidden","hasPopperEscaped","offset$1","_options$offset","invertDistance","skidding","distance","distanceAndSkiddingToXY","_data$state$placement","popperOffsets$1","preventOverflow$1","_options$tether","tether","_options$tetherOffset","tetherOffset","isBasePlacement","tetherOffsetValue","normalizedTetherOffsetValue","offsetModifierState","_offsetModifierState$","mainSide","altSide","additive","minLen","maxLen","arrowPaddingObject","arrowPaddingMin","arrowPaddingMax","arrowLen","minOffset","maxOffset","clientOffset","offsetModifierValue","tetherMax","preventedOffset","_offsetModifierState$2","_mainSide","_altSide","_offset","_len","_min","_max","isOriginSide","_offsetModifierValue","_tetherMin","_tetherMax","_preventedOffset","v","withinMaxClamp","getCompositeRect","elementOrVirtualElement","isOffsetParentAnElement","offsetParentIsScaled","isElementScaled","modifiers","visited","result","modifier","dep","depModifier","DEFAULT_OPTIONS","areValidElements","arguments","_key","popperGenerator","generatorOptions","_generatorOptions","_generatorOptions$def","defaultModifiers","_generatorOptions$def2","defaultOptions","pending","orderedModifiers","effectCleanupFns","isDestroyed","setOptions","setOptionsAction","cleanupModifierEffects","merged","orderModifiers","current","existing","m","_ref$options","cleanupFn","forceUpdate","_state$elements","_state$orderedModifie","_state$orderedModifie2","Promise","resolve","then","destroy","onFirstUpdate","createPopper","computeStyles","applyStyles","flip","ARROW_UP_KEY","ARROW_DOWN_KEY","EVENT_KEYDOWN_DATA_API","EVENT_KEYUP_DATA_API","SELECTOR_DATA_TOGGLE_SHOWN","SELECTOR_MENU","PLACEMENT_TOP","PLACEMENT_TOPEND","PLACEMENT_BOTTOM","PLACEMENT_BOTTOMEND","PLACEMENT_RIGHT","PLACEMENT_LEFT","autoClose","display","popperConfig","Dropdown","_popper","_parent","_menu","_inNavbar","_detectNavbar","_createPopper","focus","_completeHide","Popper","referenceElement","_getPopperConfig","_getPlacement","parentDropdown","isEnd","_getOffset","popperData","defaultBsPopperConfig","_selectMenuItem","clearMenus","openToggles","context","composedPath","isMenuTarget","dataApiKeydownHandler","isInput","isEscapeEvent","isUpOrDownEvent","getToggleButton","stopPropagation","EVENT_MOUSEDOWN","className","clickCallback","rootElement","Backdrop","_isAppended","_append","_getElement","_emulateAnimation","backdrop","createElement","append","EVENT_FOCUSIN","EVENT_KEYDOWN_TAB","TAB_NAV_BACKWARD","autofocus","trapElement","FocusTrap","_isActive","_lastTabNavDirection","activate","_handleFocusin","_handleKeydown","deactivate","shiftKey","SELECTOR_FIXED_CONTENT","SELECTOR_STICKY_CONTENT","PROPERTY_PADDING","PROPERTY_MARGIN","ScrollBarHelper","getWidth","documentWidth","innerWidth","_disableOverFlow","_setElementAttributes","calculatedValue","_resetElementAttributes","isOverflowing","_saveInitialAttribute","styleProperty","scrollbarWidth","_applyManipulationCallback","setProperty","actualValue","removeProperty","callBack","sel","EVENT_HIDE_PREVENTED","EVENT_RESIZE","EVENT_CLICK_DISMISS","EVENT_MOUSEDOWN_DISMISS","EVENT_KEYDOWN_DISMISS","CLASS_NAME_OPEN","CLASS_NAME_STATIC","Modal","_dialog","_backdrop","_initializeBackDrop","_focustrap","_initializeFocusTrap","_scrollBar","_adjustDialog","_showElement","_hideModal","handleUpdate","modalBody","transitionComplete","_triggerBackdropTransition","event2","_resetAdjustments","isModalOverflowing","initialOverflowY","isBodyOverflowing","paddingLeft","paddingRight","showEvent","alreadyOpen","CLASS_NAME_SHOWING","CLASS_NAME_HIDING","OPEN_SELECTOR","Offcanvas","blur","completeCallback","DefaultAllowlist","area","br","col","code","div","em","hr","h1","h2","h3","h4","h5","h6","li","ol","p","pre","s","small","span","sub","sup","strong","u","ul","uriAttributes","SAFE_URL_PATTERN","allowedAttribute","allowedAttributeList","attributeName","nodeValue","attributeRegex","regex","allowList","content","extraClass","sanitize","sanitizeFn","template","DefaultContentType","entry","TemplateFactory","getContent","_resolvePossibleFunction","hasContent","changeContent","_checkContent","toHtml","templateWrapper","innerHTML","_maybeSanitize","text","_setContent","arg","templateElement","_putElementInTemplate","textContent","unsafeHtml","sanitizeFunction","createdDocument","DOMParser","parseFromString","elementName","attributeList","allowedAttributes","sanitizeHtml","DISALLOWED_ATTRIBUTES","CLASS_NAME_FADE","SELECTOR_MODAL","EVENT_MODAL_HIDE","TRIGGER_HOVER","TRIGGER_FOCUS","AttachmentMap","AUTO","TOP","RIGHT","BOTTOM","LEFT","animation","container","customClass","delay","title","Tooltip","_isEnabled","_timeout","_isHovered","_activeTrigger","_templateFactory","_newContent","tip","_setListeners","_fixTitle","enable","disable","toggleEnabled","click","_leave","_enter","_hideModalHandler","_disposePopper","_isWithContent","isInTheDom","_getTipElement","_isWithActiveTrigger","_getTitle","_createTipElement","_getContentForTemplate","_getTemplateFactory","tipId","prefix","floor","random","getElementById","getUID","setContent","_initializeOnDelegatedTarget","_getDelegateConfig","attachment","triggers","eventIn","eventOut","_setTimeout","timeout","dataAttributes","dataAttribute","Popover","_getContent","EVENT_ACTIVATE","EVENT_CLICK","SELECTOR_TARGET_LINKS","SELECTOR_NAV_LINKS","SELECTOR_LINK_ITEMS","rootMargin","smoothScroll","threshold","ScrollSpy","_targetLinks","_observableSections","_rootElement","_activeTarget","_observer","_previousScrollData","visibleEntryTop","parentScrollTop","refresh","_initializeTargetsAndObservables","_maybeEnableSmoothScroll","disconnect","_getNewObserver","section","observe","observableSection","scrollTo","behavior","IntersectionObserver","_observerCallback","targetElement","_process","userScrollsDown","isIntersecting","_clearActiveClass","entryIsLowerThanPrevious","targetLinks","anchor","decodeURI","_activateParents","listGroup","activeNodes","spy","ARROW_LEFT_KEY","ARROW_RIGHT_KEY","HOME_KEY","END_KEY","NOT_SELECTOR_DROPDOWN_TOGGLE","SELECTOR_INNER_ELEM","SELECTOR_DATA_TOGGLE_ACTIVE","Tab","_setInitialAttributes","_getChildren","innerElem","_elemIsActive","active","_getActiveElem","hideEvent","_deactivate","_activate","relatedElem","_toggleDropDown","nextActiveElement","preventScroll","_setAttributeIfNotExists","_setInitialAttributesOnChild","_getInnerElement","isActive","outerElem","_getOuterElement","_setInitialAttributesOnTargetPanel","open","EVENT_MOUSEOVER","EVENT_MOUSEOUT","EVENT_FOCUSOUT","CLASS_NAME_HIDE","autohide","Toast","_hasMouseInteraction","_hasKeyboardInteraction","_clearTimeout","_maybeScheduleHide","isShown","_onInteraction","isInteracting"],"sources":["../../js/src/dom/data.js","../../js/src/util/index.js","../../js/src/dom/event-handler.js","../../js/src/dom/manipulator.js","../../js/src/util/config.js","../../js/src/base-component.js","../../js/src/dom/selector-engine.js","../../js/src/util/component-functions.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/util/swipe.js","../../js/src/carousel.js","../../js/src/collapse.js","../../node_modules/@popperjs/core/lib/enums.js","../../node_modules/@popperjs/core/lib/dom-utils/getNodeName.js","../../node_modules/@popperjs/core/lib/dom-utils/getWindow.js","../../node_modules/@popperjs/core/lib/dom-utils/instanceOf.js","../../node_modules/@popperjs/core/lib/modifiers/applyStyles.js","../../node_modules/@popperjs/core/lib/utils/getBasePlacement.js","../../node_modules/@popperjs/core/lib/utils/math.js","../../node_modules/@popperjs/core/lib/utils/userAgent.js","../../node_modules/@popperjs/core/lib/dom-utils/isLayoutViewport.js","../../node_modules/@popperjs/core/lib/dom-utils/getBoundingClientRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getLayoutRect.js","../../node_modules/@popperjs/core/lib/dom-utils/contains.js","../../node_modules/@popperjs/core/lib/dom-utils/getComputedStyle.js","../../node_modules/@popperjs/core/lib/dom-utils/isTableElement.js","../../node_modules/@popperjs/core/lib/dom-utils/getDocumentElement.js","../../node_modules/@popperjs/core/lib/dom-utils/getParentNode.js","../../node_modules/@popperjs/core/lib/dom-utils/getOffsetParent.js","../../node_modules/@popperjs/core/lib/utils/getMainAxisFromPlacement.js","../../node_modules/@popperjs/core/lib/utils/within.js","../../node_modules/@popperjs/core/lib/utils/mergePaddingObject.js","../../node_modules/@popperjs/core/lib/utils/getFreshSideObject.js","../../node_modules/@popperjs/core/lib/utils/expandToHashMap.js","../../node_modules/@popperjs/core/lib/modifiers/arrow.js","../../node_modules/@popperjs/core/lib/utils/getVariation.js","../../node_modules/@popperjs/core/lib/modifiers/computeStyles.js","../../node_modules/@popperjs/core/lib/modifiers/eventListeners.js","../../node_modules/@popperjs/core/lib/utils/getOppositePlacement.js","../../node_modules/@popperjs/core/lib/utils/getOppositeVariationPlacement.js","../../node_modules/@popperjs/core/lib/dom-utils/getWindowScroll.js","../../node_modules/@popperjs/core/lib/dom-utils/getWindowScrollBarX.js","../../node_modules/@popperjs/core/lib/dom-utils/isScrollParent.js","../../node_modules/@popperjs/core/lib/dom-utils/getScrollParent.js","../../node_modules/@popperjs/core/lib/dom-utils/listScrollParents.js","../../node_modules/@popperjs/core/lib/utils/rectToClientRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getClippingRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getViewportRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getDocumentRect.js","../../node_modules/@popperjs/core/lib/utils/computeOffsets.js","../../node_modules/@popperjs/core/lib/utils/detectOverflow.js","../../node_modules/@popperjs/core/lib/utils/computeAutoPlacement.js","../../node_modules/@popperjs/core/lib/modifiers/flip.js","../../node_modules/@popperjs/core/lib/modifiers/hide.js","../../node_modules/@popperjs/core/lib/modifiers/offset.js","../../node_modules/@popperjs/core/lib/modifiers/popperOffsets.js","../../node_modules/@popperjs/core/lib/modifiers/preventOverflow.js","../../node_modules/@popperjs/core/lib/utils/getAltAxis.js","../../node_modules/@popperjs/core/lib/dom-utils/getCompositeRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getNodeScroll.js","../../node_modules/@popperjs/core/lib/dom-utils/getHTMLElementScroll.js","../../node_modules/@popperjs/core/lib/utils/orderModifiers.js","../../node_modules/@popperjs/core/lib/createPopper.js","../../node_modules/@popperjs/core/lib/utils/debounce.js","../../node_modules/@popperjs/core/lib/utils/mergeByName.js","../../node_modules/@popperjs/core/lib/popper-lite.js","../../node_modules/@popperjs/core/lib/popper.js","../../js/src/dropdown.js","../../js/src/util/backdrop.js","../../js/src/util/focustrap.js","../../js/src/util/scrollbar.js","../../js/src/modal.js","../../js/src/offcanvas.js","../../js/src/util/sanitizer.js","../../js/src/util/template-factory.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/toast.js","../../js/index.umd.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * Constants\n */\n\nconst elementMap = new Map()\n\nexport default {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map())\n }\n\n const instanceMap = elementMap.get(element)\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)\n return\n }\n\n instanceMap.set(key, instance)\n },\n\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null\n }\n\n return null\n },\n\n remove(element, key) {\n if (!elementMap.has(element)) {\n return\n }\n\n const instanceMap = elementMap.get(element)\n\n instanceMap.delete(key)\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element)\n }\n }\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst MAX_UID = 1_000_000\nconst MILLISECONDS_MULTIPLIER = 1000\nconst TRANSITION_END = 'transitionend'\n\n/**\n * Properly escape IDs selectors to handle weird IDs\n * @param {string} selector\n * @returns {string}\n */\nconst parseSelector = selector => {\n if (selector && window.CSS && window.CSS.escape) {\n // document.querySelector needs escaping to handle IDs (html5+) containing for instance /\n selector = selector.replace(/#([^\\s\"#']+)/g, (match, id) => `#${CSS.escape(id)}`)\n }\n\n return selector\n}\n\n// Shout-out Angus Croll (https://goo.gl/pxwQGp)\nconst toType = object => {\n if (object === null || object === undefined) {\n return `${object}`\n }\n\n return Object.prototype.toString.call(object).match(/\\s([a-z]+)/i)[1].toLowerCase()\n}\n\n/**\n * Public Util API\n */\n\nconst getUID = prefix => {\n do {\n prefix += Math.floor(Math.random() * MAX_UID)\n } while (document.getElementById(prefix))\n\n return prefix\n}\n\nconst getTransitionDurationFromElement = element => {\n if (!element) {\n return 0\n }\n\n // Get transition-duration of the element\n let { transitionDuration, transitionDelay } = window.getComputedStyle(element)\n\n const floatTransitionDuration = Number.parseFloat(transitionDuration)\n const floatTransitionDelay = Number.parseFloat(transitionDelay)\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0]\n transitionDelay = transitionDelay.split(',')[0]\n\n return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER\n}\n\nconst triggerTransitionEnd = element => {\n element.dispatchEvent(new Event(TRANSITION_END))\n}\n\nconst isElement = object => {\n if (!object || typeof object !== 'object') {\n return false\n }\n\n if (typeof object.jquery !== 'undefined') {\n object = object[0]\n }\n\n return typeof object.nodeType !== 'undefined'\n}\n\nconst getElement = object => {\n // it's a jQuery object or a node element\n if (isElement(object)) {\n return object.jquery ? object[0] : object\n }\n\n if (typeof object === 'string' && object.length > 0) {\n return document.querySelector(parseSelector(object))\n }\n\n return null\n}\n\nconst isVisible = element => {\n if (!isElement(element) || element.getClientRects().length === 0) {\n return false\n }\n\n const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'\n // Handle `details` element as its content may falsie appear visible when it is closed\n const closedDetails = element.closest('details:not([open])')\n\n if (!closedDetails) {\n return elementIsVisible\n }\n\n if (closedDetails !== element) {\n const summary = element.closest('summary')\n if (summary && summary.parentNode !== closedDetails) {\n return false\n }\n\n if (summary === null) {\n return false\n }\n }\n\n return elementIsVisible\n}\n\nconst isDisabled = element => {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true\n }\n\n if (element.classList.contains('disabled')) {\n return true\n }\n\n if (typeof element.disabled !== 'undefined') {\n return element.disabled\n }\n\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'\n}\n\nconst findShadowRoot = element => {\n if (!document.documentElement.attachShadow) {\n return null\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode()\n return root instanceof ShadowRoot ? root : null\n }\n\n if (element instanceof ShadowRoot) {\n return element\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null\n }\n\n return findShadowRoot(element.parentNode)\n}\n\nconst noop = () => {}\n\n/**\n * Trick to restart an element's animation\n *\n * @param {HTMLElement} element\n * @return void\n *\n * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n */\nconst reflow = element => {\n element.offsetHeight // eslint-disable-line no-unused-expressions\n}\n\nconst getjQuery = () => {\n if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n return window.jQuery\n }\n\n return null\n}\n\nconst DOMContentLoadedCallbacks = []\n\nconst onDOMContentLoaded = callback => {\n if (document.readyState === 'loading') {\n // add listener on the first call when the document is in loading state\n if (!DOMContentLoadedCallbacks.length) {\n document.addEventListener('DOMContentLoaded', () => {\n for (const callback of DOMContentLoadedCallbacks) {\n callback()\n }\n })\n }\n\n DOMContentLoadedCallbacks.push(callback)\n } else {\n callback()\n }\n}\n\nconst isRTL = () => document.documentElement.dir === 'rtl'\n\nconst defineJQueryPlugin = plugin => {\n onDOMContentLoaded(() => {\n const $ = getjQuery()\n /* istanbul ignore if */\n if ($) {\n const name = plugin.NAME\n const JQUERY_NO_CONFLICT = $.fn[name]\n $.fn[name] = plugin.jQueryInterface\n $.fn[name].Constructor = plugin\n $.fn[name].noConflict = () => {\n $.fn[name] = JQUERY_NO_CONFLICT\n return plugin.jQueryInterface\n }\n }\n })\n}\n\nconst execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {\n return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue\n}\n\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n if (!waitForTransition) {\n execute(callback)\n return\n }\n\n const durationPadding = 5\n const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding\n\n let called = false\n\n const handler = ({ target }) => {\n if (target !== transitionElement) {\n return\n }\n\n called = true\n transitionElement.removeEventListener(TRANSITION_END, handler)\n execute(callback)\n }\n\n transitionElement.addEventListener(TRANSITION_END, handler)\n setTimeout(() => {\n if (!called) {\n triggerTransitionEnd(transitionElement)\n }\n }, emulatedDuration)\n}\n\n/**\n * Return the previous/next element of a list.\n *\n * @param {array} list The list of elements\n * @param activeElement The active element\n * @param shouldGetNext Choose to get next or previous element\n * @param isCycleAllowed\n * @return {Element|elem} The proper element\n */\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n const listLength = list.length\n let index = list.indexOf(activeElement)\n\n // if the element does not exist in the list return an element\n // depending on the direction and if cycle is allowed\n if (index === -1) {\n return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]\n }\n\n index += shouldGetNext ? 1 : -1\n\n if (isCycleAllowed) {\n index = (index + listLength) % listLength\n }\n\n return list[Math.max(0, Math.min(index, listLength - 1))]\n}\n\nexport {\n defineJQueryPlugin,\n execute,\n executeAfterTransition,\n findShadowRoot,\n getElement,\n getjQuery,\n getNextActiveElement,\n getTransitionDurationFromElement,\n getUID,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop,\n onDOMContentLoaded,\n parseSelector,\n reflow,\n triggerTransitionEnd,\n toType\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { getjQuery } from '../util/index.js'\n\n/**\n * Constants\n */\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/\nconst stripNameRegex = /\\..*/\nconst stripUidRegex = /::\\d+$/\nconst eventRegistry = {} // Events storage\nlet uidEvent = 1\nconst customEvents = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n}\n\nconst nativeEvents = new Set([\n 'click',\n 'dblclick',\n 'mouseup',\n 'mousedown',\n 'contextmenu',\n 'mousewheel',\n 'DOMMouseScroll',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'selectstart',\n 'selectend',\n 'keydown',\n 'keypress',\n 'keyup',\n 'orientationchange',\n 'touchstart',\n 'touchmove',\n 'touchend',\n 'touchcancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup',\n 'pointerleave',\n 'pointercancel',\n 'gesturestart',\n 'gesturechange',\n 'gestureend',\n 'focus',\n 'blur',\n 'change',\n 'reset',\n 'select',\n 'submit',\n 'focusin',\n 'focusout',\n 'load',\n 'unload',\n 'beforeunload',\n 'resize',\n 'move',\n 'DOMContentLoaded',\n 'readystatechange',\n 'error',\n 'abort',\n 'scroll'\n])\n\n/**\n * Private methods\n */\n\nfunction makeEventUid(element, uid) {\n return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++\n}\n\nfunction getElementEvents(element) {\n const uid = makeEventUid(element)\n\n element.uidEvent = uid\n eventRegistry[uid] = eventRegistry[uid] || {}\n\n return eventRegistry[uid]\n}\n\nfunction bootstrapHandler(element, fn) {\n return function handler(event) {\n hydrateObj(event, { delegateTarget: element })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, fn)\n }\n\n return fn.apply(element, [event])\n }\n}\n\nfunction bootstrapDelegationHandler(element, selector, fn) {\n return function handler(event) {\n const domElements = element.querySelectorAll(selector)\n\n for (let { target } = event; target && target !== this; target = target.parentNode) {\n for (const domElement of domElements) {\n if (domElement !== target) {\n continue\n }\n\n hydrateObj(event, { delegateTarget: target })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, selector, fn)\n }\n\n return fn.apply(target, [event])\n }\n }\n }\n}\n\nfunction findHandler(events, callable, delegationSelector = null) {\n return Object.values(events)\n .find(event => event.callable === callable && event.delegationSelector === delegationSelector)\n}\n\nfunction normalizeParameters(originalTypeEvent, handler, delegationFunction) {\n const isDelegated = typeof handler === 'string'\n // TODO: tooltip passes `false` instead of selector, so we need to check\n const callable = isDelegated ? delegationFunction : (handler || delegationFunction)\n let typeEvent = getTypeEvent(originalTypeEvent)\n\n if (!nativeEvents.has(typeEvent)) {\n typeEvent = originalTypeEvent\n }\n\n return [isDelegated, callable, typeEvent]\n}\n\nfunction addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n\n // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n if (originalTypeEvent in customEvents) {\n const wrapFunction = fn => {\n return function (event) {\n if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {\n return fn.call(this, event)\n }\n }\n }\n\n callable = wrapFunction(callable)\n }\n\n const events = getElementEvents(element)\n const handlers = events[typeEvent] || (events[typeEvent] = {})\n const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)\n\n if (previousFunction) {\n previousFunction.oneOff = previousFunction.oneOff && oneOff\n\n return\n }\n\n const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))\n const fn = isDelegated ?\n bootstrapDelegationHandler(element, handler, callable) :\n bootstrapHandler(element, callable)\n\n fn.delegationSelector = isDelegated ? handler : null\n fn.callable = callable\n fn.oneOff = oneOff\n fn.uidEvent = uid\n handlers[uid] = fn\n\n element.addEventListener(typeEvent, fn, isDelegated)\n}\n\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector)\n\n if (!fn) {\n return\n }\n\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))\n delete events[typeEvent][fn.uidEvent]\n}\n\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\n const storeElementEvent = events[typeEvent] || {}\n\n for (const [handlerKey, event] of Object.entries(storeElementEvent)) {\n if (handlerKey.includes(namespace)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n}\n\nfunction getTypeEvent(event) {\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n event = event.replace(stripNameRegex, '')\n return customEvents[event] || event\n}\n\nconst EventHandler = {\n on(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, false)\n },\n\n one(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, true)\n },\n\n off(element, originalTypeEvent, handler, delegationFunction) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n const inNamespace = typeEvent !== originalTypeEvent\n const events = getElementEvents(element)\n const storeElementEvent = events[typeEvent] || {}\n const isNamespace = originalTypeEvent.startsWith('.')\n\n if (typeof callable !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!Object.keys(storeElementEvent).length) {\n return\n }\n\n removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)\n return\n }\n\n if (isNamespace) {\n for (const elementEvent of Object.keys(events)) {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))\n }\n }\n\n for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {\n const handlerKey = keyHandlers.replace(stripUidRegex, '')\n\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n },\n\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null\n }\n\n const $ = getjQuery()\n const typeEvent = getTypeEvent(event)\n const inNamespace = event !== typeEvent\n\n let jQueryEvent = null\n let bubbles = true\n let nativeDispatch = true\n let defaultPrevented = false\n\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args)\n\n $(element).trigger(jQueryEvent)\n bubbles = !jQueryEvent.isPropagationStopped()\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()\n defaultPrevented = jQueryEvent.isDefaultPrevented()\n }\n\n const evt = hydrateObj(new Event(event, { bubbles, cancelable: true }), args)\n\n if (defaultPrevented) {\n evt.preventDefault()\n }\n\n if (nativeDispatch) {\n element.dispatchEvent(evt)\n }\n\n if (evt.defaultPrevented && jQueryEvent) {\n jQueryEvent.preventDefault()\n }\n\n return evt\n }\n}\n\nfunction hydrateObj(obj, meta = {}) {\n for (const [key, value] of Object.entries(meta)) {\n try {\n obj[key] = value\n } catch {\n Object.defineProperty(obj, key, {\n configurable: true,\n get() {\n return value\n }\n })\n }\n }\n\n return obj\n}\n\nexport default EventHandler\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(value) {\n if (value === 'true') {\n return true\n }\n\n if (value === 'false') {\n return false\n }\n\n if (value === Number(value).toString()) {\n return Number(value)\n }\n\n if (value === '' || value === 'null') {\n return null\n }\n\n if (typeof value !== 'string') {\n return value\n }\n\n try {\n return JSON.parse(decodeURIComponent(value))\n } catch {\n return value\n }\n}\n\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)\n}\n\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)\n },\n\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)\n },\n\n getDataAttributes(element) {\n if (!element) {\n return {}\n }\n\n const attributes = {}\n const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'))\n\n for (const key of bsKeys) {\n let pureKey = key.replace(/^bs/, '')\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length)\n attributes[pureKey] = normalizeData(element.dataset[key])\n }\n\n return attributes\n },\n\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))\n }\n}\n\nexport default Manipulator\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/config.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport { isElement, toType } from './index.js'\n\n/**\n * Class definition\n */\n\nclass Config {\n // Getters\n static get Default() {\n return {}\n }\n\n static get DefaultType() {\n return {}\n }\n\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!')\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n return config\n }\n\n _mergeConfigObj(config, element) {\n const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {} // try to parse\n\n return {\n ...this.constructor.Default,\n ...(typeof jsonConfig === 'object' ? jsonConfig : {}),\n ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),\n ...(typeof config === 'object' ? config : {})\n }\n }\n\n _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {\n for (const [property, expectedTypes] of Object.entries(configTypes)) {\n const value = config[property]\n const valueType = isElement(value) ? 'element' : toType(value)\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(\n `${this.constructor.NAME.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`\n )\n }\n }\n }\n}\n\nexport default Config\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Data from './dom/data.js'\nimport EventHandler from './dom/event-handler.js'\nimport Config from './util/config.js'\nimport { executeAfterTransition, getElement } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst VERSION = '5.3.1'\n\n/**\n * Class definition\n */\n\nclass BaseComponent extends Config {\n constructor(element, config) {\n super()\n\n element = getElement(element)\n if (!element) {\n return\n }\n\n this._element = element\n this._config = this._getConfig(config)\n\n Data.set(this._element, this.constructor.DATA_KEY, this)\n }\n\n // Public\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY)\n EventHandler.off(this._element, this.constructor.EVENT_KEY)\n\n for (const propertyName of Object.getOwnPropertyNames(this)) {\n this[propertyName] = null\n }\n }\n\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated)\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config, this._element)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n // Static\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY)\n }\n\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)\n }\n\n static get VERSION() {\n return VERSION\n }\n\n static get DATA_KEY() {\n return `bs.${this.NAME}`\n }\n\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`\n }\n\n static eventName(name) {\n return `${name}${this.EVENT_KEY}`\n }\n}\n\nexport default BaseComponent\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { isDisabled, isVisible, parseSelector } from '../util/index.js'\n\nconst getSelector = element => {\n let selector = element.getAttribute('data-bs-target')\n\n if (!selector || selector === '#') {\n let hrefAttribute = element.getAttribute('href')\n\n // The only valid content that could double as a selector are IDs or classes,\n // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n // `document.querySelector` will rightfully complain it is invalid.\n // See https://github.com/twbs/bootstrap/issues/32273\n if (!hrefAttribute || (!hrefAttribute.includes('#') && !hrefAttribute.startsWith('.'))) {\n return null\n }\n\n // Just in case some CMS puts out a full URL with the anchor appended\n if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {\n hrefAttribute = `#${hrefAttribute.split('#')[1]}`\n }\n\n selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null\n }\n\n return parseSelector(selector)\n}\n\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector))\n },\n\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector)\n },\n\n children(element, selector) {\n return [].concat(...element.children).filter(child => child.matches(selector))\n },\n\n parents(element, selector) {\n const parents = []\n let ancestor = element.parentNode.closest(selector)\n\n while (ancestor) {\n parents.push(ancestor)\n ancestor = ancestor.parentNode.closest(selector)\n }\n\n return parents\n },\n\n prev(element, selector) {\n let previous = element.previousElementSibling\n\n while (previous) {\n if (previous.matches(selector)) {\n return [previous]\n }\n\n previous = previous.previousElementSibling\n }\n\n return []\n },\n // TODO: this is now unused; remove later along with prev()\n next(element, selector) {\n let next = element.nextElementSibling\n\n while (next) {\n if (next.matches(selector)) {\n return [next]\n }\n\n next = next.nextElementSibling\n }\n\n return []\n },\n\n focusableChildren(element) {\n const focusables = [\n 'a',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'details',\n '[tabindex]',\n '[contenteditable=\"true\"]'\n ].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(',')\n\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))\n },\n\n getSelectorFromElement(element) {\n const selector = getSelector(element)\n\n if (selector) {\n return SelectorEngine.findOne(selector) ? selector : null\n }\n\n return null\n },\n\n getElementFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.findOne(selector) : null\n },\n\n getMultipleElementsFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.find(selector) : []\n }\n}\n\nexport default SelectorEngine\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isDisabled } from './index.js'\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`\n const name = component.NAME\n\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`)\n const instance = component.getOrCreateInstance(target)\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]()\n })\n}\n\nexport {\n enableDismissTrigger\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'alert'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\n\n if (closeEvent.defaultPrevented) {\n return\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\n }\n\n // Private\n _destroyElement() {\n this._element.remove()\n EventHandler.trigger(this._element, EVENT_CLOSED)\n this.dispose()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Alert, 'close')\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Alert)\n\nexport default Alert\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'button'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"button\"]'\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this)\n\n if (config === 'toggle') {\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\n event.preventDefault()\n\n const button = event.target.closest(SELECTOR_DATA_TOGGLE)\n const data = Button.getOrCreateInstance(button)\n\n data.toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Button)\n\nexport default Button\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/swipe.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport { execute } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'swipe'\nconst EVENT_KEY = '.bs.swipe'\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY}`\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY}`\nconst POINTER_TYPE_TOUCH = 'touch'\nconst POINTER_TYPE_PEN = 'pen'\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event'\nconst SWIPE_THRESHOLD = 40\n\nconst Default = {\n endCallback: null,\n leftCallback: null,\n rightCallback: null\n}\n\nconst DefaultType = {\n endCallback: '(function|null)',\n leftCallback: '(function|null)',\n rightCallback: '(function|null)'\n}\n\n/**\n * Class definition\n */\n\nclass Swipe extends Config {\n constructor(element, config) {\n super()\n this._element = element\n\n if (!element || !Swipe.isSupported()) {\n return\n }\n\n this._config = this._getConfig(config)\n this._deltaX = 0\n this._supportPointerEvents = Boolean(window.PointerEvent)\n this._initEvents()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n dispose() {\n EventHandler.off(this._element, EVENT_KEY)\n }\n\n // Private\n _start(event) {\n if (!this._supportPointerEvents) {\n this._deltaX = event.touches[0].clientX\n\n return\n }\n\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX\n }\n }\n\n _end(event) {\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX - this._deltaX\n }\n\n this._handleSwipe()\n execute(this._config.endCallback)\n }\n\n _move(event) {\n this._deltaX = event.touches && event.touches.length > 1 ?\n 0 :\n event.touches[0].clientX - this._deltaX\n }\n\n _handleSwipe() {\n const absDeltaX = Math.abs(this._deltaX)\n\n if (absDeltaX <= SWIPE_THRESHOLD) {\n return\n }\n\n const direction = absDeltaX / this._deltaX\n\n this._deltaX = 0\n\n if (!direction) {\n return\n }\n\n execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback)\n }\n\n _initEvents() {\n if (this._supportPointerEvents) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event))\n EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event))\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT)\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event))\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event))\n EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event))\n }\n }\n\n _eventIsPointerPenTouch(event) {\n return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)\n }\n\n // Static\n static isSupported() {\n return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0\n }\n}\n\nexport default Swipe\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getNextActiveElement,\n isRTL,\n isVisible,\n reflow,\n triggerTransitionEnd\n} from './util/index.js'\nimport Swipe from './util/swipe.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'carousel'\nconst DATA_KEY = 'bs.carousel'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch\n\nconst ORDER_NEXT = 'next'\nconst ORDER_PREV = 'prev'\nconst DIRECTION_LEFT = 'left'\nconst DIRECTION_RIGHT = 'right'\n\nconst EVENT_SLIDE = `slide${EVENT_KEY}`\nconst EVENT_SLID = `slid${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`\nconst EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_CAROUSEL = 'carousel'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_SLIDE = 'slide'\nconst CLASS_NAME_END = 'carousel-item-end'\nconst CLASS_NAME_START = 'carousel-item-start'\nconst CLASS_NAME_NEXT = 'carousel-item-next'\nconst CLASS_NAME_PREV = 'carousel-item-prev'\n\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ITEM = '.carousel-item'\nconst SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM\nconst SELECTOR_ITEM_IMG = '.carousel-item img'\nconst SELECTOR_INDICATORS = '.carousel-indicators'\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]'\n\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY]: DIRECTION_LEFT\n}\n\nconst Default = {\n interval: 5000,\n keyboard: true,\n pause: 'hover',\n ride: false,\n touch: true,\n wrap: true\n}\n\nconst DefaultType = {\n interval: '(number|boolean)', // TODO:v6 remove boolean support\n keyboard: 'boolean',\n pause: '(string|boolean)',\n ride: '(boolean|string)',\n touch: 'boolean',\n wrap: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._interval = null\n this._activeElement = null\n this._isSliding = false\n this.touchTimeout = null\n this._swipeHelper = null\n\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)\n this._addEventListeners()\n\n if (this._config.ride === CLASS_NAME_CAROUSEL) {\n this.cycle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n next() {\n this._slide(ORDER_NEXT)\n }\n\n nextWhenVisible() {\n // FIXME TODO use `document.visibilityState`\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next()\n }\n }\n\n prev() {\n this._slide(ORDER_PREV)\n }\n\n pause() {\n if (this._isSliding) {\n triggerTransitionEnd(this._element)\n }\n\n this._clearInterval()\n }\n\n cycle() {\n this._clearInterval()\n this._updateInterval()\n\n this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval)\n }\n\n _maybeEnableCycle() {\n if (!this._config.ride) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.cycle())\n return\n }\n\n this.cycle()\n }\n\n to(index) {\n const items = this._getItems()\n if (index > items.length - 1 || index < 0) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index))\n return\n }\n\n const activeIndex = this._getItemIndex(this._getActive())\n if (activeIndex === index) {\n return\n }\n\n const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV\n\n this._slide(order, items[index])\n }\n\n dispose() {\n if (this._swipeHelper) {\n this._swipeHelper.dispose()\n }\n\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n config.defaultInterval = config.interval\n return config\n }\n\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER, () => this.pause())\n EventHandler.on(this._element, EVENT_MOUSELEAVE, () => this._maybeEnableCycle())\n }\n\n if (this._config.touch && Swipe.isSupported()) {\n this._addTouchEventListeners()\n }\n }\n\n _addTouchEventListeners() {\n for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {\n EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault())\n }\n\n const endCallBack = () => {\n if (this._config.pause !== 'hover') {\n return\n }\n\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause()\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout)\n }\n\n this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval)\n }\n\n const swipeConfig = {\n leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),\n rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),\n endCallback: endCallBack\n }\n\n this._swipeHelper = new Swipe(this._element, swipeConfig)\n }\n\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return\n }\n\n const direction = KEY_TO_DIRECTION[event.key]\n if (direction) {\n event.preventDefault()\n this._slide(this._directionToOrder(direction))\n }\n }\n\n _getItemIndex(element) {\n return this._getItems().indexOf(element)\n }\n\n _setActiveIndicatorElement(index) {\n if (!this._indicatorsElement) {\n return\n }\n\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement)\n\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE)\n activeIndicator.removeAttribute('aria-current')\n\n const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to=\"${index}\"]`, this._indicatorsElement)\n\n if (newActiveIndicator) {\n newActiveIndicator.classList.add(CLASS_NAME_ACTIVE)\n newActiveIndicator.setAttribute('aria-current', 'true')\n }\n }\n\n _updateInterval() {\n const element = this._activeElement || this._getActive()\n\n if (!element) {\n return\n }\n\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10)\n\n this._config.interval = elementInterval || this._config.defaultInterval\n }\n\n _slide(order, element = null) {\n if (this._isSliding) {\n return\n }\n\n const activeElement = this._getActive()\n const isNext = order === ORDER_NEXT\n const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap)\n\n if (nextElement === activeElement) {\n return\n }\n\n const nextElementIndex = this._getItemIndex(nextElement)\n\n const triggerEvent = eventName => {\n return EventHandler.trigger(this._element, eventName, {\n relatedTarget: nextElement,\n direction: this._orderToDirection(order),\n from: this._getItemIndex(activeElement),\n to: nextElementIndex\n })\n }\n\n const slideEvent = triggerEvent(EVENT_SLIDE)\n\n if (slideEvent.defaultPrevented) {\n return\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n // TODO: change tests that use empty divs to avoid this check\n return\n }\n\n const isCycling = Boolean(this._interval)\n this.pause()\n\n this._isSliding = true\n\n this._setActiveIndicatorElement(nextElementIndex)\n this._activeElement = nextElement\n\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV\n\n nextElement.classList.add(orderClassName)\n\n reflow(nextElement)\n\n activeElement.classList.add(directionalClassName)\n nextElement.classList.add(directionalClassName)\n\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName)\n nextElement.classList.add(CLASS_NAME_ACTIVE)\n\n activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName)\n\n this._isSliding = false\n\n triggerEvent(EVENT_SLID)\n }\n\n this._queueCallback(completeCallBack, activeElement, this._isAnimated())\n\n if (isCycling) {\n this.cycle()\n }\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_SLIDE)\n }\n\n _getActive() {\n return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n }\n\n _getItems() {\n return SelectorEngine.find(SELECTOR_ITEM, this._element)\n }\n\n _clearInterval() {\n if (this._interval) {\n clearInterval(this._interval)\n this._interval = null\n }\n }\n\n _directionToOrder(direction) {\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT\n }\n\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV\n }\n\n _orderToDirection(order) {\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT\n }\n\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Carousel.getOrCreateInstance(this, config)\n\n if (typeof config === 'number') {\n data.to(config)\n return\n }\n\n if (typeof config === 'string') {\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return\n }\n\n event.preventDefault()\n\n const carousel = Carousel.getOrCreateInstance(target)\n const slideIndex = this.getAttribute('data-bs-slide-to')\n\n if (slideIndex) {\n carousel.to(slideIndex)\n carousel._maybeEnableCycle()\n return\n }\n\n if (Manipulator.getDataAttribute(this, 'slide') === 'next') {\n carousel.next()\n carousel._maybeEnableCycle()\n return\n }\n\n carousel.prev()\n carousel._maybeEnableCycle()\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE)\n\n for (const carousel of carousels) {\n Carousel.getOrCreateInstance(carousel)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Carousel)\n\nexport default Carousel\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getElement,\n reflow\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'collapse'\nconst DATA_KEY = 'bs.collapse'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_COLLAPSE = 'collapse'\nconst CLASS_NAME_COLLAPSING = 'collapsing'\nconst CLASS_NAME_COLLAPSED = 'collapsed'\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal'\n\nconst WIDTH = 'width'\nconst HEIGHT = 'height'\n\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"collapse\"]'\n\nconst Default = {\n parent: null,\n toggle: true\n}\n\nconst DefaultType = {\n parent: '(null|element)',\n toggle: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isTransitioning = false\n this._triggerArray = []\n\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\n\n for (const elem of toggleList) {\n const selector = SelectorEngine.getSelectorFromElement(elem)\n const filterElement = SelectorEngine.find(selector)\n .filter(foundElement => foundElement === this._element)\n\n if (selector !== null && filterElement.length) {\n this._triggerArray.push(elem)\n }\n }\n\n this._initializeChildren()\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown())\n }\n\n if (this._config.toggle) {\n this.toggle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n if (this._isShown()) {\n this.hide()\n } else {\n this.show()\n }\n }\n\n show() {\n if (this._isTransitioning || this._isShown()) {\n return\n }\n\n let activeChildren = []\n\n // find active children\n if (this._config.parent) {\n activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES)\n .filter(element => element !== this._element)\n .map(element => Collapse.getOrCreateInstance(element, { toggle: false }))\n }\n\n if (activeChildren.length && activeChildren[0]._isTransitioning) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n if (startEvent.defaultPrevented) {\n return\n }\n\n for (const activeInstance of activeChildren) {\n activeInstance.hide()\n }\n\n const dimension = this._getDimension()\n\n this._element.classList.remove(CLASS_NAME_COLLAPSE)\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n\n this._element.style[dimension] = 0\n\n this._addAriaAndCollapsedClass(this._triggerArray, true)\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n this._element.style[dimension] = ''\n\n EventHandler.trigger(this._element, EVENT_SHOWN)\n }\n\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)\n const scrollSize = `scroll${capitalizedDimension}`\n\n this._queueCallback(complete, this._element, true)\n this._element.style[dimension] = `${this._element[scrollSize]}px`\n }\n\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n if (startEvent.defaultPrevented) {\n return\n }\n\n const dimension = this._getDimension()\n\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n for (const trigger of this._triggerArray) {\n const element = SelectorEngine.getElementFromSelector(trigger)\n\n if (element && !this._isShown(element)) {\n this._addAriaAndCollapsedClass([trigger], false)\n }\n }\n\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.style[dimension] = ''\n\n this._queueCallback(complete, this._element, true)\n }\n\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n _configAfterMerge(config) {\n config.toggle = Boolean(config.toggle) // Coerce string values\n config.parent = getElement(config.parent)\n return config\n }\n\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT\n }\n\n _initializeChildren() {\n if (!this._config.parent) {\n return\n }\n\n const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE)\n\n for (const element of children) {\n const selected = SelectorEngine.getElementFromSelector(element)\n\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected))\n }\n }\n }\n\n _getFirstLevelChildren(selector) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\n // remove children if greater depth\n return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element))\n }\n\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return\n }\n\n for (const element of triggerArray) {\n element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen)\n element.setAttribute('aria-expanded', isOpen)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n const _config = {}\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false\n }\n\n return this.each(function () {\n const data = Collapse.getOrCreateInstance(this, _config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n // preventDefault only for elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {\n event.preventDefault()\n }\n\n for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {\n Collapse.getOrCreateInstance(element, { toggle: false }).toggle()\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Collapse)\n\nexport default Collapse\n","export var top = 'top';\nexport var bottom = 'bottom';\nexport var right = 'right';\nexport var left = 'left';\nexport var auto = 'auto';\nexport var basePlacements = [top, bottom, right, left];\nexport var start = 'start';\nexport var end = 'end';\nexport var clippingParents = 'clippingParents';\nexport var viewport = 'viewport';\nexport var popper = 'popper';\nexport var reference = 'reference';\nexport var variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) {\n return acc.concat([placement + \"-\" + start, placement + \"-\" + end]);\n}, []);\nexport var placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) {\n return acc.concat([placement, placement + \"-\" + start, placement + \"-\" + end]);\n}, []); // modifiers that need to read the DOM\n\nexport var beforeRead = 'beforeRead';\nexport var read = 'read';\nexport var afterRead = 'afterRead'; // pure-logic modifiers\n\nexport var beforeMain = 'beforeMain';\nexport var main = 'main';\nexport var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state)\n\nexport var beforeWrite = 'beforeWrite';\nexport var write = 'write';\nexport var afterWrite = 'afterWrite';\nexport var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite];","export default function getNodeName(element) {\n return element ? (element.nodeName || '').toLowerCase() : null;\n}","export default function getWindow(node) {\n if (node == null) {\n return window;\n }\n\n if (node.toString() !== '[object Window]') {\n var ownerDocument = node.ownerDocument;\n return ownerDocument ? ownerDocument.defaultView || window : window;\n }\n\n return node;\n}","import getWindow from \"./getWindow.js\";\n\nfunction isElement(node) {\n var OwnElement = getWindow(node).Element;\n return node instanceof OwnElement || node instanceof Element;\n}\n\nfunction isHTMLElement(node) {\n var OwnElement = getWindow(node).HTMLElement;\n return node instanceof OwnElement || node instanceof HTMLElement;\n}\n\nfunction isShadowRoot(node) {\n // IE 11 has no ShadowRoot\n if (typeof ShadowRoot === 'undefined') {\n return false;\n }\n\n var OwnElement = getWindow(node).ShadowRoot;\n return node instanceof OwnElement || node instanceof ShadowRoot;\n}\n\nexport { isElement, isHTMLElement, isShadowRoot };","import getNodeName from \"../dom-utils/getNodeName.js\";\nimport { isHTMLElement } from \"../dom-utils/instanceOf.js\"; // This modifier takes the styles prepared by the `computeStyles` modifier\n// and applies them to the HTMLElements such as popper and arrow\n\nfunction applyStyles(_ref) {\n var state = _ref.state;\n Object.keys(state.elements).forEach(function (name) {\n var style = state.styles[name] || {};\n var attributes = state.attributes[name] || {};\n var element = state.elements[name]; // arrow is optional + virtual elements\n\n if (!isHTMLElement(element) || !getNodeName(element)) {\n return;\n } // Flow doesn't support to extend this property, but it's the most\n // effective way to apply styles to an HTMLElement\n // $FlowFixMe[cannot-write]\n\n\n Object.assign(element.style, style);\n Object.keys(attributes).forEach(function (name) {\n var value = attributes[name];\n\n if (value === false) {\n element.removeAttribute(name);\n } else {\n element.setAttribute(name, value === true ? '' : value);\n }\n });\n });\n}\n\nfunction effect(_ref2) {\n var state = _ref2.state;\n var initialStyles = {\n popper: {\n position: state.options.strategy,\n left: '0',\n top: '0',\n margin: '0'\n },\n arrow: {\n position: 'absolute'\n },\n reference: {}\n };\n Object.assign(state.elements.popper.style, initialStyles.popper);\n state.styles = initialStyles;\n\n if (state.elements.arrow) {\n Object.assign(state.elements.arrow.style, initialStyles.arrow);\n }\n\n return function () {\n Object.keys(state.elements).forEach(function (name) {\n var element = state.elements[name];\n var attributes = state.attributes[name] || {};\n var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them\n\n var style = styleProperties.reduce(function (style, property) {\n style[property] = '';\n return style;\n }, {}); // arrow is optional + virtual elements\n\n if (!isHTMLElement(element) || !getNodeName(element)) {\n return;\n }\n\n Object.assign(element.style, style);\n Object.keys(attributes).forEach(function (attribute) {\n element.removeAttribute(attribute);\n });\n });\n };\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'applyStyles',\n enabled: true,\n phase: 'write',\n fn: applyStyles,\n effect: effect,\n requires: ['computeStyles']\n};","import { auto } from \"../enums.js\";\nexport default function getBasePlacement(placement) {\n return placement.split('-')[0];\n}","export var max = Math.max;\nexport var min = Math.min;\nexport var round = Math.round;","export default function getUAString() {\n var uaData = navigator.userAgentData;\n\n if (uaData != null && uaData.brands && Array.isArray(uaData.brands)) {\n return uaData.brands.map(function (item) {\n return item.brand + \"/\" + item.version;\n }).join(' ');\n }\n\n return navigator.userAgent;\n}","import getUAString from \"../utils/userAgent.js\";\nexport default function isLayoutViewport() {\n return !/^((?!chrome|android).)*safari/i.test(getUAString());\n}","import { isElement, isHTMLElement } from \"./instanceOf.js\";\nimport { round } from \"../utils/math.js\";\nimport getWindow from \"./getWindow.js\";\nimport isLayoutViewport from \"./isLayoutViewport.js\";\nexport default function getBoundingClientRect(element, includeScale, isFixedStrategy) {\n if (includeScale === void 0) {\n includeScale = false;\n }\n\n if (isFixedStrategy === void 0) {\n isFixedStrategy = false;\n }\n\n var clientRect = element.getBoundingClientRect();\n var scaleX = 1;\n var scaleY = 1;\n\n if (includeScale && isHTMLElement(element)) {\n scaleX = element.offsetWidth > 0 ? round(clientRect.width) / element.offsetWidth || 1 : 1;\n scaleY = element.offsetHeight > 0 ? round(clientRect.height) / element.offsetHeight || 1 : 1;\n }\n\n var _ref = isElement(element) ? getWindow(element) : window,\n visualViewport = _ref.visualViewport;\n\n var addVisualOffsets = !isLayoutViewport() && isFixedStrategy;\n var x = (clientRect.left + (addVisualOffsets && visualViewport ? visualViewport.offsetLeft : 0)) / scaleX;\n var y = (clientRect.top + (addVisualOffsets && visualViewport ? visualViewport.offsetTop : 0)) / scaleY;\n var width = clientRect.width / scaleX;\n var height = clientRect.height / scaleY;\n return {\n width: width,\n height: height,\n top: y,\n right: x + width,\n bottom: y + height,\n left: x,\n x: x,\n y: y\n };\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\"; // Returns the layout rect of an element relative to its offsetParent. Layout\n// means it doesn't take into account transforms.\n\nexport default function getLayoutRect(element) {\n var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed.\n // Fixes https://github.com/popperjs/popper-core/issues/1223\n\n var width = element.offsetWidth;\n var height = element.offsetHeight;\n\n if (Math.abs(clientRect.width - width) <= 1) {\n width = clientRect.width;\n }\n\n if (Math.abs(clientRect.height - height) <= 1) {\n height = clientRect.height;\n }\n\n return {\n x: element.offsetLeft,\n y: element.offsetTop,\n width: width,\n height: height\n };\n}","import { isShadowRoot } from \"./instanceOf.js\";\nexport default function contains(parent, child) {\n var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method\n\n if (parent.contains(child)) {\n return true;\n } // then fallback to custom implementation with Shadow DOM support\n else if (rootNode && isShadowRoot(rootNode)) {\n var next = child;\n\n do {\n if (next && parent.isSameNode(next)) {\n return true;\n } // $FlowFixMe[prop-missing]: need a better way to handle this...\n\n\n next = next.parentNode || next.host;\n } while (next);\n } // Give up, the result is false\n\n\n return false;\n}","import getWindow from \"./getWindow.js\";\nexport default function getComputedStyle(element) {\n return getWindow(element).getComputedStyle(element);\n}","import getNodeName from \"./getNodeName.js\";\nexport default function isTableElement(element) {\n return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;\n}","import { isElement } from \"./instanceOf.js\";\nexport default function getDocumentElement(element) {\n // $FlowFixMe[incompatible-return]: assume body is always available\n return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]\n element.document) || window.document).documentElement;\n}","import getNodeName from \"./getNodeName.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport { isShadowRoot } from \"./instanceOf.js\";\nexport default function getParentNode(element) {\n if (getNodeName(element) === 'html') {\n return element;\n }\n\n return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle\n // $FlowFixMe[incompatible-return]\n // $FlowFixMe[prop-missing]\n element.assignedSlot || // step into the shadow DOM of the parent of a slotted node\n element.parentNode || ( // DOM Element detected\n isShadowRoot(element) ? element.host : null) || // ShadowRoot detected\n // $FlowFixMe[incompatible-call]: HTMLElement is a Node\n getDocumentElement(element) // fallback\n\n );\n}","import getWindow from \"./getWindow.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport { isHTMLElement, isShadowRoot } from \"./instanceOf.js\";\nimport isTableElement from \"./isTableElement.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport getUAString from \"../utils/userAgent.js\";\n\nfunction getTrueOffsetParent(element) {\n if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837\n getComputedStyle(element).position === 'fixed') {\n return null;\n }\n\n return element.offsetParent;\n} // `.offsetParent` reports `null` for fixed elements, while absolute elements\n// return the containing block\n\n\nfunction getContainingBlock(element) {\n var isFirefox = /firefox/i.test(getUAString());\n var isIE = /Trident/i.test(getUAString());\n\n if (isIE && isHTMLElement(element)) {\n // In IE 9, 10 and 11 fixed elements containing block is always established by the viewport\n var elementCss = getComputedStyle(element);\n\n if (elementCss.position === 'fixed') {\n return null;\n }\n }\n\n var currentNode = getParentNode(element);\n\n if (isShadowRoot(currentNode)) {\n currentNode = currentNode.host;\n }\n\n while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {\n var css = getComputedStyle(currentNode); // This is non-exhaustive but covers the most common CSS properties that\n // create a containing block.\n // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block\n\n if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') {\n return currentNode;\n } else {\n currentNode = currentNode.parentNode;\n }\n }\n\n return null;\n} // Gets the closest ancestor positioned element. Handles some edge cases,\n// such as table ancestors and cross browser bugs.\n\n\nexport default function getOffsetParent(element) {\n var window = getWindow(element);\n var offsetParent = getTrueOffsetParent(element);\n\n while (offsetParent && isTableElement(offsetParent) && getComputedStyle(offsetParent).position === 'static') {\n offsetParent = getTrueOffsetParent(offsetParent);\n }\n\n if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle(offsetParent).position === 'static')) {\n return window;\n }\n\n return offsetParent || getContainingBlock(element) || window;\n}","export default function getMainAxisFromPlacement(placement) {\n return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y';\n}","import { max as mathMax, min as mathMin } from \"./math.js\";\nexport function within(min, value, max) {\n return mathMax(min, mathMin(value, max));\n}\nexport function withinMaxClamp(min, value, max) {\n var v = within(min, value, max);\n return v > max ? max : v;\n}","import getFreshSideObject from \"./getFreshSideObject.js\";\nexport default function mergePaddingObject(paddingObject) {\n return Object.assign({}, getFreshSideObject(), paddingObject);\n}","export default function getFreshSideObject() {\n return {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0\n };\n}","export default function expandToHashMap(value, keys) {\n return keys.reduce(function (hashMap, key) {\n hashMap[key] = value;\n return hashMap;\n }, {});\n}","import getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getLayoutRect from \"../dom-utils/getLayoutRect.js\";\nimport contains from \"../dom-utils/contains.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport getMainAxisFromPlacement from \"../utils/getMainAxisFromPlacement.js\";\nimport { within } from \"../utils/within.js\";\nimport mergePaddingObject from \"../utils/mergePaddingObject.js\";\nimport expandToHashMap from \"../utils/expandToHashMap.js\";\nimport { left, right, basePlacements, top, bottom } from \"../enums.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar toPaddingObject = function toPaddingObject(padding, state) {\n padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, {\n placement: state.placement\n })) : padding;\n return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n};\n\nfunction arrow(_ref) {\n var _state$modifiersData$;\n\n var state = _ref.state,\n name = _ref.name,\n options = _ref.options;\n var arrowElement = state.elements.arrow;\n var popperOffsets = state.modifiersData.popperOffsets;\n var basePlacement = getBasePlacement(state.placement);\n var axis = getMainAxisFromPlacement(basePlacement);\n var isVertical = [left, right].indexOf(basePlacement) >= 0;\n var len = isVertical ? 'height' : 'width';\n\n if (!arrowElement || !popperOffsets) {\n return;\n }\n\n var paddingObject = toPaddingObject(options.padding, state);\n var arrowRect = getLayoutRect(arrowElement);\n var minProp = axis === 'y' ? top : left;\n var maxProp = axis === 'y' ? bottom : right;\n var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len];\n var startDiff = popperOffsets[axis] - state.rects.reference[axis];\n var arrowOffsetParent = getOffsetParent(arrowElement);\n var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;\n var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is\n // outside of the popper bounds\n\n var min = paddingObject[minProp];\n var max = clientSize - arrowRect[len] - paddingObject[maxProp];\n var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference;\n var offset = within(min, center, max); // Prevents breaking syntax highlighting...\n\n var axisProp = axis;\n state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$);\n}\n\nfunction effect(_ref2) {\n var state = _ref2.state,\n options = _ref2.options;\n var _options$element = options.element,\n arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element;\n\n if (arrowElement == null) {\n return;\n } // CSS selector\n\n\n if (typeof arrowElement === 'string') {\n arrowElement = state.elements.popper.querySelector(arrowElement);\n\n if (!arrowElement) {\n return;\n }\n }\n\n if (!contains(state.elements.popper, arrowElement)) {\n return;\n }\n\n state.elements.arrow = arrowElement;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'arrow',\n enabled: true,\n phase: 'main',\n fn: arrow,\n effect: effect,\n requires: ['popperOffsets'],\n requiresIfExists: ['preventOverflow']\n};","export default function getVariation(placement) {\n return placement.split('-')[1];\n}","import { top, left, right, bottom, end } from \"../enums.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport getWindow from \"../dom-utils/getWindow.js\";\nimport getDocumentElement from \"../dom-utils/getDocumentElement.js\";\nimport getComputedStyle from \"../dom-utils/getComputedStyle.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getVariation from \"../utils/getVariation.js\";\nimport { round } from \"../utils/math.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar unsetSides = {\n top: 'auto',\n right: 'auto',\n bottom: 'auto',\n left: 'auto'\n}; // Round the offsets to the nearest suitable subpixel based on the DPR.\n// Zooming can change the DPR, but it seems to report a value that will\n// cleanly divide the values into the appropriate subpixels.\n\nfunction roundOffsetsByDPR(_ref, win) {\n var x = _ref.x,\n y = _ref.y;\n var dpr = win.devicePixelRatio || 1;\n return {\n x: round(x * dpr) / dpr || 0,\n y: round(y * dpr) / dpr || 0\n };\n}\n\nexport function mapToStyles(_ref2) {\n var _Object$assign2;\n\n var popper = _ref2.popper,\n popperRect = _ref2.popperRect,\n placement = _ref2.placement,\n variation = _ref2.variation,\n offsets = _ref2.offsets,\n position = _ref2.position,\n gpuAcceleration = _ref2.gpuAcceleration,\n adaptive = _ref2.adaptive,\n roundOffsets = _ref2.roundOffsets,\n isFixed = _ref2.isFixed;\n var _offsets$x = offsets.x,\n x = _offsets$x === void 0 ? 0 : _offsets$x,\n _offsets$y = offsets.y,\n y = _offsets$y === void 0 ? 0 : _offsets$y;\n\n var _ref3 = typeof roundOffsets === 'function' ? roundOffsets({\n x: x,\n y: y\n }) : {\n x: x,\n y: y\n };\n\n x = _ref3.x;\n y = _ref3.y;\n var hasX = offsets.hasOwnProperty('x');\n var hasY = offsets.hasOwnProperty('y');\n var sideX = left;\n var sideY = top;\n var win = window;\n\n if (adaptive) {\n var offsetParent = getOffsetParent(popper);\n var heightProp = 'clientHeight';\n var widthProp = 'clientWidth';\n\n if (offsetParent === getWindow(popper)) {\n offsetParent = getDocumentElement(popper);\n\n if (getComputedStyle(offsetParent).position !== 'static' && position === 'absolute') {\n heightProp = 'scrollHeight';\n widthProp = 'scrollWidth';\n }\n } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it\n\n\n offsetParent = offsetParent;\n\n if (placement === top || (placement === left || placement === right) && variation === end) {\n sideY = bottom;\n var offsetY = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.height : // $FlowFixMe[prop-missing]\n offsetParent[heightProp];\n y -= offsetY - popperRect.height;\n y *= gpuAcceleration ? 1 : -1;\n }\n\n if (placement === left || (placement === top || placement === bottom) && variation === end) {\n sideX = right;\n var offsetX = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.width : // $FlowFixMe[prop-missing]\n offsetParent[widthProp];\n x -= offsetX - popperRect.width;\n x *= gpuAcceleration ? 1 : -1;\n }\n }\n\n var commonStyles = Object.assign({\n position: position\n }, adaptive && unsetSides);\n\n var _ref4 = roundOffsets === true ? roundOffsetsByDPR({\n x: x,\n y: y\n }, getWindow(popper)) : {\n x: x,\n y: y\n };\n\n x = _ref4.x;\n y = _ref4.y;\n\n if (gpuAcceleration) {\n var _Object$assign;\n\n return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) <= 1 ? \"translate(\" + x + \"px, \" + y + \"px)\" : \"translate3d(\" + x + \"px, \" + y + \"px, 0)\", _Object$assign));\n }\n\n return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + \"px\" : '', _Object$assign2[sideX] = hasX ? x + \"px\" : '', _Object$assign2.transform = '', _Object$assign2));\n}\n\nfunction computeStyles(_ref5) {\n var state = _ref5.state,\n options = _ref5.options;\n var _options$gpuAccelerat = options.gpuAcceleration,\n gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat,\n _options$adaptive = options.adaptive,\n adaptive = _options$adaptive === void 0 ? true : _options$adaptive,\n _options$roundOffsets = options.roundOffsets,\n roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;\n var commonStyles = {\n placement: getBasePlacement(state.placement),\n variation: getVariation(state.placement),\n popper: state.elements.popper,\n popperRect: state.rects.popper,\n gpuAcceleration: gpuAcceleration,\n isFixed: state.options.strategy === 'fixed'\n };\n\n if (state.modifiersData.popperOffsets != null) {\n state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {\n offsets: state.modifiersData.popperOffsets,\n position: state.options.strategy,\n adaptive: adaptive,\n roundOffsets: roundOffsets\n })));\n }\n\n if (state.modifiersData.arrow != null) {\n state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {\n offsets: state.modifiersData.arrow,\n position: 'absolute',\n adaptive: false,\n roundOffsets: roundOffsets\n })));\n }\n\n state.attributes.popper = Object.assign({}, state.attributes.popper, {\n 'data-popper-placement': state.placement\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'computeStyles',\n enabled: true,\n phase: 'beforeWrite',\n fn: computeStyles,\n data: {}\n};","import getWindow from \"../dom-utils/getWindow.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar passive = {\n passive: true\n};\n\nfunction effect(_ref) {\n var state = _ref.state,\n instance = _ref.instance,\n options = _ref.options;\n var _options$scroll = options.scroll,\n scroll = _options$scroll === void 0 ? true : _options$scroll,\n _options$resize = options.resize,\n resize = _options$resize === void 0 ? true : _options$resize;\n var window = getWindow(state.elements.popper);\n var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);\n\n if (scroll) {\n scrollParents.forEach(function (scrollParent) {\n scrollParent.addEventListener('scroll', instance.update, passive);\n });\n }\n\n if (resize) {\n window.addEventListener('resize', instance.update, passive);\n }\n\n return function () {\n if (scroll) {\n scrollParents.forEach(function (scrollParent) {\n scrollParent.removeEventListener('scroll', instance.update, passive);\n });\n }\n\n if (resize) {\n window.removeEventListener('resize', instance.update, passive);\n }\n };\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'eventListeners',\n enabled: true,\n phase: 'write',\n fn: function fn() {},\n effect: effect,\n data: {}\n};","var hash = {\n left: 'right',\n right: 'left',\n bottom: 'top',\n top: 'bottom'\n};\nexport default function getOppositePlacement(placement) {\n return placement.replace(/left|right|bottom|top/g, function (matched) {\n return hash[matched];\n });\n}","var hash = {\n start: 'end',\n end: 'start'\n};\nexport default function getOppositeVariationPlacement(placement) {\n return placement.replace(/start|end/g, function (matched) {\n return hash[matched];\n });\n}","import getWindow from \"./getWindow.js\";\nexport default function getWindowScroll(node) {\n var win = getWindow(node);\n var scrollLeft = win.pageXOffset;\n var scrollTop = win.pageYOffset;\n return {\n scrollLeft: scrollLeft,\n scrollTop: scrollTop\n };\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getWindowScroll from \"./getWindowScroll.js\";\nexport default function getWindowScrollBarX(element) {\n // If has a CSS width greater than the viewport, then this will be\n // incorrect for RTL.\n // Popper 1 is broken in this case and never had a bug report so let's assume\n // it's not an issue. I don't think anyone ever specifies width on \n // anyway.\n // Browsers where the left scrollbar doesn't cause an issue report `0` for\n // this (e.g. Edge 2019, IE11, Safari)\n return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;\n}","import getComputedStyle from \"./getComputedStyle.js\";\nexport default function isScrollParent(element) {\n // Firefox wants us to check `-x` and `-y` variations as well\n var _getComputedStyle = getComputedStyle(element),\n overflow = _getComputedStyle.overflow,\n overflowX = _getComputedStyle.overflowX,\n overflowY = _getComputedStyle.overflowY;\n\n return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);\n}","import getParentNode from \"./getParentNode.js\";\nimport isScrollParent from \"./isScrollParent.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nexport default function getScrollParent(node) {\n if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {\n // $FlowFixMe[incompatible-return]: assume body is always available\n return node.ownerDocument.body;\n }\n\n if (isHTMLElement(node) && isScrollParent(node)) {\n return node;\n }\n\n return getScrollParent(getParentNode(node));\n}","import getScrollParent from \"./getScrollParent.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport getWindow from \"./getWindow.js\";\nimport isScrollParent from \"./isScrollParent.js\";\n/*\ngiven a DOM element, return the list of all scroll parents, up the list of ancesors\nuntil we get to the top window object. This list is what we attach scroll listeners\nto, because if any of these parent elements scroll, we'll need to re-calculate the\nreference element's position.\n*/\n\nexport default function listScrollParents(element, list) {\n var _element$ownerDocumen;\n\n if (list === void 0) {\n list = [];\n }\n\n var scrollParent = getScrollParent(element);\n var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);\n var win = getWindow(scrollParent);\n var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;\n var updatedList = list.concat(target);\n return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here\n updatedList.concat(listScrollParents(getParentNode(target)));\n}","export default function rectToClientRect(rect) {\n return Object.assign({}, rect, {\n left: rect.x,\n top: rect.y,\n right: rect.x + rect.width,\n bottom: rect.y + rect.height\n });\n}","import { viewport } from \"../enums.js\";\nimport getViewportRect from \"./getViewportRect.js\";\nimport getDocumentRect from \"./getDocumentRect.js\";\nimport listScrollParents from \"./listScrollParents.js\";\nimport getOffsetParent from \"./getOffsetParent.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport { isElement, isHTMLElement } from \"./instanceOf.js\";\nimport getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport contains from \"./contains.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport rectToClientRect from \"../utils/rectToClientRect.js\";\nimport { max, min } from \"../utils/math.js\";\n\nfunction getInnerBoundingClientRect(element, strategy) {\n var rect = getBoundingClientRect(element, false, strategy === 'fixed');\n rect.top = rect.top + element.clientTop;\n rect.left = rect.left + element.clientLeft;\n rect.bottom = rect.top + element.clientHeight;\n rect.right = rect.left + element.clientWidth;\n rect.width = element.clientWidth;\n rect.height = element.clientHeight;\n rect.x = rect.left;\n rect.y = rect.top;\n return rect;\n}\n\nfunction getClientRectFromMixedType(element, clippingParent, strategy) {\n return clippingParent === viewport ? rectToClientRect(getViewportRect(element, strategy)) : isElement(clippingParent) ? getInnerBoundingClientRect(clippingParent, strategy) : rectToClientRect(getDocumentRect(getDocumentElement(element)));\n} // A \"clipping parent\" is an overflowable container with the characteristic of\n// clipping (or hiding) overflowing elements with a position different from\n// `initial`\n\n\nfunction getClippingParents(element) {\n var clippingParents = listScrollParents(getParentNode(element));\n var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle(element).position) >= 0;\n var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;\n\n if (!isElement(clipperElement)) {\n return [];\n } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414\n\n\n return clippingParents.filter(function (clippingParent) {\n return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body';\n });\n} // Gets the maximum area that the element is visible in due to any number of\n// clipping parents\n\n\nexport default function getClippingRect(element, boundary, rootBoundary, strategy) {\n var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary);\n var clippingParents = [].concat(mainClippingParents, [rootBoundary]);\n var firstClippingParent = clippingParents[0];\n var clippingRect = clippingParents.reduce(function (accRect, clippingParent) {\n var rect = getClientRectFromMixedType(element, clippingParent, strategy);\n accRect.top = max(rect.top, accRect.top);\n accRect.right = min(rect.right, accRect.right);\n accRect.bottom = min(rect.bottom, accRect.bottom);\n accRect.left = max(rect.left, accRect.left);\n return accRect;\n }, getClientRectFromMixedType(element, firstClippingParent, strategy));\n clippingRect.width = clippingRect.right - clippingRect.left;\n clippingRect.height = clippingRect.bottom - clippingRect.top;\n clippingRect.x = clippingRect.left;\n clippingRect.y = clippingRect.top;\n return clippingRect;\n}","import getWindow from \"./getWindow.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport isLayoutViewport from \"./isLayoutViewport.js\";\nexport default function getViewportRect(element, strategy) {\n var win = getWindow(element);\n var html = getDocumentElement(element);\n var visualViewport = win.visualViewport;\n var width = html.clientWidth;\n var height = html.clientHeight;\n var x = 0;\n var y = 0;\n\n if (visualViewport) {\n width = visualViewport.width;\n height = visualViewport.height;\n var layoutViewport = isLayoutViewport();\n\n if (layoutViewport || !layoutViewport && strategy === 'fixed') {\n x = visualViewport.offsetLeft;\n y = visualViewport.offsetTop;\n }\n }\n\n return {\n width: width,\n height: height,\n x: x + getWindowScrollBarX(element),\n y: y\n };\n}","import getDocumentElement from \"./getDocumentElement.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport getWindowScroll from \"./getWindowScroll.js\";\nimport { max } from \"../utils/math.js\"; // Gets the entire size of the scrollable document area, even extending outside\n// of the `` and `` rect bounds if horizontally scrollable\n\nexport default function getDocumentRect(element) {\n var _element$ownerDocumen;\n\n var html = getDocumentElement(element);\n var winScroll = getWindowScroll(element);\n var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;\n var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);\n var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);\n var x = -winScroll.scrollLeft + getWindowScrollBarX(element);\n var y = -winScroll.scrollTop;\n\n if (getComputedStyle(body || html).direction === 'rtl') {\n x += max(html.clientWidth, body ? body.clientWidth : 0) - width;\n }\n\n return {\n width: width,\n height: height,\n x: x,\n y: y\n };\n}","import getBasePlacement from \"./getBasePlacement.js\";\nimport getVariation from \"./getVariation.js\";\nimport getMainAxisFromPlacement from \"./getMainAxisFromPlacement.js\";\nimport { top, right, bottom, left, start, end } from \"../enums.js\";\nexport default function computeOffsets(_ref) {\n var reference = _ref.reference,\n element = _ref.element,\n placement = _ref.placement;\n var basePlacement = placement ? getBasePlacement(placement) : null;\n var variation = placement ? getVariation(placement) : null;\n var commonX = reference.x + reference.width / 2 - element.width / 2;\n var commonY = reference.y + reference.height / 2 - element.height / 2;\n var offsets;\n\n switch (basePlacement) {\n case top:\n offsets = {\n x: commonX,\n y: reference.y - element.height\n };\n break;\n\n case bottom:\n offsets = {\n x: commonX,\n y: reference.y + reference.height\n };\n break;\n\n case right:\n offsets = {\n x: reference.x + reference.width,\n y: commonY\n };\n break;\n\n case left:\n offsets = {\n x: reference.x - element.width,\n y: commonY\n };\n break;\n\n default:\n offsets = {\n x: reference.x,\n y: reference.y\n };\n }\n\n var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;\n\n if (mainAxis != null) {\n var len = mainAxis === 'y' ? 'height' : 'width';\n\n switch (variation) {\n case start:\n offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2);\n break;\n\n case end:\n offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2);\n break;\n\n default:\n }\n }\n\n return offsets;\n}","import getClippingRect from \"../dom-utils/getClippingRect.js\";\nimport getDocumentElement from \"../dom-utils/getDocumentElement.js\";\nimport getBoundingClientRect from \"../dom-utils/getBoundingClientRect.js\";\nimport computeOffsets from \"./computeOffsets.js\";\nimport rectToClientRect from \"./rectToClientRect.js\";\nimport { clippingParents, reference, popper, bottom, top, right, basePlacements, viewport } from \"../enums.js\";\nimport { isElement } from \"../dom-utils/instanceOf.js\";\nimport mergePaddingObject from \"./mergePaddingObject.js\";\nimport expandToHashMap from \"./expandToHashMap.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport default function detectOverflow(state, options) {\n if (options === void 0) {\n options = {};\n }\n\n var _options = options,\n _options$placement = _options.placement,\n placement = _options$placement === void 0 ? state.placement : _options$placement,\n _options$strategy = _options.strategy,\n strategy = _options$strategy === void 0 ? state.strategy : _options$strategy,\n _options$boundary = _options.boundary,\n boundary = _options$boundary === void 0 ? clippingParents : _options$boundary,\n _options$rootBoundary = _options.rootBoundary,\n rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary,\n _options$elementConte = _options.elementContext,\n elementContext = _options$elementConte === void 0 ? popper : _options$elementConte,\n _options$altBoundary = _options.altBoundary,\n altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary,\n _options$padding = _options.padding,\n padding = _options$padding === void 0 ? 0 : _options$padding;\n var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n var altContext = elementContext === popper ? reference : popper;\n var popperRect = state.rects.popper;\n var element = state.elements[altBoundary ? altContext : elementContext];\n var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary, strategy);\n var referenceClientRect = getBoundingClientRect(state.elements.reference);\n var popperOffsets = computeOffsets({\n reference: referenceClientRect,\n element: popperRect,\n strategy: 'absolute',\n placement: placement\n });\n var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets));\n var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect\n // 0 or negative = within the clipping rect\n\n var overflowOffsets = {\n top: clippingClientRect.top - elementClientRect.top + paddingObject.top,\n bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,\n left: clippingClientRect.left - elementClientRect.left + paddingObject.left,\n right: elementClientRect.right - clippingClientRect.right + paddingObject.right\n };\n var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element\n\n if (elementContext === popper && offsetData) {\n var offset = offsetData[placement];\n Object.keys(overflowOffsets).forEach(function (key) {\n var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;\n var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x';\n overflowOffsets[key] += offset[axis] * multiply;\n });\n }\n\n return overflowOffsets;\n}","import getVariation from \"./getVariation.js\";\nimport { variationPlacements, basePlacements, placements as allPlacements } from \"../enums.js\";\nimport detectOverflow from \"./detectOverflow.js\";\nimport getBasePlacement from \"./getBasePlacement.js\";\nexport default function computeAutoPlacement(state, options) {\n if (options === void 0) {\n options = {};\n }\n\n var _options = options,\n placement = _options.placement,\n boundary = _options.boundary,\n rootBoundary = _options.rootBoundary,\n padding = _options.padding,\n flipVariations = _options.flipVariations,\n _options$allowedAutoP = _options.allowedAutoPlacements,\n allowedAutoPlacements = _options$allowedAutoP === void 0 ? allPlacements : _options$allowedAutoP;\n var variation = getVariation(placement);\n var placements = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) {\n return getVariation(placement) === variation;\n }) : basePlacements;\n var allowedPlacements = placements.filter(function (placement) {\n return allowedAutoPlacements.indexOf(placement) >= 0;\n });\n\n if (allowedPlacements.length === 0) {\n allowedPlacements = placements;\n } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions...\n\n\n var overflows = allowedPlacements.reduce(function (acc, placement) {\n acc[placement] = detectOverflow(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding\n })[getBasePlacement(placement)];\n return acc;\n }, {});\n return Object.keys(overflows).sort(function (a, b) {\n return overflows[a] - overflows[b];\n });\n}","import getOppositePlacement from \"../utils/getOppositePlacement.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getOppositeVariationPlacement from \"../utils/getOppositeVariationPlacement.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\nimport computeAutoPlacement from \"../utils/computeAutoPlacement.js\";\nimport { bottom, top, start, right, left, auto } from \"../enums.js\";\nimport getVariation from \"../utils/getVariation.js\"; // eslint-disable-next-line import/no-unused-modules\n\nfunction getExpandedFallbackPlacements(placement) {\n if (getBasePlacement(placement) === auto) {\n return [];\n }\n\n var oppositePlacement = getOppositePlacement(placement);\n return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];\n}\n\nfunction flip(_ref) {\n var state = _ref.state,\n options = _ref.options,\n name = _ref.name;\n\n if (state.modifiersData[name]._skip) {\n return;\n }\n\n var _options$mainAxis = options.mainAxis,\n checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n _options$altAxis = options.altAxis,\n checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis,\n specifiedFallbackPlacements = options.fallbackPlacements,\n padding = options.padding,\n boundary = options.boundary,\n rootBoundary = options.rootBoundary,\n altBoundary = options.altBoundary,\n _options$flipVariatio = options.flipVariations,\n flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio,\n allowedAutoPlacements = options.allowedAutoPlacements;\n var preferredPlacement = state.options.placement;\n var basePlacement = getBasePlacement(preferredPlacement);\n var isBasePlacement = basePlacement === preferredPlacement;\n var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement));\n var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) {\n return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding,\n flipVariations: flipVariations,\n allowedAutoPlacements: allowedAutoPlacements\n }) : placement);\n }, []);\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var checksMap = new Map();\n var makeFallbackChecks = true;\n var firstFittingPlacement = placements[0];\n\n for (var i = 0; i < placements.length; i++) {\n var placement = placements[i];\n\n var _basePlacement = getBasePlacement(placement);\n\n var isStartVariation = getVariation(placement) === start;\n var isVertical = [top, bottom].indexOf(_basePlacement) >= 0;\n var len = isVertical ? 'width' : 'height';\n var overflow = detectOverflow(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n altBoundary: altBoundary,\n padding: padding\n });\n var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top;\n\n if (referenceRect[len] > popperRect[len]) {\n mainVariationSide = getOppositePlacement(mainVariationSide);\n }\n\n var altVariationSide = getOppositePlacement(mainVariationSide);\n var checks = [];\n\n if (checkMainAxis) {\n checks.push(overflow[_basePlacement] <= 0);\n }\n\n if (checkAltAxis) {\n checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0);\n }\n\n if (checks.every(function (check) {\n return check;\n })) {\n firstFittingPlacement = placement;\n makeFallbackChecks = false;\n break;\n }\n\n checksMap.set(placement, checks);\n }\n\n if (makeFallbackChecks) {\n // `2` may be desired in some cases – research later\n var numberOfChecks = flipVariations ? 3 : 1;\n\n var _loop = function _loop(_i) {\n var fittingPlacement = placements.find(function (placement) {\n var checks = checksMap.get(placement);\n\n if (checks) {\n return checks.slice(0, _i).every(function (check) {\n return check;\n });\n }\n });\n\n if (fittingPlacement) {\n firstFittingPlacement = fittingPlacement;\n return \"break\";\n }\n };\n\n for (var _i = numberOfChecks; _i > 0; _i--) {\n var _ret = _loop(_i);\n\n if (_ret === \"break\") break;\n }\n }\n\n if (state.placement !== firstFittingPlacement) {\n state.modifiersData[name]._skip = true;\n state.placement = firstFittingPlacement;\n state.reset = true;\n }\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'flip',\n enabled: true,\n phase: 'main',\n fn: flip,\n requiresIfExists: ['offset'],\n data: {\n _skip: false\n }\n};","import { top, bottom, left, right } from \"../enums.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\n\nfunction getSideOffsets(overflow, rect, preventedOffsets) {\n if (preventedOffsets === void 0) {\n preventedOffsets = {\n x: 0,\n y: 0\n };\n }\n\n return {\n top: overflow.top - rect.height - preventedOffsets.y,\n right: overflow.right - rect.width + preventedOffsets.x,\n bottom: overflow.bottom - rect.height + preventedOffsets.y,\n left: overflow.left - rect.width - preventedOffsets.x\n };\n}\n\nfunction isAnySideFullyClipped(overflow) {\n return [top, right, bottom, left].some(function (side) {\n return overflow[side] >= 0;\n });\n}\n\nfunction hide(_ref) {\n var state = _ref.state,\n name = _ref.name;\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var preventedOffsets = state.modifiersData.preventOverflow;\n var referenceOverflow = detectOverflow(state, {\n elementContext: 'reference'\n });\n var popperAltOverflow = detectOverflow(state, {\n altBoundary: true\n });\n var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);\n var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);\n var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);\n var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);\n state.modifiersData[name] = {\n referenceClippingOffsets: referenceClippingOffsets,\n popperEscapeOffsets: popperEscapeOffsets,\n isReferenceHidden: isReferenceHidden,\n hasPopperEscaped: hasPopperEscaped\n };\n state.attributes.popper = Object.assign({}, state.attributes.popper, {\n 'data-popper-reference-hidden': isReferenceHidden,\n 'data-popper-escaped': hasPopperEscaped\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'hide',\n enabled: true,\n phase: 'main',\n requiresIfExists: ['preventOverflow'],\n fn: hide\n};","import getBasePlacement from \"../utils/getBasePlacement.js\";\nimport { top, left, right, placements } from \"../enums.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport function distanceAndSkiddingToXY(placement, rects, offset) {\n var basePlacement = getBasePlacement(placement);\n var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1;\n\n var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, {\n placement: placement\n })) : offset,\n skidding = _ref[0],\n distance = _ref[1];\n\n skidding = skidding || 0;\n distance = (distance || 0) * invertDistance;\n return [left, right].indexOf(basePlacement) >= 0 ? {\n x: distance,\n y: skidding\n } : {\n x: skidding,\n y: distance\n };\n}\n\nfunction offset(_ref2) {\n var state = _ref2.state,\n options = _ref2.options,\n name = _ref2.name;\n var _options$offset = options.offset,\n offset = _options$offset === void 0 ? [0, 0] : _options$offset;\n var data = placements.reduce(function (acc, placement) {\n acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset);\n return acc;\n }, {});\n var _data$state$placement = data[state.placement],\n x = _data$state$placement.x,\n y = _data$state$placement.y;\n\n if (state.modifiersData.popperOffsets != null) {\n state.modifiersData.popperOffsets.x += x;\n state.modifiersData.popperOffsets.y += y;\n }\n\n state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'offset',\n enabled: true,\n phase: 'main',\n requires: ['popperOffsets'],\n fn: offset\n};","import computeOffsets from \"../utils/computeOffsets.js\";\n\nfunction popperOffsets(_ref) {\n var state = _ref.state,\n name = _ref.name;\n // Offsets are the actual position the popper needs to have to be\n // properly positioned near its reference element\n // This is the most basic placement, and will be adjusted by\n // the modifiers in the next step\n state.modifiersData[name] = computeOffsets({\n reference: state.rects.reference,\n element: state.rects.popper,\n strategy: 'absolute',\n placement: state.placement\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'popperOffsets',\n enabled: true,\n phase: 'read',\n fn: popperOffsets,\n data: {}\n};","import { top, left, right, bottom, start } from \"../enums.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getMainAxisFromPlacement from \"../utils/getMainAxisFromPlacement.js\";\nimport getAltAxis from \"../utils/getAltAxis.js\";\nimport { within, withinMaxClamp } from \"../utils/within.js\";\nimport getLayoutRect from \"../dom-utils/getLayoutRect.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\nimport getVariation from \"../utils/getVariation.js\";\nimport getFreshSideObject from \"../utils/getFreshSideObject.js\";\nimport { min as mathMin, max as mathMax } from \"../utils/math.js\";\n\nfunction preventOverflow(_ref) {\n var state = _ref.state,\n options = _ref.options,\n name = _ref.name;\n var _options$mainAxis = options.mainAxis,\n checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n _options$altAxis = options.altAxis,\n checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis,\n boundary = options.boundary,\n rootBoundary = options.rootBoundary,\n altBoundary = options.altBoundary,\n padding = options.padding,\n _options$tether = options.tether,\n tether = _options$tether === void 0 ? true : _options$tether,\n _options$tetherOffset = options.tetherOffset,\n tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;\n var overflow = detectOverflow(state, {\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding,\n altBoundary: altBoundary\n });\n var basePlacement = getBasePlacement(state.placement);\n var variation = getVariation(state.placement);\n var isBasePlacement = !variation;\n var mainAxis = getMainAxisFromPlacement(basePlacement);\n var altAxis = getAltAxis(mainAxis);\n var popperOffsets = state.modifiersData.popperOffsets;\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, {\n placement: state.placement\n })) : tetherOffset;\n var normalizedTetherOffsetValue = typeof tetherOffsetValue === 'number' ? {\n mainAxis: tetherOffsetValue,\n altAxis: tetherOffsetValue\n } : Object.assign({\n mainAxis: 0,\n altAxis: 0\n }, tetherOffsetValue);\n var offsetModifierState = state.modifiersData.offset ? state.modifiersData.offset[state.placement] : null;\n var data = {\n x: 0,\n y: 0\n };\n\n if (!popperOffsets) {\n return;\n }\n\n if (checkMainAxis) {\n var _offsetModifierState$;\n\n var mainSide = mainAxis === 'y' ? top : left;\n var altSide = mainAxis === 'y' ? bottom : right;\n var len = mainAxis === 'y' ? 'height' : 'width';\n var offset = popperOffsets[mainAxis];\n var min = offset + overflow[mainSide];\n var max = offset - overflow[altSide];\n var additive = tether ? -popperRect[len] / 2 : 0;\n var minLen = variation === start ? referenceRect[len] : popperRect[len];\n var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go\n // outside the reference bounds\n\n var arrowElement = state.elements.arrow;\n var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {\n width: 0,\n height: 0\n };\n var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();\n var arrowPaddingMin = arrowPaddingObject[mainSide];\n var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want\n // to include its full size in the calculation. If the reference is small\n // and near the edge of a boundary, the popper can overflow even if the\n // reference is not overflowing as well (e.g. virtual elements with no\n // width or height)\n\n var arrowLen = within(0, referenceRect[len], arrowRect[len]);\n var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis : minLen - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis;\n var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis : maxLen + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis;\n var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);\n var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;\n var offsetModifierValue = (_offsetModifierState$ = offsetModifierState == null ? void 0 : offsetModifierState[mainAxis]) != null ? _offsetModifierState$ : 0;\n var tetherMin = offset + minOffset - offsetModifierValue - clientOffset;\n var tetherMax = offset + maxOffset - offsetModifierValue;\n var preventedOffset = within(tether ? mathMin(min, tetherMin) : min, offset, tether ? mathMax(max, tetherMax) : max);\n popperOffsets[mainAxis] = preventedOffset;\n data[mainAxis] = preventedOffset - offset;\n }\n\n if (checkAltAxis) {\n var _offsetModifierState$2;\n\n var _mainSide = mainAxis === 'x' ? top : left;\n\n var _altSide = mainAxis === 'x' ? bottom : right;\n\n var _offset = popperOffsets[altAxis];\n\n var _len = altAxis === 'y' ? 'height' : 'width';\n\n var _min = _offset + overflow[_mainSide];\n\n var _max = _offset - overflow[_altSide];\n\n var isOriginSide = [top, left].indexOf(basePlacement) !== -1;\n\n var _offsetModifierValue = (_offsetModifierState$2 = offsetModifierState == null ? void 0 : offsetModifierState[altAxis]) != null ? _offsetModifierState$2 : 0;\n\n var _tetherMin = isOriginSide ? _min : _offset - referenceRect[_len] - popperRect[_len] - _offsetModifierValue + normalizedTetherOffsetValue.altAxis;\n\n var _tetherMax = isOriginSide ? _offset + referenceRect[_len] + popperRect[_len] - _offsetModifierValue - normalizedTetherOffsetValue.altAxis : _max;\n\n var _preventedOffset = tether && isOriginSide ? withinMaxClamp(_tetherMin, _offset, _tetherMax) : within(tether ? _tetherMin : _min, _offset, tether ? _tetherMax : _max);\n\n popperOffsets[altAxis] = _preventedOffset;\n data[altAxis] = _preventedOffset - _offset;\n }\n\n state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'preventOverflow',\n enabled: true,\n phase: 'main',\n fn: preventOverflow,\n requiresIfExists: ['offset']\n};","export default function getAltAxis(axis) {\n return axis === 'x' ? 'y' : 'x';\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getNodeScroll from \"./getNodeScroll.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport isScrollParent from \"./isScrollParent.js\";\nimport { round } from \"../utils/math.js\";\n\nfunction isElementScaled(element) {\n var rect = element.getBoundingClientRect();\n var scaleX = round(rect.width) / element.offsetWidth || 1;\n var scaleY = round(rect.height) / element.offsetHeight || 1;\n return scaleX !== 1 || scaleY !== 1;\n} // Returns the composite rect of an element relative to its offsetParent.\n// Composite means it takes into account transforms as well as layout.\n\n\nexport default function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {\n if (isFixed === void 0) {\n isFixed = false;\n }\n\n var isOffsetParentAnElement = isHTMLElement(offsetParent);\n var offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent);\n var documentElement = getDocumentElement(offsetParent);\n var rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled, isFixed);\n var scroll = {\n scrollLeft: 0,\n scrollTop: 0\n };\n var offsets = {\n x: 0,\n y: 0\n };\n\n if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {\n if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078\n isScrollParent(documentElement)) {\n scroll = getNodeScroll(offsetParent);\n }\n\n if (isHTMLElement(offsetParent)) {\n offsets = getBoundingClientRect(offsetParent, true);\n offsets.x += offsetParent.clientLeft;\n offsets.y += offsetParent.clientTop;\n } else if (documentElement) {\n offsets.x = getWindowScrollBarX(documentElement);\n }\n }\n\n return {\n x: rect.left + scroll.scrollLeft - offsets.x,\n y: rect.top + scroll.scrollTop - offsets.y,\n width: rect.width,\n height: rect.height\n };\n}","import getWindowScroll from \"./getWindowScroll.js\";\nimport getWindow from \"./getWindow.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nimport getHTMLElementScroll from \"./getHTMLElementScroll.js\";\nexport default function getNodeScroll(node) {\n if (node === getWindow(node) || !isHTMLElement(node)) {\n return getWindowScroll(node);\n } else {\n return getHTMLElementScroll(node);\n }\n}","export default function getHTMLElementScroll(element) {\n return {\n scrollLeft: element.scrollLeft,\n scrollTop: element.scrollTop\n };\n}","import { modifierPhases } from \"../enums.js\"; // source: https://stackoverflow.com/questions/49875255\n\nfunction order(modifiers) {\n var map = new Map();\n var visited = new Set();\n var result = [];\n modifiers.forEach(function (modifier) {\n map.set(modifier.name, modifier);\n }); // On visiting object, check for its dependencies and visit them recursively\n\n function sort(modifier) {\n visited.add(modifier.name);\n var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);\n requires.forEach(function (dep) {\n if (!visited.has(dep)) {\n var depModifier = map.get(dep);\n\n if (depModifier) {\n sort(depModifier);\n }\n }\n });\n result.push(modifier);\n }\n\n modifiers.forEach(function (modifier) {\n if (!visited.has(modifier.name)) {\n // check for visited object\n sort(modifier);\n }\n });\n return result;\n}\n\nexport default function orderModifiers(modifiers) {\n // order based on dependencies\n var orderedModifiers = order(modifiers); // order based on phase\n\n return modifierPhases.reduce(function (acc, phase) {\n return acc.concat(orderedModifiers.filter(function (modifier) {\n return modifier.phase === phase;\n }));\n }, []);\n}","import getCompositeRect from \"./dom-utils/getCompositeRect.js\";\nimport getLayoutRect from \"./dom-utils/getLayoutRect.js\";\nimport listScrollParents from \"./dom-utils/listScrollParents.js\";\nimport getOffsetParent from \"./dom-utils/getOffsetParent.js\";\nimport orderModifiers from \"./utils/orderModifiers.js\";\nimport debounce from \"./utils/debounce.js\";\nimport mergeByName from \"./utils/mergeByName.js\";\nimport detectOverflow from \"./utils/detectOverflow.js\";\nimport { isElement } from \"./dom-utils/instanceOf.js\";\nvar DEFAULT_OPTIONS = {\n placement: 'bottom',\n modifiers: [],\n strategy: 'absolute'\n};\n\nfunction areValidElements() {\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n return !args.some(function (element) {\n return !(element && typeof element.getBoundingClientRect === 'function');\n });\n}\n\nexport function popperGenerator(generatorOptions) {\n if (generatorOptions === void 0) {\n generatorOptions = {};\n }\n\n var _generatorOptions = generatorOptions,\n _generatorOptions$def = _generatorOptions.defaultModifiers,\n defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def,\n _generatorOptions$def2 = _generatorOptions.defaultOptions,\n defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;\n return function createPopper(reference, popper, options) {\n if (options === void 0) {\n options = defaultOptions;\n }\n\n var state = {\n placement: 'bottom',\n orderedModifiers: [],\n options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions),\n modifiersData: {},\n elements: {\n reference: reference,\n popper: popper\n },\n attributes: {},\n styles: {}\n };\n var effectCleanupFns = [];\n var isDestroyed = false;\n var instance = {\n state: state,\n setOptions: function setOptions(setOptionsAction) {\n var options = typeof setOptionsAction === 'function' ? setOptionsAction(state.options) : setOptionsAction;\n cleanupModifierEffects();\n state.options = Object.assign({}, defaultOptions, state.options, options);\n state.scrollParents = {\n reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [],\n popper: listScrollParents(popper)\n }; // Orders the modifiers based on their dependencies and `phase`\n // properties\n\n var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers\n\n state.orderedModifiers = orderedModifiers.filter(function (m) {\n return m.enabled;\n });\n runModifierEffects();\n return instance.update();\n },\n // Sync update – it will always be executed, even if not necessary. This\n // is useful for low frequency updates where sync behavior simplifies the\n // logic.\n // For high frequency updates (e.g. `resize` and `scroll` events), always\n // prefer the async Popper#update method\n forceUpdate: function forceUpdate() {\n if (isDestroyed) {\n return;\n }\n\n var _state$elements = state.elements,\n reference = _state$elements.reference,\n popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements\n // anymore\n\n if (!areValidElements(reference, popper)) {\n return;\n } // Store the reference and popper rects to be read by modifiers\n\n\n state.rects = {\n reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'),\n popper: getLayoutRect(popper)\n }; // Modifiers have the ability to reset the current update cycle. The\n // most common use case for this is the `flip` modifier changing the\n // placement, which then needs to re-run all the modifiers, because the\n // logic was previously ran for the previous placement and is therefore\n // stale/incorrect\n\n state.reset = false;\n state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier\n // is filled with the initial data specified by the modifier. This means\n // it doesn't persist and is fresh on each update.\n // To ensure persistent data, use `${name}#persistent`\n\n state.orderedModifiers.forEach(function (modifier) {\n return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);\n });\n\n for (var index = 0; index < state.orderedModifiers.length; index++) {\n if (state.reset === true) {\n state.reset = false;\n index = -1;\n continue;\n }\n\n var _state$orderedModifie = state.orderedModifiers[index],\n fn = _state$orderedModifie.fn,\n _state$orderedModifie2 = _state$orderedModifie.options,\n _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2,\n name = _state$orderedModifie.name;\n\n if (typeof fn === 'function') {\n state = fn({\n state: state,\n options: _options,\n name: name,\n instance: instance\n }) || state;\n }\n }\n },\n // Async and optimistically optimized update – it will not be executed if\n // not necessary (debounced to run at most once-per-tick)\n update: debounce(function () {\n return new Promise(function (resolve) {\n instance.forceUpdate();\n resolve(state);\n });\n }),\n destroy: function destroy() {\n cleanupModifierEffects();\n isDestroyed = true;\n }\n };\n\n if (!areValidElements(reference, popper)) {\n return instance;\n }\n\n instance.setOptions(options).then(function (state) {\n if (!isDestroyed && options.onFirstUpdate) {\n options.onFirstUpdate(state);\n }\n }); // Modifiers have the ability to execute arbitrary code before the first\n // update cycle runs. They will be executed in the same order as the update\n // cycle. This is useful when a modifier adds some persistent data that\n // other modifiers need to use, but the modifier is run after the dependent\n // one.\n\n function runModifierEffects() {\n state.orderedModifiers.forEach(function (_ref) {\n var name = _ref.name,\n _ref$options = _ref.options,\n options = _ref$options === void 0 ? {} : _ref$options,\n effect = _ref.effect;\n\n if (typeof effect === 'function') {\n var cleanupFn = effect({\n state: state,\n name: name,\n instance: instance,\n options: options\n });\n\n var noopFn = function noopFn() {};\n\n effectCleanupFns.push(cleanupFn || noopFn);\n }\n });\n }\n\n function cleanupModifierEffects() {\n effectCleanupFns.forEach(function (fn) {\n return fn();\n });\n effectCleanupFns = [];\n }\n\n return instance;\n };\n}\nexport var createPopper = /*#__PURE__*/popperGenerator(); // eslint-disable-next-line import/no-unused-modules\n\nexport { detectOverflow };","export default function debounce(fn) {\n var pending;\n return function () {\n if (!pending) {\n pending = new Promise(function (resolve) {\n Promise.resolve().then(function () {\n pending = undefined;\n resolve(fn());\n });\n });\n }\n\n return pending;\n };\n}","export default function mergeByName(modifiers) {\n var merged = modifiers.reduce(function (merged, current) {\n var existing = merged[current.name];\n merged[current.name] = existing ? Object.assign({}, existing, current, {\n options: Object.assign({}, existing.options, current.options),\n data: Object.assign({}, existing.data, current.data)\n }) : current;\n return merged;\n }, {}); // IE11 does not support Object.values\n\n return Object.keys(merged).map(function (key) {\n return merged[key];\n });\n}","import { popperGenerator, detectOverflow } from \"./createPopper.js\";\nimport eventListeners from \"./modifiers/eventListeners.js\";\nimport popperOffsets from \"./modifiers/popperOffsets.js\";\nimport computeStyles from \"./modifiers/computeStyles.js\";\nimport applyStyles from \"./modifiers/applyStyles.js\";\nvar defaultModifiers = [eventListeners, popperOffsets, computeStyles, applyStyles];\nvar createPopper = /*#__PURE__*/popperGenerator({\n defaultModifiers: defaultModifiers\n}); // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper, popperGenerator, defaultModifiers, detectOverflow };","import { popperGenerator, detectOverflow } from \"./createPopper.js\";\nimport eventListeners from \"./modifiers/eventListeners.js\";\nimport popperOffsets from \"./modifiers/popperOffsets.js\";\nimport computeStyles from \"./modifiers/computeStyles.js\";\nimport applyStyles from \"./modifiers/applyStyles.js\";\nimport offset from \"./modifiers/offset.js\";\nimport flip from \"./modifiers/flip.js\";\nimport preventOverflow from \"./modifiers/preventOverflow.js\";\nimport arrow from \"./modifiers/arrow.js\";\nimport hide from \"./modifiers/hide.js\";\nvar defaultModifiers = [eventListeners, popperOffsets, computeStyles, applyStyles, offset, flip, preventOverflow, arrow, hide];\nvar createPopper = /*#__PURE__*/popperGenerator({\n defaultModifiers: defaultModifiers\n}); // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper, popperGenerator, defaultModifiers, detectOverflow }; // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper as createPopperLite } from \"./popper-lite.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport * from \"./modifiers/index.js\";","/**\n * --------------------------------------------------------------------------\n * Bootstrap dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n execute,\n getElement,\n getNextActiveElement,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'dropdown'\nconst DATA_KEY = 'bs.dropdown'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ESCAPE_KEY = 'Escape'\nconst TAB_KEY = 'Tab'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_DROPUP = 'dropup'\nconst CLASS_NAME_DROPEND = 'dropend'\nconst CLASS_NAME_DROPSTART = 'dropstart'\nconst CLASS_NAME_DROPUP_CENTER = 'dropup-center'\nconst CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"dropdown\"]:not(.disabled):not(:disabled)'\nconst SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`\nconst SELECTOR_MENU = '.dropdown-menu'\nconst SELECTOR_NAVBAR = '.navbar'\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav'\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'\nconst PLACEMENT_TOPCENTER = 'top'\nconst PLACEMENT_BOTTOMCENTER = 'bottom'\n\nconst Default = {\n autoClose: true,\n boundary: 'clippingParents',\n display: 'dynamic',\n offset: [0, 2],\n popperConfig: null,\n reference: 'toggle'\n}\n\nconst DefaultType = {\n autoClose: '(boolean|string)',\n boundary: '(string|element)',\n display: 'string',\n offset: '(array|string|function)',\n popperConfig: '(null|object|function)',\n reference: '(string|element|object)'\n}\n\n/**\n * Class definition\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._popper = null\n this._parent = this._element.parentNode // dropdown wrapper\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.prev(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.findOne(SELECTOR_MENU, this._parent)\n this._inNavbar = this._detectNavbar()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n return this._isShown() ? this.hide() : this.show()\n }\n\n show() {\n if (isDisabled(this._element) || this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._createPopper()\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n this._element.focus()\n this._element.setAttribute('aria-expanded', true)\n\n this._menu.classList.add(CLASS_NAME_SHOW)\n this._element.classList.add(CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)\n }\n\n hide() {\n if (isDisabled(this._element) || !this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n this._completeHide(relatedTarget)\n }\n\n dispose() {\n if (this._popper) {\n this._popper.destroy()\n }\n\n super.dispose()\n }\n\n update() {\n this._inNavbar = this._detectNavbar()\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Private\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n if (this._popper) {\n this._popper.destroy()\n }\n\n this._menu.classList.remove(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOW)\n this._element.setAttribute('aria-expanded', 'false')\n Manipulator.removeDataAttribute(this._menu, 'popper')\n EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)\n }\n\n _getConfig(config) {\n config = super._getConfig(config)\n\n if (typeof config.reference === 'object' && !isElement(config.reference) &&\n typeof config.reference.getBoundingClientRect !== 'function'\n ) {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`)\n }\n\n return config\n }\n\n _createPopper() {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org)')\n }\n\n let referenceElement = this._element\n\n if (this._config.reference === 'parent') {\n referenceElement = this._parent\n } else if (isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference)\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference\n }\n\n const popperConfig = this._getPopperConfig()\n this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)\n }\n\n _isShown() {\n return this._menu.classList.contains(CLASS_NAME_SHOW)\n }\n\n _getPlacement() {\n const parentDropdown = this._parent\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {\n return PLACEMENT_TOPCENTER\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {\n return PLACEMENT_BOTTOMCENTER\n }\n\n // We need to trim the value because custom properties can also include spaces\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP\n }\n\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM\n }\n\n _detectNavbar() {\n return this._element.closest(SELECTOR_NAVBAR) !== null\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n }\n\n // Disable Popper if we have a static display or Dropdown is in Navbar\n if (this._inNavbar || this._config.display === 'static') {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static') // TODO: v6 remove\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [defaultBsPopperConfig])\n }\n }\n\n _selectMenuItem({ key, target }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element))\n\n if (!items.length) {\n return\n }\n\n // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n\n static clearMenus(event) {\n if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) {\n return\n }\n\n const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN)\n\n for (const toggle of openToggles) {\n const context = Dropdown.getInstance(toggle)\n if (!context || context._config.autoClose === false) {\n continue\n }\n\n const composedPath = event.composedPath()\n const isMenuTarget = composedPath.includes(context._menu)\n if (\n composedPath.includes(context._element) ||\n (context._config.autoClose === 'inside' && !isMenuTarget) ||\n (context._config.autoClose === 'outside' && isMenuTarget)\n ) {\n continue\n }\n\n // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue\n }\n\n const relatedTarget = { relatedTarget: context._element }\n\n if (event.type === 'click') {\n relatedTarget.clickEvent = event\n }\n\n context._completeHide(relatedTarget)\n }\n }\n\n static dataApiKeydownHandler(event) {\n // If not an UP | DOWN | ESCAPE key => not a dropdown command\n // If input/textarea && if key is other than ESCAPE => not a dropdown command\n\n const isInput = /input|textarea/i.test(event.target.tagName)\n const isEscapeEvent = event.key === ESCAPE_KEY\n const isUpOrDownEvent = [ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)\n\n if (!isUpOrDownEvent && !isEscapeEvent) {\n return\n }\n\n if (isInput && !isEscapeEvent) {\n return\n }\n\n event.preventDefault()\n\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ?\n this :\n (SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.next(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, event.delegateTarget.parentNode))\n\n const instance = Dropdown.getOrCreateInstance(getToggleButton)\n\n if (isUpOrDownEvent) {\n event.stopPropagation()\n instance.show()\n instance._selectMenuItem(event)\n return\n }\n\n if (instance._isShown()) { // else is escape and we check if it is shown\n event.stopPropagation()\n instance.hide()\n getToggleButton.focus()\n }\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n event.preventDefault()\n Dropdown.getOrCreateInstance(this).toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Dropdown)\n\nexport default Dropdown\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport { execute, executeAfterTransition, getElement, reflow } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'backdrop'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`\n\nconst Default = {\n className: 'modal-backdrop',\n clickCallback: null,\n isAnimated: false,\n isVisible: true, // if false, we use the backdrop helper without adding any element to the dom\n rootElement: 'body' // give the choice to place backdrop under different elements\n}\n\nconst DefaultType = {\n className: 'string',\n clickCallback: '(function|null)',\n isAnimated: 'boolean',\n isVisible: 'boolean',\n rootElement: '(element|string)'\n}\n\n/**\n * Class definition\n */\n\nclass Backdrop extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isAppended = false\n this._element = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._append()\n\n const element = this._getElement()\n if (this._config.isAnimated) {\n reflow(element)\n }\n\n element.classList.add(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n execute(callback)\n })\n }\n\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._getElement().classList.remove(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n this.dispose()\n execute(callback)\n })\n }\n\n dispose() {\n if (!this._isAppended) {\n return\n }\n\n EventHandler.off(this._element, EVENT_MOUSEDOWN)\n\n this._element.remove()\n this._isAppended = false\n }\n\n // Private\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div')\n backdrop.className = this._config.className\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE)\n }\n\n this._element = backdrop\n }\n\n return this._element\n }\n\n _configAfterMerge(config) {\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement)\n return config\n }\n\n _append() {\n if (this._isAppended) {\n return\n }\n\n const element = this._getElement()\n this._config.rootElement.append(element)\n\n EventHandler.on(element, EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback)\n })\n\n this._isAppended = true\n }\n\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated)\n }\n}\n\nexport default Backdrop\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'focustrap'\nconst DATA_KEY = 'bs.focustrap'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`\n\nconst TAB_KEY = 'Tab'\nconst TAB_NAV_FORWARD = 'forward'\nconst TAB_NAV_BACKWARD = 'backward'\n\nconst Default = {\n autofocus: true,\n trapElement: null // The element to trap focus inside of\n}\n\nconst DefaultType = {\n autofocus: 'boolean',\n trapElement: 'element'\n}\n\n/**\n * Class definition\n */\n\nclass FocusTrap extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isActive = false\n this._lastTabNavDirection = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n activate() {\n if (this._isActive) {\n return\n }\n\n if (this._config.autofocus) {\n this._config.trapElement.focus()\n }\n\n EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))\n\n this._isActive = true\n }\n\n deactivate() {\n if (!this._isActive) {\n return\n }\n\n this._isActive = false\n EventHandler.off(document, EVENT_KEY)\n }\n\n // Private\n _handleFocusin(event) {\n const { trapElement } = this._config\n\n if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {\n return\n }\n\n const elements = SelectorEngine.focusableChildren(trapElement)\n\n if (elements.length === 0) {\n trapElement.focus()\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus()\n } else {\n elements[0].focus()\n }\n }\n\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return\n }\n\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD\n }\n}\n\nexport default FocusTrap\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'\nconst SELECTOR_STICKY_CONTENT = '.sticky-top'\nconst PROPERTY_PADDING = 'padding-right'\nconst PROPERTY_MARGIN = 'margin-right'\n\n/**\n * Class definition\n */\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body\n }\n\n // Public\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth\n return Math.abs(window.innerWidth - documentWidth)\n }\n\n hide() {\n const width = this.getWidth()\n this._disableOverFlow()\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width)\n }\n\n reset() {\n this._resetElementAttributes(this._element, 'overflow')\n this._resetElementAttributes(this._element, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN)\n }\n\n isOverflowing() {\n return this.getWidth() > 0\n }\n\n // Private\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow')\n this._element.style.overflow = 'hidden'\n }\n\n _setElementAttributes(selector, styleProperty, callback) {\n const scrollbarWidth = this.getWidth()\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return\n }\n\n this._saveInitialAttribute(element, styleProperty)\n const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)\n element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _saveInitialAttribute(element, styleProperty) {\n const actualValue = element.style.getPropertyValue(styleProperty)\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProperty, actualValue)\n }\n }\n\n _resetElementAttributes(selector, styleProperty) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProperty)\n // We only want to remove the property if the value is `null`; the value can also be zero\n if (value === null) {\n element.style.removeProperty(styleProperty)\n return\n }\n\n Manipulator.removeDataAttribute(element, styleProperty)\n element.style.setProperty(styleProperty, value)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector)\n return\n }\n\n for (const sel of SelectorEngine.find(selector, this._element)) {\n callBack(sel)\n }\n }\n}\n\nexport default ScrollBarHelper\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport { defineJQueryPlugin, isRTL, isVisible, reflow } from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'modal'\nconst DATA_KEY = 'bs.modal'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst ESCAPE_KEY = 'Escape'\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_OPEN = 'modal-open'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_STATIC = 'modal-static'\n\nconst OPEN_SELECTOR = '.modal.show'\nconst SELECTOR_DIALOG = '.modal-dialog'\nconst SELECTOR_MODAL_BODY = '.modal-body'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"modal\"]'\n\nconst Default = {\n backdrop: true,\n focus: true,\n keyboard: true\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n focus: 'boolean',\n keyboard: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._isShown = false\n this._isTransitioning = false\n this._scrollBar = new ScrollBarHelper()\n\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n relatedTarget\n })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._isTransitioning = true\n\n this._scrollBar.hide()\n\n document.body.classList.add(CLASS_NAME_OPEN)\n\n this._adjustDialog()\n\n this._backdrop.show(() => this._showElement(relatedTarget))\n }\n\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._isShown = false\n this._isTransitioning = true\n this._focustrap.deactivate()\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n this._queueCallback(() => this._hideModal(), this._element, this._isAnimated())\n }\n\n dispose() {\n EventHandler.off(window, EVENT_KEY)\n EventHandler.off(this._dialog, EVENT_KEY)\n\n this._backdrop.dispose()\n this._focustrap.deactivate()\n\n super.dispose()\n }\n\n handleUpdate() {\n this._adjustDialog()\n }\n\n // Private\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value,\n isAnimated: this._isAnimated()\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _showElement(relatedTarget) {\n // try to append dynamic modal\n if (!document.body.contains(this._element)) {\n document.body.append(this._element)\n }\n\n this._element.style.display = 'block'\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.scrollTop = 0\n\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)\n if (modalBody) {\n modalBody.scrollTop = 0\n }\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_SHOW)\n\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate()\n }\n\n this._isTransitioning = false\n EventHandler.trigger(this._element, EVENT_SHOWN, {\n relatedTarget\n })\n }\n\n this._queueCallback(transitionComplete, this._dialog, this._isAnimated())\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n this._triggerBackdropTransition()\n })\n\n EventHandler.on(window, EVENT_RESIZE, () => {\n if (this._isShown && !this._isTransitioning) {\n this._adjustDialog()\n }\n })\n\n EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {\n // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks\n EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {\n if (this._element !== event.target || this._element !== event2.target) {\n return\n }\n\n if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition()\n return\n }\n\n if (this._config.backdrop) {\n this.hide()\n }\n })\n })\n }\n\n _hideModal() {\n this._element.style.display = 'none'\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n this._isTransitioning = false\n\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN)\n this._resetAdjustments()\n this._scrollBar.reset()\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n })\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE)\n }\n\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const initialOverflowY = this._element.style.overflowY\n // return if the following background transition hasn't yet completed\n if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {\n return\n }\n\n if (!isModalOverflowing) {\n this._element.style.overflowY = 'hidden'\n }\n\n this._element.classList.add(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.classList.remove(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.style.overflowY = initialOverflowY\n }, this._dialog)\n }, this._dialog)\n\n this._element.focus()\n }\n\n /**\n * The following methods are used to handle overflowing modals\n */\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const scrollbarWidth = this._scrollBar.getWidth()\n const isBodyOverflowing = scrollbarWidth > 0\n\n if (isBodyOverflowing && !isModalOverflowing) {\n const property = isRTL() ? 'paddingLeft' : 'paddingRight'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n\n if (!isBodyOverflowing && isModalOverflowing) {\n const property = isRTL() ? 'paddingRight' : 'paddingLeft'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n }\n\n _resetAdjustments() {\n this._element.style.paddingLeft = ''\n this._element.style.paddingRight = ''\n }\n\n // Static\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](relatedTarget)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n EventHandler.one(target, EVENT_SHOW, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n if (isVisible(this)) {\n this.focus()\n }\n })\n })\n\n // avoid conflict when clicking modal toggler while another one is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen) {\n Modal.getInstance(alreadyOpen).hide()\n }\n\n const data = Modal.getOrCreateInstance(target)\n\n data.toggle(this)\n})\n\nenableDismissTrigger(Modal)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Modal)\n\nexport default Modal\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin,\n isDisabled,\n isVisible\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'offcanvas'\nconst DATA_KEY = 'bs.offcanvas'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst ESCAPE_KEY = 'Escape'\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\nconst CLASS_NAME_HIDING = 'hiding'\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop'\nconst OPEN_SELECTOR = '.offcanvas.show'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"offcanvas\"]'\n\nconst Default = {\n backdrop: true,\n keyboard: true,\n scroll: false\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n scroll: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isShown = false\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { relatedTarget })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._backdrop.show()\n\n if (!this._config.scroll) {\n new ScrollBarHelper().hide()\n }\n\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.classList.add(CLASS_NAME_SHOWING)\n\n const completeCallBack = () => {\n if (!this._config.scroll || this._config.backdrop) {\n this._focustrap.activate()\n }\n\n this._element.classList.add(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })\n }\n\n this._queueCallback(completeCallBack, this._element, true)\n }\n\n hide() {\n if (!this._isShown) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._focustrap.deactivate()\n this._element.blur()\n this._isShown = false\n this._element.classList.add(CLASS_NAME_HIDING)\n this._backdrop.hide()\n\n const completeCallback = () => {\n this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n\n if (!this._config.scroll) {\n new ScrollBarHelper().reset()\n }\n\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._queueCallback(completeCallback, this._element, true)\n }\n\n dispose() {\n this._backdrop.dispose()\n this._focustrap.deactivate()\n super.dispose()\n }\n\n // Private\n _initializeBackDrop() {\n const clickCallback = () => {\n if (this._config.backdrop === 'static') {\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n return\n }\n\n this.hide()\n }\n\n // 'static' option will be translated to true, and booleans will keep their value\n const isVisible = Boolean(this._config.backdrop)\n\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: isVisible ? clickCallback : null\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n })\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus()\n }\n })\n\n // avoid conflict when clicking a toggler of an offcanvas, while another is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen && alreadyOpen !== target) {\n Offcanvas.getInstance(alreadyOpen).hide()\n }\n\n const data = Offcanvas.getOrCreateInstance(target)\n data.toggle(this)\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {\n Offcanvas.getOrCreateInstance(selector).show()\n }\n})\n\nEventHandler.on(window, EVENT_RESIZE, () => {\n for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {\n if (getComputedStyle(element).position !== 'fixed') {\n Offcanvas.getOrCreateInstance(element).hide()\n }\n }\n})\n\nenableDismissTrigger(Offcanvas)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Offcanvas)\n\nexport default Offcanvas\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n// js-docs-start allow-list\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i\n\nexport const DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n div: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n}\n// js-docs-end allow-list\n\nconst uriAttributes = new Set([\n 'background',\n 'cite',\n 'href',\n 'itemtype',\n 'longdesc',\n 'poster',\n 'src',\n 'xlink:href'\n])\n\n/**\n * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation\n * contexts.\n *\n * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38\n */\n// eslint-disable-next-line unicorn/better-regex\nconst SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i\n\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase()\n\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue))\n }\n\n return true\n }\n\n // Check if a regular expression validates the attribute.\n return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)\n .some(regex => regex.test(attributeName))\n}\n\nexport function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {\n if (!unsafeHtml.length) {\n return unsafeHtml\n }\n\n if (sanitizeFunction && typeof sanitizeFunction === 'function') {\n return sanitizeFunction(unsafeHtml)\n }\n\n const domParser = new window.DOMParser()\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'))\n\n for (const element of elements) {\n const elementName = element.nodeName.toLowerCase()\n\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove()\n continue\n }\n\n const attributeList = [].concat(...element.attributes)\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])\n\n for (const attribute of attributeList) {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName)\n }\n }\n }\n\n return createdDocument.body.innerHTML\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/template-factory.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\nimport { DefaultAllowlist, sanitizeHtml } from './sanitizer.js'\nimport { execute, getElement, isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'TemplateFactory'\n\nconst Default = {\n allowList: DefaultAllowlist,\n content: {}, // { selector : text , selector2 : text2 , }\n extraClass: '',\n html: false,\n sanitize: true,\n sanitizeFn: null,\n template: '
    '\n}\n\nconst DefaultType = {\n allowList: 'object',\n content: 'object',\n extraClass: '(string|function)',\n html: 'boolean',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n template: 'string'\n}\n\nconst DefaultContentType = {\n entry: '(string|element|function|null)',\n selector: '(string|element)'\n}\n\n/**\n * Class definition\n */\n\nclass TemplateFactory extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n getContent() {\n return Object.values(this._config.content)\n .map(config => this._resolvePossibleFunction(config))\n .filter(Boolean)\n }\n\n hasContent() {\n return this.getContent().length > 0\n }\n\n changeContent(content) {\n this._checkContent(content)\n this._config.content = { ...this._config.content, ...content }\n return this\n }\n\n toHtml() {\n const templateWrapper = document.createElement('div')\n templateWrapper.innerHTML = this._maybeSanitize(this._config.template)\n\n for (const [selector, text] of Object.entries(this._config.content)) {\n this._setContent(templateWrapper, text, selector)\n }\n\n const template = templateWrapper.children[0]\n const extraClass = this._resolvePossibleFunction(this._config.extraClass)\n\n if (extraClass) {\n template.classList.add(...extraClass.split(' '))\n }\n\n return template\n }\n\n // Private\n _typeCheckConfig(config) {\n super._typeCheckConfig(config)\n this._checkContent(config.content)\n }\n\n _checkContent(arg) {\n for (const [selector, content] of Object.entries(arg)) {\n super._typeCheckConfig({ selector, entry: content }, DefaultContentType)\n }\n }\n\n _setContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template)\n\n if (!templateElement) {\n return\n }\n\n content = this._resolvePossibleFunction(content)\n\n if (!content) {\n templateElement.remove()\n return\n }\n\n if (isElement(content)) {\n this._putElementInTemplate(getElement(content), templateElement)\n return\n }\n\n if (this._config.html) {\n templateElement.innerHTML = this._maybeSanitize(content)\n return\n }\n\n templateElement.textContent = content\n }\n\n _maybeSanitize(arg) {\n return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [this])\n }\n\n _putElementInTemplate(element, templateElement) {\n if (this._config.html) {\n templateElement.innerHTML = ''\n templateElement.append(element)\n return\n }\n\n templateElement.textContent = element.textContent\n }\n}\n\nexport default TemplateFactory\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport { defineJQueryPlugin, execute, findShadowRoot, getElement, getUID, isRTL, noop } from './util/index.js'\nimport { DefaultAllowlist } from './util/sanitizer.js'\nimport TemplateFactory from './util/template-factory.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tooltip'\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn'])\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_MODAL = 'modal'\nconst CLASS_NAME_SHOW = 'show'\n\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner'\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`\n\nconst EVENT_MODAL_HIDE = 'hide.bs.modal'\n\nconst TRIGGER_HOVER = 'hover'\nconst TRIGGER_FOCUS = 'focus'\nconst TRIGGER_CLICK = 'click'\nconst TRIGGER_MANUAL = 'manual'\n\nconst EVENT_HIDE = 'hide'\nconst EVENT_HIDDEN = 'hidden'\nconst EVENT_SHOW = 'show'\nconst EVENT_SHOWN = 'shown'\nconst EVENT_INSERTED = 'inserted'\nconst EVENT_CLICK = 'click'\nconst EVENT_FOCUSIN = 'focusin'\nconst EVENT_FOCUSOUT = 'focusout'\nconst EVENT_MOUSEENTER = 'mouseenter'\nconst EVENT_MOUSELEAVE = 'mouseleave'\n\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n}\n\nconst Default = {\n allowList: DefaultAllowlist,\n animation: true,\n boundary: 'clippingParents',\n container: false,\n customClass: '',\n delay: 0,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n html: false,\n offset: [0, 6],\n placement: 'top',\n popperConfig: null,\n sanitize: true,\n sanitizeFn: null,\n selector: false,\n template: '
    ' +\n '
    ' +\n '
    ' +\n '
    ',\n title: '',\n trigger: 'hover focus'\n}\n\nconst DefaultType = {\n allowList: 'object',\n animation: 'boolean',\n boundary: '(string|element)',\n container: '(string|element|boolean)',\n customClass: '(string|function)',\n delay: '(number|object)',\n fallbackPlacements: 'array',\n html: 'boolean',\n offset: '(array|string|function)',\n placement: '(string|function)',\n popperConfig: '(null|object|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n selector: '(string|boolean)',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string'\n}\n\n/**\n * Class definition\n */\n\nclass Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org)')\n }\n\n super(element, config)\n\n // Private\n this._isEnabled = true\n this._timeout = 0\n this._isHovered = null\n this._activeTrigger = {}\n this._popper = null\n this._templateFactory = null\n this._newContent = null\n\n // Protected\n this.tip = null\n\n this._setListeners()\n\n if (!this._config.selector) {\n this._fixTitle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n enable() {\n this._isEnabled = true\n }\n\n disable() {\n this._isEnabled = false\n }\n\n toggleEnabled() {\n this._isEnabled = !this._isEnabled\n }\n\n toggle() {\n if (!this._isEnabled) {\n return\n }\n\n this._activeTrigger.click = !this._activeTrigger.click\n if (this._isShown()) {\n this._leave()\n return\n }\n\n this._enter()\n }\n\n dispose() {\n clearTimeout(this._timeout)\n\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n\n if (this._element.getAttribute('data-bs-original-title')) {\n this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'))\n }\n\n this._disposePopper()\n super.dispose()\n }\n\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements')\n }\n\n if (!(this._isWithContent() && this._isEnabled)) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW))\n const shadowRoot = findShadowRoot(this._element)\n const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element)\n\n if (showEvent.defaultPrevented || !isInTheDom) {\n return\n }\n\n // TODO: v6 remove this or make it optional\n this._disposePopper()\n\n const tip = this._getTipElement()\n\n this._element.setAttribute('aria-describedby', tip.getAttribute('id'))\n\n const { container } = this._config\n\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip)\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED))\n }\n\n this._popper = this._createPopper(tip)\n\n tip.classList.add(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n const complete = () => {\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN))\n\n if (this._isHovered === false) {\n this._leave()\n }\n\n this._isHovered = false\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n hide() {\n if (!this._isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE))\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const tip = this._getTipElement()\n tip.classList.remove(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false\n this._activeTrigger[TRIGGER_FOCUS] = false\n this._activeTrigger[TRIGGER_HOVER] = false\n this._isHovered = null // it is a trick to support manual triggering\n\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n if (!this._isHovered) {\n this._disposePopper()\n }\n\n this._element.removeAttribute('aria-describedby')\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN))\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n update() {\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Protected\n _isWithContent() {\n return Boolean(this._getTitle())\n }\n\n _getTipElement() {\n if (!this.tip) {\n this.tip = this._createTipElement(this._newContent || this._getContentForTemplate())\n }\n\n return this.tip\n }\n\n _createTipElement(content) {\n const tip = this._getTemplateFactory(content).toHtml()\n\n // TODO: remove this check in v6\n if (!tip) {\n return null\n }\n\n tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)\n // TODO: v6 the following can be achieved with CSS only\n tip.classList.add(`bs-${this.constructor.NAME}-auto`)\n\n const tipId = getUID(this.constructor.NAME).toString()\n\n tip.setAttribute('id', tipId)\n\n if (this._isAnimated()) {\n tip.classList.add(CLASS_NAME_FADE)\n }\n\n return tip\n }\n\n setContent(content) {\n this._newContent = content\n if (this._isShown()) {\n this._disposePopper()\n this.show()\n }\n }\n\n _getTemplateFactory(content) {\n if (this._templateFactory) {\n this._templateFactory.changeContent(content)\n } else {\n this._templateFactory = new TemplateFactory({\n ...this._config,\n // the `content` var has to be after `this._config`\n // to override config.content in case of popover\n content,\n extraClass: this._resolvePossibleFunction(this._config.customClass)\n })\n }\n\n return this._templateFactory\n }\n\n _getContentForTemplate() {\n return {\n [SELECTOR_TOOLTIP_INNER]: this._getTitle()\n }\n }\n\n _getTitle() {\n return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title')\n }\n\n // Private\n _initializeOnDelegatedTarget(event) {\n return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig())\n }\n\n _isAnimated() {\n return this._config.animation || (this.tip && this.tip.classList.contains(CLASS_NAME_FADE))\n }\n\n _isShown() {\n return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW)\n }\n\n _createPopper(tip) {\n const placement = execute(this._config.placement, [this, tip, this._element])\n const attachment = AttachmentMap[placement.toUpperCase()]\n return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [this._element])\n }\n\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [\n {\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n },\n {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n },\n {\n name: 'preSetPlacement',\n enabled: true,\n phase: 'beforeMain',\n fn: data => {\n // Pre-set Popper's placement attribute in order to read the arrow sizes properly.\n // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement\n this._getTipElement().setAttribute('data-popper-placement', data.state.placement)\n }\n }\n ]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [defaultBsPopperConfig])\n }\n }\n\n _setListeners() {\n const triggers = this._config.trigger.split(' ')\n\n for (const trigger of triggers) {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context.toggle()\n })\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSEENTER) :\n this.constructor.eventName(EVENT_FOCUSIN)\n const eventOut = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSELEAVE) :\n this.constructor.eventName(EVENT_FOCUSOUT)\n\n EventHandler.on(this._element, eventIn, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true\n context._enter()\n })\n EventHandler.on(this._element, eventOut, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] =\n context._element.contains(event.relatedTarget)\n\n context._leave()\n })\n }\n }\n\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide()\n }\n }\n\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n }\n\n _fixTitle() {\n const title = this._element.getAttribute('title')\n\n if (!title) {\n return\n }\n\n if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {\n this._element.setAttribute('aria-label', title)\n }\n\n this._element.setAttribute('data-bs-original-title', title) // DO NOT USE IT. Is only for backwards compatibility\n this._element.removeAttribute('title')\n }\n\n _enter() {\n if (this._isShown() || this._isHovered) {\n this._isHovered = true\n return\n }\n\n this._isHovered = true\n\n this._setTimeout(() => {\n if (this._isHovered) {\n this.show()\n }\n }, this._config.delay.show)\n }\n\n _leave() {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n this._isHovered = false\n\n this._setTimeout(() => {\n if (!this._isHovered) {\n this.hide()\n }\n }, this._config.delay.hide)\n }\n\n _setTimeout(handler, timeout) {\n clearTimeout(this._timeout)\n this._timeout = setTimeout(handler, timeout)\n }\n\n _isWithActiveTrigger() {\n return Object.values(this._activeTrigger).includes(true)\n }\n\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element)\n\n for (const dataAttribute of Object.keys(dataAttributes)) {\n if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {\n delete dataAttributes[dataAttribute]\n }\n }\n\n config = {\n ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n }\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n config.container = config.container === false ? document.body : getElement(config.container)\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n }\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString()\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString()\n }\n\n return config\n }\n\n _getDelegateConfig() {\n const config = {}\n\n for (const [key, value] of Object.entries(this._config)) {\n if (this.constructor.Default[key] !== value) {\n config[key] = value\n }\n }\n\n config.selector = false\n config.trigger = 'manual'\n\n // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n return config\n }\n\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy()\n this._popper = null\n }\n\n if (this.tip) {\n this.tip.remove()\n this.tip = null\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tooltip.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tooltip)\n\nexport default Tooltip\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Tooltip from './tooltip.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'popover'\n\nconst SELECTOR_TITLE = '.popover-header'\nconst SELECTOR_CONTENT = '.popover-body'\n\nconst Default = {\n ...Tooltip.Default,\n content: '',\n offset: [0, 8],\n placement: 'right',\n template: '
    ' +\n '
    ' +\n '

    ' +\n '
    ' +\n '
    ',\n trigger: 'click'\n}\n\nconst DefaultType = {\n ...Tooltip.DefaultType,\n content: '(null|string|element|function)'\n}\n\n/**\n * Class definition\n */\n\nclass Popover extends Tooltip {\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Overrides\n _isWithContent() {\n return this._getTitle() || this._getContent()\n }\n\n // Private\n _getContentForTemplate() {\n return {\n [SELECTOR_TITLE]: this._getTitle(),\n [SELECTOR_CONTENT]: this._getContent()\n }\n }\n\n _getContent() {\n return this._resolvePossibleFunction(this._config.content)\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Popover)\n\nexport default Popover\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport { defineJQueryPlugin, getElement, isDisabled, isVisible } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'scrollspy'\nconst DATA_KEY = 'bs.scrollspy'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_ACTIVATE = `activate${EVENT_KEY}`\nconst EVENT_CLICK = `click${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]'\nconst SELECTOR_TARGET_LINKS = '[href]'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_NAV_LINKS = '.nav-link'\nconst SELECTOR_NAV_ITEMS = '.nav-item'\nconst SELECTOR_LIST_ITEMS = '.list-group-item'\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\n\nconst Default = {\n offset: null, // TODO: v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: '0px 0px -25%',\n smoothScroll: false,\n target: null,\n threshold: [0.1, 0.5, 1]\n}\n\nconst DefaultType = {\n offset: '(number|null)', // TODO v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: 'string',\n smoothScroll: 'boolean',\n target: 'element',\n threshold: 'array'\n}\n\n/**\n * Class definition\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n // this._element is the observablesContainer and config.target the menu links wrapper\n this._targetLinks = new Map()\n this._observableSections = new Map()\n this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element\n this._activeTarget = null\n this._observer = null\n this._previousScrollData = {\n visibleEntryTop: 0,\n parentScrollTop: 0\n }\n this.refresh() // initialize\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n refresh() {\n this._initializeTargetsAndObservables()\n this._maybeEnableSmoothScroll()\n\n if (this._observer) {\n this._observer.disconnect()\n } else {\n this._observer = this._getNewObserver()\n }\n\n for (const section of this._observableSections.values()) {\n this._observer.observe(section)\n }\n }\n\n dispose() {\n this._observer.disconnect()\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case\n config.target = getElement(config.target) || document.body\n\n // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only\n config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin\n\n if (typeof config.threshold === 'string') {\n config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value))\n }\n\n return config\n }\n\n _maybeEnableSmoothScroll() {\n if (!this._config.smoothScroll) {\n return\n }\n\n // unregister any previous listeners\n EventHandler.off(this._config.target, EVENT_CLICK)\n\n EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {\n const observableSection = this._observableSections.get(event.target.hash)\n if (observableSection) {\n event.preventDefault()\n const root = this._rootElement || window\n const height = observableSection.offsetTop - this._element.offsetTop\n if (root.scrollTo) {\n root.scrollTo({ top: height, behavior: 'smooth' })\n return\n }\n\n // Chrome 60 doesn't support `scrollTo`\n root.scrollTop = height\n }\n })\n }\n\n _getNewObserver() {\n const options = {\n root: this._rootElement,\n threshold: this._config.threshold,\n rootMargin: this._config.rootMargin\n }\n\n return new IntersectionObserver(entries => this._observerCallback(entries), options)\n }\n\n // The logic of selection\n _observerCallback(entries) {\n const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`)\n const activate = entry => {\n this._previousScrollData.visibleEntryTop = entry.target.offsetTop\n this._process(targetElement(entry))\n }\n\n const parentScrollTop = (this._rootElement || document.documentElement).scrollTop\n const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop\n this._previousScrollData.parentScrollTop = parentScrollTop\n\n for (const entry of entries) {\n if (!entry.isIntersecting) {\n this._activeTarget = null\n this._clearActiveClass(targetElement(entry))\n\n continue\n }\n\n const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop\n // if we are scrolling down, pick the bigger offsetTop\n if (userScrollsDown && entryIsLowerThanPrevious) {\n activate(entry)\n // if parent isn't scrolled, let's keep the first visible item, breaking the iteration\n if (!parentScrollTop) {\n return\n }\n\n continue\n }\n\n // if we are scrolling up, pick the smallest offsetTop\n if (!userScrollsDown && !entryIsLowerThanPrevious) {\n activate(entry)\n }\n }\n }\n\n _initializeTargetsAndObservables() {\n this._targetLinks = new Map()\n this._observableSections = new Map()\n\n const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target)\n\n for (const anchor of targetLinks) {\n // ensure that the anchor has an id and is not disabled\n if (!anchor.hash || isDisabled(anchor)) {\n continue\n }\n\n const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element)\n\n // ensure that the observableSection exists & is visible\n if (isVisible(observableSection)) {\n this._targetLinks.set(decodeURI(anchor.hash), anchor)\n this._observableSections.set(anchor.hash, observableSection)\n }\n }\n }\n\n _process(target) {\n if (this._activeTarget === target) {\n return\n }\n\n this._clearActiveClass(this._config.target)\n this._activeTarget = target\n target.classList.add(CLASS_NAME_ACTIVE)\n this._activateParents(target)\n\n EventHandler.trigger(this._element, EVENT_ACTIVATE, { relatedTarget: target })\n }\n\n _activateParents(target) {\n // Activate dropdown parents\n if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, target.closest(SELECTOR_DROPDOWN))\n .classList.add(CLASS_NAME_ACTIVE)\n return\n }\n\n for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {\n // Set triggered links parents as active\n // With both
      and
    ')},createChildNavList:function(e){var t=this.createNavList();return e.append(t),t},generateNavEl:function(e,t){var n=a('
    ');n.attr("href","#"+e),n.text(t);var r=a("
  • ");return r.append(n),r},generateNavItem:function(e){var t=this.generateAnchor(e),n=a(e),r=n.data("toc-text")||n.text();return this.generateNavEl(t,r)},getTopLevel:function(e){for(var t=1;t<=6;t++){if(1 + + + + + + + + + + + + diff --git a/docs/deps/font-awesome-6.5.2/css/all.css b/docs/deps/font-awesome-6.5.2/css/all.css new file mode 100644 index 0000000..151dd57 --- /dev/null +++ b/docs/deps/font-awesome-6.5.2/css/all.css @@ -0,0 +1,8028 @@ +/*! + * Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +.fa { + font-family: var(--fa-style-family, "Font Awesome 6 Free"); + font-weight: var(--fa-style, 900); } + +.fa, +.fa-classic, +.fa-sharp, +.fas, +.fa-solid, +.far, +.fa-regular, +.fab, +.fa-brands { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: var(--fa-display, inline-block); + font-style: normal; + font-variant: normal; + line-height: 1; + text-rendering: auto; } + +.fas, +.fa-classic, +.fa-solid, +.far, +.fa-regular { + font-family: 'Font Awesome 6 Free'; } + +.fab, +.fa-brands { + font-family: 'Font Awesome 6 Brands'; } + +.fa-1x { + font-size: 1em; } + +.fa-2x { + font-size: 2em; } + +.fa-3x { + font-size: 3em; } + +.fa-4x { + font-size: 4em; } + +.fa-5x { + font-size: 5em; } + +.fa-6x { + font-size: 6em; } + +.fa-7x { + font-size: 7em; } + +.fa-8x { + font-size: 8em; } + +.fa-9x { + font-size: 9em; } + +.fa-10x { + font-size: 10em; } + +.fa-2xs { + font-size: 0.625em; + line-height: 0.1em; + vertical-align: 0.225em; } + +.fa-xs { + font-size: 0.75em; + line-height: 0.08333em; + vertical-align: 0.125em; } + +.fa-sm { + font-size: 0.875em; + line-height: 0.07143em; + vertical-align: 0.05357em; } + +.fa-lg { + font-size: 1.25em; + line-height: 0.05em; + vertical-align: -0.075em; } + +.fa-xl { + font-size: 1.5em; + line-height: 0.04167em; + vertical-align: -0.125em; } + +.fa-2xl { + font-size: 2em; + line-height: 0.03125em; + vertical-align: -0.1875em; } + +.fa-fw { + text-align: center; + width: 1.25em; } + +.fa-ul { + list-style-type: none; + margin-left: var(--fa-li-margin, 2.5em); + padding-left: 0; } + .fa-ul > li { + position: relative; } + +.fa-li { + left: calc(var(--fa-li-width, 2em) * -1); + position: absolute; + text-align: center; + width: var(--fa-li-width, 2em); + line-height: inherit; } + +.fa-border { + border-color: var(--fa-border-color, #eee); + border-radius: var(--fa-border-radius, 0.1em); + border-style: var(--fa-border-style, solid); + border-width: var(--fa-border-width, 0.08em); + padding: var(--fa-border-padding, 0.2em 0.25em 0.15em); } + +.fa-pull-left { + float: left; + margin-right: var(--fa-pull-margin, 0.3em); } + +.fa-pull-right { + float: right; + margin-left: var(--fa-pull-margin, 0.3em); } + +.fa-beat { + -webkit-animation-name: fa-beat; + animation-name: fa-beat; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out); + animation-timing-function: var(--fa-animation-timing, ease-in-out); } + +.fa-bounce { + -webkit-animation-name: fa-bounce; + animation-name: fa-bounce; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); } + +.fa-fade { + -webkit-animation-name: fa-fade; + animation-name: fa-fade; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); } + +.fa-beat-fade { + -webkit-animation-name: fa-beat-fade; + animation-name: fa-beat-fade; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); } + +.fa-flip { + -webkit-animation-name: fa-flip; + animation-name: fa-flip; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out); + animation-timing-function: var(--fa-animation-timing, ease-in-out); } + +.fa-shake { + -webkit-animation-name: fa-shake; + animation-name: fa-shake; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, linear); + animation-timing-function: var(--fa-animation-timing, linear); } + +.fa-spin { + -webkit-animation-name: fa-spin; + animation-name: fa-spin; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 2s); + animation-duration: var(--fa-animation-duration, 2s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, linear); + animation-timing-function: var(--fa-animation-timing, linear); } + +.fa-spin-reverse { + --fa-animation-direction: reverse; } + +.fa-pulse, +.fa-spin-pulse { + -webkit-animation-name: fa-spin; + animation-name: fa-spin; + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, steps(8)); + animation-timing-function: var(--fa-animation-timing, steps(8)); } + +@media (prefers-reduced-motion: reduce) { + .fa-beat, + .fa-bounce, + .fa-fade, + .fa-beat-fade, + .fa-flip, + .fa-pulse, + .fa-shake, + .fa-spin, + .fa-spin-pulse { + -webkit-animation-delay: -1ms; + animation-delay: -1ms; + -webkit-animation-duration: 1ms; + animation-duration: 1ms; + -webkit-animation-iteration-count: 1; + animation-iteration-count: 1; + -webkit-transition-delay: 0s; + transition-delay: 0s; + -webkit-transition-duration: 0s; + transition-duration: 0s; } } + +@-webkit-keyframes fa-beat { + 0%, 90% { + -webkit-transform: scale(1); + transform: scale(1); } + 45% { + -webkit-transform: scale(var(--fa-beat-scale, 1.25)); + transform: scale(var(--fa-beat-scale, 1.25)); } } + +@keyframes fa-beat { + 0%, 90% { + -webkit-transform: scale(1); + transform: scale(1); } + 45% { + -webkit-transform: scale(var(--fa-beat-scale, 1.25)); + transform: scale(var(--fa-beat-scale, 1.25)); } } + +@-webkit-keyframes fa-bounce { + 0% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); } + 10% { + -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); } + 30% { + -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); } + 50% { + -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); } + 57% { + -webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); + transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); } + 64% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); } + 100% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); } } + +@keyframes fa-bounce { + 0% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); } + 10% { + -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); } + 30% { + -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); } + 50% { + -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); } + 57% { + -webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); + transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); } + 64% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); } + 100% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); } } + +@-webkit-keyframes fa-fade { + 50% { + opacity: var(--fa-fade-opacity, 0.4); } } + +@keyframes fa-fade { + 50% { + opacity: var(--fa-fade-opacity, 0.4); } } + +@-webkit-keyframes fa-beat-fade { + 0%, 100% { + opacity: var(--fa-beat-fade-opacity, 0.4); + -webkit-transform: scale(1); + transform: scale(1); } + 50% { + opacity: 1; + -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125)); + transform: scale(var(--fa-beat-fade-scale, 1.125)); } } + +@keyframes fa-beat-fade { + 0%, 100% { + opacity: var(--fa-beat-fade-opacity, 0.4); + -webkit-transform: scale(1); + transform: scale(1); } + 50% { + opacity: 1; + -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125)); + transform: scale(var(--fa-beat-fade-scale, 1.125)); } } + +@-webkit-keyframes fa-flip { + 50% { + -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } } + +@keyframes fa-flip { + 50% { + -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } } + +@-webkit-keyframes fa-shake { + 0% { + -webkit-transform: rotate(-15deg); + transform: rotate(-15deg); } + 4% { + -webkit-transform: rotate(15deg); + transform: rotate(15deg); } + 8%, 24% { + -webkit-transform: rotate(-18deg); + transform: rotate(-18deg); } + 12%, 28% { + -webkit-transform: rotate(18deg); + transform: rotate(18deg); } + 16% { + -webkit-transform: rotate(-22deg); + transform: rotate(-22deg); } + 20% { + -webkit-transform: rotate(22deg); + transform: rotate(22deg); } + 32% { + -webkit-transform: rotate(-12deg); + transform: rotate(-12deg); } + 36% { + -webkit-transform: rotate(12deg); + transform: rotate(12deg); } + 40%, 100% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); } } + +@keyframes fa-shake { + 0% { + -webkit-transform: rotate(-15deg); + transform: rotate(-15deg); } + 4% { + -webkit-transform: rotate(15deg); + transform: rotate(15deg); } + 8%, 24% { + -webkit-transform: rotate(-18deg); + transform: rotate(-18deg); } + 12%, 28% { + -webkit-transform: rotate(18deg); + transform: rotate(18deg); } + 16% { + -webkit-transform: rotate(-22deg); + transform: rotate(-22deg); } + 20% { + -webkit-transform: rotate(22deg); + transform: rotate(22deg); } + 32% { + -webkit-transform: rotate(-12deg); + transform: rotate(-12deg); } + 36% { + -webkit-transform: rotate(12deg); + transform: rotate(12deg); } + 40%, 100% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); } } + +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); } } + +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); } } + +.fa-rotate-90 { + -webkit-transform: rotate(90deg); + transform: rotate(90deg); } + +.fa-rotate-180 { + -webkit-transform: rotate(180deg); + transform: rotate(180deg); } + +.fa-rotate-270 { + -webkit-transform: rotate(270deg); + transform: rotate(270deg); } + +.fa-flip-horizontal { + -webkit-transform: scale(-1, 1); + transform: scale(-1, 1); } + +.fa-flip-vertical { + -webkit-transform: scale(1, -1); + transform: scale(1, -1); } + +.fa-flip-both, +.fa-flip-horizontal.fa-flip-vertical { + -webkit-transform: scale(-1, -1); + transform: scale(-1, -1); } + +.fa-rotate-by { + -webkit-transform: rotate(var(--fa-rotate-angle, 0)); + transform: rotate(var(--fa-rotate-angle, 0)); } + +.fa-stack { + display: inline-block; + height: 2em; + line-height: 2em; + position: relative; + vertical-align: middle; + width: 2.5em; } + +.fa-stack-1x, +.fa-stack-2x { + left: 0; + position: absolute; + text-align: center; + width: 100%; + z-index: var(--fa-stack-z-index, auto); } + +.fa-stack-1x { + line-height: inherit; } + +.fa-stack-2x { + font-size: 2em; } + +.fa-inverse { + color: var(--fa-inverse, #fff); } + +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen +readers do not read off random characters that represent icons */ + +.fa-0::before { + content: "\30"; } + +.fa-1::before { + content: "\31"; } + +.fa-2::before { + content: "\32"; } + +.fa-3::before { + content: "\33"; } + +.fa-4::before { + content: "\34"; } + +.fa-5::before { + content: "\35"; } + +.fa-6::before { + content: "\36"; } + +.fa-7::before { + content: "\37"; } + +.fa-8::before { + content: "\38"; } + +.fa-9::before { + content: "\39"; } + +.fa-fill-drip::before { + content: "\f576"; } + +.fa-arrows-to-circle::before { + content: "\e4bd"; } + +.fa-circle-chevron-right::before { + content: "\f138"; } + +.fa-chevron-circle-right::before { + content: "\f138"; } + +.fa-at::before { + content: "\40"; } + +.fa-trash-can::before { + content: "\f2ed"; } + +.fa-trash-alt::before { + content: "\f2ed"; } + +.fa-text-height::before { + content: "\f034"; } + +.fa-user-xmark::before { + content: "\f235"; } + +.fa-user-times::before { + content: "\f235"; } + +.fa-stethoscope::before { + content: "\f0f1"; } + +.fa-message::before { + content: "\f27a"; } + +.fa-comment-alt::before { + content: "\f27a"; } + +.fa-info::before { + content: "\f129"; } + +.fa-down-left-and-up-right-to-center::before { + content: "\f422"; } + +.fa-compress-alt::before { + content: "\f422"; } + +.fa-explosion::before { + content: "\e4e9"; } + +.fa-file-lines::before { + content: "\f15c"; } + +.fa-file-alt::before { + content: "\f15c"; } + +.fa-file-text::before { + content: "\f15c"; } + +.fa-wave-square::before { + content: "\f83e"; } + +.fa-ring::before { + content: "\f70b"; } + +.fa-building-un::before { + content: "\e4d9"; } + +.fa-dice-three::before { + content: "\f527"; } + +.fa-calendar-days::before { + content: "\f073"; } + +.fa-calendar-alt::before { + content: "\f073"; } + +.fa-anchor-circle-check::before { + content: "\e4aa"; } + +.fa-building-circle-arrow-right::before { + content: "\e4d1"; } + +.fa-volleyball::before { + content: "\f45f"; } + +.fa-volleyball-ball::before { + content: "\f45f"; } + +.fa-arrows-up-to-line::before { + content: "\e4c2"; } + +.fa-sort-down::before { + content: "\f0dd"; } + +.fa-sort-desc::before { + content: "\f0dd"; } + +.fa-circle-minus::before { + content: "\f056"; } + +.fa-minus-circle::before { + content: "\f056"; } + +.fa-door-open::before { + content: "\f52b"; } + +.fa-right-from-bracket::before { + content: "\f2f5"; } + +.fa-sign-out-alt::before { + content: "\f2f5"; } + +.fa-atom::before { + content: "\f5d2"; } + +.fa-soap::before { + content: "\e06e"; } + +.fa-icons::before { + content: "\f86d"; } + +.fa-heart-music-camera-bolt::before { + content: "\f86d"; } + +.fa-microphone-lines-slash::before { + content: "\f539"; } + +.fa-microphone-alt-slash::before { + content: "\f539"; } + +.fa-bridge-circle-check::before { + content: "\e4c9"; } + +.fa-pump-medical::before { + content: "\e06a"; } + +.fa-fingerprint::before { + content: "\f577"; } + +.fa-hand-point-right::before { + content: "\f0a4"; } + +.fa-magnifying-glass-location::before { + content: "\f689"; } + +.fa-search-location::before { + content: "\f689"; } + +.fa-forward-step::before { + content: "\f051"; } + +.fa-step-forward::before { + content: "\f051"; } + +.fa-face-smile-beam::before { + content: "\f5b8"; } + +.fa-smile-beam::before { + content: "\f5b8"; } + +.fa-flag-checkered::before { + content: "\f11e"; } + +.fa-football::before { + content: "\f44e"; } + +.fa-football-ball::before { + content: "\f44e"; } + +.fa-school-circle-exclamation::before { + content: "\e56c"; } + +.fa-crop::before { + content: "\f125"; } + +.fa-angles-down::before { + content: "\f103"; } + +.fa-angle-double-down::before { + content: "\f103"; } + +.fa-users-rectangle::before { + content: "\e594"; } + +.fa-people-roof::before { + content: "\e537"; } + +.fa-people-line::before { + content: "\e534"; } + +.fa-beer-mug-empty::before { + content: "\f0fc"; } + +.fa-beer::before { + content: "\f0fc"; } + +.fa-diagram-predecessor::before { + content: "\e477"; } + +.fa-arrow-up-long::before { + content: "\f176"; } + +.fa-long-arrow-up::before { + content: "\f176"; } + +.fa-fire-flame-simple::before { + content: "\f46a"; } + +.fa-burn::before { + content: "\f46a"; } + +.fa-person::before { + content: "\f183"; } + +.fa-male::before { + content: "\f183"; } + +.fa-laptop::before { + content: "\f109"; } + +.fa-file-csv::before { + content: "\f6dd"; } + +.fa-menorah::before { + content: "\f676"; } + +.fa-truck-plane::before { + content: "\e58f"; } + +.fa-record-vinyl::before { + content: "\f8d9"; } + +.fa-face-grin-stars::before { + content: "\f587"; } + +.fa-grin-stars::before { + content: "\f587"; } + +.fa-bong::before { + content: "\f55c"; } + +.fa-spaghetti-monster-flying::before { + content: "\f67b"; } + +.fa-pastafarianism::before { + content: "\f67b"; } + +.fa-arrow-down-up-across-line::before { + content: "\e4af"; } + +.fa-spoon::before { + content: "\f2e5"; } + +.fa-utensil-spoon::before { + content: "\f2e5"; } + +.fa-jar-wheat::before { + content: "\e517"; } + +.fa-envelopes-bulk::before { + content: "\f674"; } + +.fa-mail-bulk::before { + content: "\f674"; } + +.fa-file-circle-exclamation::before { + content: "\e4eb"; } + +.fa-circle-h::before { + content: "\f47e"; } + +.fa-hospital-symbol::before { + content: "\f47e"; } + +.fa-pager::before { + content: "\f815"; } + +.fa-address-book::before { + content: "\f2b9"; } + +.fa-contact-book::before { + content: "\f2b9"; } + +.fa-strikethrough::before { + content: "\f0cc"; } + +.fa-k::before { + content: "\4b"; } + +.fa-landmark-flag::before { + content: "\e51c"; } + +.fa-pencil::before { + content: "\f303"; } + +.fa-pencil-alt::before { + content: "\f303"; } + +.fa-backward::before { + content: "\f04a"; } + +.fa-caret-right::before { + content: "\f0da"; } + +.fa-comments::before { + content: "\f086"; } + +.fa-paste::before { + content: "\f0ea"; } + +.fa-file-clipboard::before { + content: "\f0ea"; } + +.fa-code-pull-request::before { + content: "\e13c"; } + +.fa-clipboard-list::before { + content: "\f46d"; } + +.fa-truck-ramp-box::before { + content: "\f4de"; } + +.fa-truck-loading::before { + content: "\f4de"; } + +.fa-user-check::before { + content: "\f4fc"; } + +.fa-vial-virus::before { + content: "\e597"; } + +.fa-sheet-plastic::before { + content: "\e571"; } + +.fa-blog::before { + content: "\f781"; } + +.fa-user-ninja::before { + content: "\f504"; } + +.fa-person-arrow-up-from-line::before { + content: "\e539"; } + +.fa-scroll-torah::before { + content: "\f6a0"; } + +.fa-torah::before { + content: "\f6a0"; } + +.fa-broom-ball::before { + content: "\f458"; } + +.fa-quidditch::before { + content: "\f458"; } + +.fa-quidditch-broom-ball::before { + content: "\f458"; } + +.fa-toggle-off::before { + content: "\f204"; } + +.fa-box-archive::before { + content: "\f187"; } + +.fa-archive::before { + content: "\f187"; } + +.fa-person-drowning::before { + content: "\e545"; } + +.fa-arrow-down-9-1::before { + content: "\f886"; } + +.fa-sort-numeric-desc::before { + content: "\f886"; } + +.fa-sort-numeric-down-alt::before { + content: "\f886"; } + +.fa-face-grin-tongue-squint::before { + content: "\f58a"; } + +.fa-grin-tongue-squint::before { + content: "\f58a"; } + +.fa-spray-can::before { + content: "\f5bd"; } + +.fa-truck-monster::before { + content: "\f63b"; } + +.fa-w::before { + content: "\57"; } + +.fa-earth-africa::before { + content: "\f57c"; } + +.fa-globe-africa::before { + content: "\f57c"; } + +.fa-rainbow::before { + content: "\f75b"; } + +.fa-circle-notch::before { + content: "\f1ce"; } + +.fa-tablet-screen-button::before { + content: "\f3fa"; } + +.fa-tablet-alt::before { + content: "\f3fa"; } + +.fa-paw::before { + content: "\f1b0"; } + +.fa-cloud::before { + content: "\f0c2"; } + +.fa-trowel-bricks::before { + content: "\e58a"; } + +.fa-face-flushed::before { + content: "\f579"; } + +.fa-flushed::before { + content: "\f579"; } + +.fa-hospital-user::before { + content: "\f80d"; } + +.fa-tent-arrow-left-right::before { + content: "\e57f"; } + +.fa-gavel::before { + content: "\f0e3"; } + +.fa-legal::before { + content: "\f0e3"; } + +.fa-binoculars::before { + content: "\f1e5"; } + +.fa-microphone-slash::before { + content: "\f131"; } + +.fa-box-tissue::before { + content: "\e05b"; } + +.fa-motorcycle::before { + content: "\f21c"; } + +.fa-bell-concierge::before { + content: "\f562"; } + +.fa-concierge-bell::before { + content: "\f562"; } + +.fa-pen-ruler::before { + content: "\f5ae"; } + +.fa-pencil-ruler::before { + content: "\f5ae"; } + +.fa-people-arrows::before { + content: "\e068"; } + +.fa-people-arrows-left-right::before { + content: "\e068"; } + +.fa-mars-and-venus-burst::before { + content: "\e523"; } + +.fa-square-caret-right::before { + content: "\f152"; } + +.fa-caret-square-right::before { + content: "\f152"; } + +.fa-scissors::before { + content: "\f0c4"; } + +.fa-cut::before { + content: "\f0c4"; } + +.fa-sun-plant-wilt::before { + content: "\e57a"; } + +.fa-toilets-portable::before { + content: "\e584"; } + +.fa-hockey-puck::before { + content: "\f453"; } + +.fa-table::before { + content: "\f0ce"; } + +.fa-magnifying-glass-arrow-right::before { + content: "\e521"; } + +.fa-tachograph-digital::before { + content: "\f566"; } + +.fa-digital-tachograph::before { + content: "\f566"; } + +.fa-users-slash::before { + content: "\e073"; } + +.fa-clover::before { + content: "\e139"; } + +.fa-reply::before { + content: "\f3e5"; } + +.fa-mail-reply::before { + content: "\f3e5"; } + +.fa-star-and-crescent::before { + content: "\f699"; } + +.fa-house-fire::before { + content: "\e50c"; } + +.fa-square-minus::before { + content: "\f146"; } + +.fa-minus-square::before { + content: "\f146"; } + +.fa-helicopter::before { + content: "\f533"; } + +.fa-compass::before { + content: "\f14e"; } + +.fa-square-caret-down::before { + content: "\f150"; } + +.fa-caret-square-down::before { + content: "\f150"; } + +.fa-file-circle-question::before { + content: "\e4ef"; } + +.fa-laptop-code::before { + content: "\f5fc"; } + +.fa-swatchbook::before { + content: "\f5c3"; } + +.fa-prescription-bottle::before { + content: "\f485"; } + +.fa-bars::before { + content: "\f0c9"; } + +.fa-navicon::before { + content: "\f0c9"; } + +.fa-people-group::before { + content: "\e533"; } + +.fa-hourglass-end::before { + content: "\f253"; } + +.fa-hourglass-3::before { + content: "\f253"; } + +.fa-heart-crack::before { + content: "\f7a9"; } + +.fa-heart-broken::before { + content: "\f7a9"; } + +.fa-square-up-right::before { + content: "\f360"; } + +.fa-external-link-square-alt::before { + content: "\f360"; } + +.fa-face-kiss-beam::before { + content: "\f597"; } + +.fa-kiss-beam::before { + content: "\f597"; } + +.fa-film::before { + content: "\f008"; } + +.fa-ruler-horizontal::before { + content: "\f547"; } + +.fa-people-robbery::before { + content: "\e536"; } + +.fa-lightbulb::before { + content: "\f0eb"; } + +.fa-caret-left::before { + content: "\f0d9"; } + +.fa-circle-exclamation::before { + content: "\f06a"; } + +.fa-exclamation-circle::before { + content: "\f06a"; } + +.fa-school-circle-xmark::before { + content: "\e56d"; } + +.fa-arrow-right-from-bracket::before { + content: "\f08b"; } + +.fa-sign-out::before { + content: "\f08b"; } + +.fa-circle-chevron-down::before { + content: "\f13a"; } + +.fa-chevron-circle-down::before { + content: "\f13a"; } + +.fa-unlock-keyhole::before { + content: "\f13e"; } + +.fa-unlock-alt::before { + content: "\f13e"; } + +.fa-cloud-showers-heavy::before { + content: "\f740"; } + +.fa-headphones-simple::before { + content: "\f58f"; } + +.fa-headphones-alt::before { + content: "\f58f"; } + +.fa-sitemap::before { + content: "\f0e8"; } + +.fa-circle-dollar-to-slot::before { + content: "\f4b9"; } + +.fa-donate::before { + content: "\f4b9"; } + +.fa-memory::before { + content: "\f538"; } + +.fa-road-spikes::before { + content: "\e568"; } + +.fa-fire-burner::before { + content: "\e4f1"; } + +.fa-flag::before { + content: "\f024"; } + +.fa-hanukiah::before { + content: "\f6e6"; } + +.fa-feather::before { + content: "\f52d"; } + +.fa-volume-low::before { + content: "\f027"; } + +.fa-volume-down::before { + content: "\f027"; } + +.fa-comment-slash::before { + content: "\f4b3"; } + +.fa-cloud-sun-rain::before { + content: "\f743"; } + +.fa-compress::before { + content: "\f066"; } + +.fa-wheat-awn::before { + content: "\e2cd"; } + +.fa-wheat-alt::before { + content: "\e2cd"; } + +.fa-ankh::before { + content: "\f644"; } + +.fa-hands-holding-child::before { + content: "\e4fa"; } + +.fa-asterisk::before { + content: "\2a"; } + +.fa-square-check::before { + content: "\f14a"; } + +.fa-check-square::before { + content: "\f14a"; } + +.fa-peseta-sign::before { + content: "\e221"; } + +.fa-heading::before { + content: "\f1dc"; } + +.fa-header::before { + content: "\f1dc"; } + +.fa-ghost::before { + content: "\f6e2"; } + +.fa-list::before { + content: "\f03a"; } + +.fa-list-squares::before { + content: "\f03a"; } + +.fa-square-phone-flip::before { + content: "\f87b"; } + +.fa-phone-square-alt::before { + content: "\f87b"; } + +.fa-cart-plus::before { + content: "\f217"; } + +.fa-gamepad::before { + content: "\f11b"; } + +.fa-circle-dot::before { + content: "\f192"; } + +.fa-dot-circle::before { + content: "\f192"; } + +.fa-face-dizzy::before { + content: "\f567"; } + +.fa-dizzy::before { + content: "\f567"; } + +.fa-egg::before { + content: "\f7fb"; } + +.fa-house-medical-circle-xmark::before { + content: "\e513"; } + +.fa-campground::before { + content: "\f6bb"; } + +.fa-folder-plus::before { + content: "\f65e"; } + +.fa-futbol::before { + content: "\f1e3"; } + +.fa-futbol-ball::before { + content: "\f1e3"; } + +.fa-soccer-ball::before { + content: "\f1e3"; } + +.fa-paintbrush::before { + content: "\f1fc"; } + +.fa-paint-brush::before { + content: "\f1fc"; } + +.fa-lock::before { + content: "\f023"; } + +.fa-gas-pump::before { + content: "\f52f"; } + +.fa-hot-tub-person::before { + content: "\f593"; } + +.fa-hot-tub::before { + content: "\f593"; } + +.fa-map-location::before { + content: "\f59f"; } + +.fa-map-marked::before { + content: "\f59f"; } + +.fa-house-flood-water::before { + content: "\e50e"; } + +.fa-tree::before { + content: "\f1bb"; } + +.fa-bridge-lock::before { + content: "\e4cc"; } + +.fa-sack-dollar::before { + content: "\f81d"; } + +.fa-pen-to-square::before { + content: "\f044"; } + +.fa-edit::before { + content: "\f044"; } + +.fa-car-side::before { + content: "\f5e4"; } + +.fa-share-nodes::before { + content: "\f1e0"; } + +.fa-share-alt::before { + content: "\f1e0"; } + +.fa-heart-circle-minus::before { + content: "\e4ff"; } + +.fa-hourglass-half::before { + content: "\f252"; } + +.fa-hourglass-2::before { + content: "\f252"; } + +.fa-microscope::before { + content: "\f610"; } + +.fa-sink::before { + content: "\e06d"; } + +.fa-bag-shopping::before { + content: "\f290"; } + +.fa-shopping-bag::before { + content: "\f290"; } + +.fa-arrow-down-z-a::before { + content: "\f881"; } + +.fa-sort-alpha-desc::before { + content: "\f881"; } + +.fa-sort-alpha-down-alt::before { + content: "\f881"; } + +.fa-mitten::before { + content: "\f7b5"; } + +.fa-person-rays::before { + content: "\e54d"; } + +.fa-users::before { + content: "\f0c0"; } + +.fa-eye-slash::before { + content: "\f070"; } + +.fa-flask-vial::before { + content: "\e4f3"; } + +.fa-hand::before { + content: "\f256"; } + +.fa-hand-paper::before { + content: "\f256"; } + +.fa-om::before { + content: "\f679"; } + +.fa-worm::before { + content: "\e599"; } + +.fa-house-circle-xmark::before { + content: "\e50b"; } + +.fa-plug::before { + content: "\f1e6"; } + +.fa-chevron-up::before { + content: "\f077"; } + +.fa-hand-spock::before { + content: "\f259"; } + +.fa-stopwatch::before { + content: "\f2f2"; } + +.fa-face-kiss::before { + content: "\f596"; } + +.fa-kiss::before { + content: "\f596"; } + +.fa-bridge-circle-xmark::before { + content: "\e4cb"; } + +.fa-face-grin-tongue::before { + content: "\f589"; } + +.fa-grin-tongue::before { + content: "\f589"; } + +.fa-chess-bishop::before { + content: "\f43a"; } + +.fa-face-grin-wink::before { + content: "\f58c"; } + +.fa-grin-wink::before { + content: "\f58c"; } + +.fa-ear-deaf::before { + content: "\f2a4"; } + +.fa-deaf::before { + content: "\f2a4"; } + +.fa-deafness::before { + content: "\f2a4"; } + +.fa-hard-of-hearing::before { + content: "\f2a4"; } + +.fa-road-circle-check::before { + content: "\e564"; } + +.fa-dice-five::before { + content: "\f523"; } + +.fa-square-rss::before { + content: "\f143"; } + +.fa-rss-square::before { + content: "\f143"; } + +.fa-land-mine-on::before { + content: "\e51b"; } + +.fa-i-cursor::before { + content: "\f246"; } + +.fa-stamp::before { + content: "\f5bf"; } + +.fa-stairs::before { + content: "\e289"; } + +.fa-i::before { + content: "\49"; } + +.fa-hryvnia-sign::before { + content: "\f6f2"; } + +.fa-hryvnia::before { + content: "\f6f2"; } + +.fa-pills::before { + content: "\f484"; } + +.fa-face-grin-wide::before { + content: "\f581"; } + +.fa-grin-alt::before { + content: "\f581"; } + +.fa-tooth::before { + content: "\f5c9"; } + +.fa-v::before { + content: "\56"; } + +.fa-bangladeshi-taka-sign::before { + content: "\e2e6"; } + +.fa-bicycle::before { + content: "\f206"; } + +.fa-staff-snake::before { + content: "\e579"; } + +.fa-rod-asclepius::before { + content: "\e579"; } + +.fa-rod-snake::before { + content: "\e579"; } + +.fa-staff-aesculapius::before { + content: "\e579"; } + +.fa-head-side-cough-slash::before { + content: "\e062"; } + +.fa-truck-medical::before { + content: "\f0f9"; } + +.fa-ambulance::before { + content: "\f0f9"; } + +.fa-wheat-awn-circle-exclamation::before { + content: "\e598"; } + +.fa-snowman::before { + content: "\f7d0"; } + +.fa-mortar-pestle::before { + content: "\f5a7"; } + +.fa-road-barrier::before { + content: "\e562"; } + +.fa-school::before { + content: "\f549"; } + +.fa-igloo::before { + content: "\f7ae"; } + +.fa-joint::before { + content: "\f595"; } + +.fa-angle-right::before { + content: "\f105"; } + +.fa-horse::before { + content: "\f6f0"; } + +.fa-q::before { + content: "\51"; } + +.fa-g::before { + content: "\47"; } + +.fa-notes-medical::before { + content: "\f481"; } + +.fa-temperature-half::before { + content: "\f2c9"; } + +.fa-temperature-2::before { + content: "\f2c9"; } + +.fa-thermometer-2::before { + content: "\f2c9"; } + +.fa-thermometer-half::before { + content: "\f2c9"; } + +.fa-dong-sign::before { + content: "\e169"; } + +.fa-capsules::before { + content: "\f46b"; } + +.fa-poo-storm::before { + content: "\f75a"; } + +.fa-poo-bolt::before { + content: "\f75a"; } + +.fa-face-frown-open::before { + content: "\f57a"; } + +.fa-frown-open::before { + content: "\f57a"; } + +.fa-hand-point-up::before { + content: "\f0a6"; } + +.fa-money-bill::before { + content: "\f0d6"; } + +.fa-bookmark::before { + content: "\f02e"; } + +.fa-align-justify::before { + content: "\f039"; } + +.fa-umbrella-beach::before { + content: "\f5ca"; } + +.fa-helmet-un::before { + content: "\e503"; } + +.fa-bullseye::before { + content: "\f140"; } + +.fa-bacon::before { + content: "\f7e5"; } + +.fa-hand-point-down::before { + content: "\f0a7"; } + +.fa-arrow-up-from-bracket::before { + content: "\e09a"; } + +.fa-folder::before { + content: "\f07b"; } + +.fa-folder-blank::before { + content: "\f07b"; } + +.fa-file-waveform::before { + content: "\f478"; } + +.fa-file-medical-alt::before { + content: "\f478"; } + +.fa-radiation::before { + content: "\f7b9"; } + +.fa-chart-simple::before { + content: "\e473"; } + +.fa-mars-stroke::before { + content: "\f229"; } + +.fa-vial::before { + content: "\f492"; } + +.fa-gauge::before { + content: "\f624"; } + +.fa-dashboard::before { + content: "\f624"; } + +.fa-gauge-med::before { + content: "\f624"; } + +.fa-tachometer-alt-average::before { + content: "\f624"; } + +.fa-wand-magic-sparkles::before { + content: "\e2ca"; } + +.fa-magic-wand-sparkles::before { + content: "\e2ca"; } + +.fa-e::before { + content: "\45"; } + +.fa-pen-clip::before { + content: "\f305"; } + +.fa-pen-alt::before { + content: "\f305"; } + +.fa-bridge-circle-exclamation::before { + content: "\e4ca"; } + +.fa-user::before { + content: "\f007"; } + +.fa-school-circle-check::before { + content: "\e56b"; } + +.fa-dumpster::before { + content: "\f793"; } + +.fa-van-shuttle::before { + content: "\f5b6"; } + +.fa-shuttle-van::before { + content: "\f5b6"; } + +.fa-building-user::before { + content: "\e4da"; } + +.fa-square-caret-left::before { + content: "\f191"; } + +.fa-caret-square-left::before { + content: "\f191"; } + +.fa-highlighter::before { + content: "\f591"; } + +.fa-key::before { + content: "\f084"; } + +.fa-bullhorn::before { + content: "\f0a1"; } + +.fa-globe::before { + content: "\f0ac"; } + +.fa-synagogue::before { + content: "\f69b"; } + +.fa-person-half-dress::before { + content: "\e548"; } + +.fa-road-bridge::before { + content: "\e563"; } + +.fa-location-arrow::before { + content: "\f124"; } + +.fa-c::before { + content: "\43"; } + +.fa-tablet-button::before { + content: "\f10a"; } + +.fa-building-lock::before { + content: "\e4d6"; } + +.fa-pizza-slice::before { + content: "\f818"; } + +.fa-money-bill-wave::before { + content: "\f53a"; } + +.fa-chart-area::before { + content: "\f1fe"; } + +.fa-area-chart::before { + content: "\f1fe"; } + +.fa-house-flag::before { + content: "\e50d"; } + +.fa-person-circle-minus::before { + content: "\e540"; } + +.fa-ban::before { + content: "\f05e"; } + +.fa-cancel::before { + content: "\f05e"; } + +.fa-camera-rotate::before { + content: "\e0d8"; } + +.fa-spray-can-sparkles::before { + content: "\f5d0"; } + +.fa-air-freshener::before { + content: "\f5d0"; } + +.fa-star::before { + content: "\f005"; } + +.fa-repeat::before { + content: "\f363"; } + +.fa-cross::before { + content: "\f654"; } + +.fa-box::before { + content: "\f466"; } + +.fa-venus-mars::before { + content: "\f228"; } + +.fa-arrow-pointer::before { + content: "\f245"; } + +.fa-mouse-pointer::before { + content: "\f245"; } + +.fa-maximize::before { + content: "\f31e"; } + +.fa-expand-arrows-alt::before { + content: "\f31e"; } + +.fa-charging-station::before { + content: "\f5e7"; } + +.fa-shapes::before { + content: "\f61f"; } + +.fa-triangle-circle-square::before { + content: "\f61f"; } + +.fa-shuffle::before { + content: "\f074"; } + +.fa-random::before { + content: "\f074"; } + +.fa-person-running::before { + content: "\f70c"; } + +.fa-running::before { + content: "\f70c"; } + +.fa-mobile-retro::before { + content: "\e527"; } + +.fa-grip-lines-vertical::before { + content: "\f7a5"; } + +.fa-spider::before { + content: "\f717"; } + +.fa-hands-bound::before { + content: "\e4f9"; } + +.fa-file-invoice-dollar::before { + content: "\f571"; } + +.fa-plane-circle-exclamation::before { + content: "\e556"; } + +.fa-x-ray::before { + content: "\f497"; } + +.fa-spell-check::before { + content: "\f891"; } + +.fa-slash::before { + content: "\f715"; } + +.fa-computer-mouse::before { + content: "\f8cc"; } + +.fa-mouse::before { + content: "\f8cc"; } + +.fa-arrow-right-to-bracket::before { + content: "\f090"; } + +.fa-sign-in::before { + content: "\f090"; } + +.fa-shop-slash::before { + content: "\e070"; } + +.fa-store-alt-slash::before { + content: "\e070"; } + +.fa-server::before { + content: "\f233"; } + +.fa-virus-covid-slash::before { + content: "\e4a9"; } + +.fa-shop-lock::before { + content: "\e4a5"; } + +.fa-hourglass-start::before { + content: "\f251"; } + +.fa-hourglass-1::before { + content: "\f251"; } + +.fa-blender-phone::before { + content: "\f6b6"; } + +.fa-building-wheat::before { + content: "\e4db"; } + +.fa-person-breastfeeding::before { + content: "\e53a"; } + +.fa-right-to-bracket::before { + content: "\f2f6"; } + +.fa-sign-in-alt::before { + content: "\f2f6"; } + +.fa-venus::before { + content: "\f221"; } + +.fa-passport::before { + content: "\f5ab"; } + +.fa-heart-pulse::before { + content: "\f21e"; } + +.fa-heartbeat::before { + content: "\f21e"; } + +.fa-people-carry-box::before { + content: "\f4ce"; } + +.fa-people-carry::before { + content: "\f4ce"; } + +.fa-temperature-high::before { + content: "\f769"; } + +.fa-microchip::before { + content: "\f2db"; } + +.fa-crown::before { + content: "\f521"; } + +.fa-weight-hanging::before { + content: "\f5cd"; } + +.fa-xmarks-lines::before { + content: "\e59a"; } + +.fa-file-prescription::before { + content: "\f572"; } + +.fa-weight-scale::before { + content: "\f496"; } + +.fa-weight::before { + content: "\f496"; } + +.fa-user-group::before { + content: "\f500"; } + +.fa-user-friends::before { + content: "\f500"; } + +.fa-arrow-up-a-z::before { + content: "\f15e"; } + +.fa-sort-alpha-up::before { + content: "\f15e"; } + +.fa-chess-knight::before { + content: "\f441"; } + +.fa-face-laugh-squint::before { + content: "\f59b"; } + +.fa-laugh-squint::before { + content: "\f59b"; } + +.fa-wheelchair::before { + content: "\f193"; } + +.fa-circle-arrow-up::before { + content: "\f0aa"; } + +.fa-arrow-circle-up::before { + content: "\f0aa"; } + +.fa-toggle-on::before { + content: "\f205"; } + +.fa-person-walking::before { + content: "\f554"; } + +.fa-walking::before { + content: "\f554"; } + +.fa-l::before { + content: "\4c"; } + +.fa-fire::before { + content: "\f06d"; } + +.fa-bed-pulse::before { + content: "\f487"; } + +.fa-procedures::before { + content: "\f487"; } + +.fa-shuttle-space::before { + content: "\f197"; } + +.fa-space-shuttle::before { + content: "\f197"; } + +.fa-face-laugh::before { + content: "\f599"; } + +.fa-laugh::before { + content: "\f599"; } + +.fa-folder-open::before { + content: "\f07c"; } + +.fa-heart-circle-plus::before { + content: "\e500"; } + +.fa-code-fork::before { + content: "\e13b"; } + +.fa-city::before { + content: "\f64f"; } + +.fa-microphone-lines::before { + content: "\f3c9"; } + +.fa-microphone-alt::before { + content: "\f3c9"; } + +.fa-pepper-hot::before { + content: "\f816"; } + +.fa-unlock::before { + content: "\f09c"; } + +.fa-colon-sign::before { + content: "\e140"; } + +.fa-headset::before { + content: "\f590"; } + +.fa-store-slash::before { + content: "\e071"; } + +.fa-road-circle-xmark::before { + content: "\e566"; } + +.fa-user-minus::before { + content: "\f503"; } + +.fa-mars-stroke-up::before { + content: "\f22a"; } + +.fa-mars-stroke-v::before { + content: "\f22a"; } + +.fa-champagne-glasses::before { + content: "\f79f"; } + +.fa-glass-cheers::before { + content: "\f79f"; } + +.fa-clipboard::before { + content: "\f328"; } + +.fa-house-circle-exclamation::before { + content: "\e50a"; } + +.fa-file-arrow-up::before { + content: "\f574"; } + +.fa-file-upload::before { + content: "\f574"; } + +.fa-wifi::before { + content: "\f1eb"; } + +.fa-wifi-3::before { + content: "\f1eb"; } + +.fa-wifi-strong::before { + content: "\f1eb"; } + +.fa-bath::before { + content: "\f2cd"; } + +.fa-bathtub::before { + content: "\f2cd"; } + +.fa-underline::before { + content: "\f0cd"; } + +.fa-user-pen::before { + content: "\f4ff"; } + +.fa-user-edit::before { + content: "\f4ff"; } + +.fa-signature::before { + content: "\f5b7"; } + +.fa-stroopwafel::before { + content: "\f551"; } + +.fa-bold::before { + content: "\f032"; } + +.fa-anchor-lock::before { + content: "\e4ad"; } + +.fa-building-ngo::before { + content: "\e4d7"; } + +.fa-manat-sign::before { + content: "\e1d5"; } + +.fa-not-equal::before { + content: "\f53e"; } + +.fa-border-top-left::before { + content: "\f853"; } + +.fa-border-style::before { + content: "\f853"; } + +.fa-map-location-dot::before { + content: "\f5a0"; } + +.fa-map-marked-alt::before { + content: "\f5a0"; } + +.fa-jedi::before { + content: "\f669"; } + +.fa-square-poll-vertical::before { + content: "\f681"; } + +.fa-poll::before { + content: "\f681"; } + +.fa-mug-hot::before { + content: "\f7b6"; } + +.fa-car-battery::before { + content: "\f5df"; } + +.fa-battery-car::before { + content: "\f5df"; } + +.fa-gift::before { + content: "\f06b"; } + +.fa-dice-two::before { + content: "\f528"; } + +.fa-chess-queen::before { + content: "\f445"; } + +.fa-glasses::before { + content: "\f530"; } + +.fa-chess-board::before { + content: "\f43c"; } + +.fa-building-circle-check::before { + content: "\e4d2"; } + +.fa-person-chalkboard::before { + content: "\e53d"; } + +.fa-mars-stroke-right::before { + content: "\f22b"; } + +.fa-mars-stroke-h::before { + content: "\f22b"; } + +.fa-hand-back-fist::before { + content: "\f255"; } + +.fa-hand-rock::before { + content: "\f255"; } + +.fa-square-caret-up::before { + content: "\f151"; } + +.fa-caret-square-up::before { + content: "\f151"; } + +.fa-cloud-showers-water::before { + content: "\e4e4"; } + +.fa-chart-bar::before { + content: "\f080"; } + +.fa-bar-chart::before { + content: "\f080"; } + +.fa-hands-bubbles::before { + content: "\e05e"; } + +.fa-hands-wash::before { + content: "\e05e"; } + +.fa-less-than-equal::before { + content: "\f537"; } + +.fa-train::before { + content: "\f238"; } + +.fa-eye-low-vision::before { + content: "\f2a8"; } + +.fa-low-vision::before { + content: "\f2a8"; } + +.fa-crow::before { + content: "\f520"; } + +.fa-sailboat::before { + content: "\e445"; } + +.fa-window-restore::before { + content: "\f2d2"; } + +.fa-square-plus::before { + content: "\f0fe"; } + +.fa-plus-square::before { + content: "\f0fe"; } + +.fa-torii-gate::before { + content: "\f6a1"; } + +.fa-frog::before { + content: "\f52e"; } + +.fa-bucket::before { + content: "\e4cf"; } + +.fa-image::before { + content: "\f03e"; } + +.fa-microphone::before { + content: "\f130"; } + +.fa-cow::before { + content: "\f6c8"; } + +.fa-caret-up::before { + content: "\f0d8"; } + +.fa-screwdriver::before { + content: "\f54a"; } + +.fa-folder-closed::before { + content: "\e185"; } + +.fa-house-tsunami::before { + content: "\e515"; } + +.fa-square-nfi::before { + content: "\e576"; } + +.fa-arrow-up-from-ground-water::before { + content: "\e4b5"; } + +.fa-martini-glass::before { + content: "\f57b"; } + +.fa-glass-martini-alt::before { + content: "\f57b"; } + +.fa-rotate-left::before { + content: "\f2ea"; } + +.fa-rotate-back::before { + content: "\f2ea"; } + +.fa-rotate-backward::before { + content: "\f2ea"; } + +.fa-undo-alt::before { + content: "\f2ea"; } + +.fa-table-columns::before { + content: "\f0db"; } + +.fa-columns::before { + content: "\f0db"; } + +.fa-lemon::before { + content: "\f094"; } + +.fa-head-side-mask::before { + content: "\e063"; } + +.fa-handshake::before { + content: "\f2b5"; } + +.fa-gem::before { + content: "\f3a5"; } + +.fa-dolly::before { + content: "\f472"; } + +.fa-dolly-box::before { + content: "\f472"; } + +.fa-smoking::before { + content: "\f48d"; } + +.fa-minimize::before { + content: "\f78c"; } + +.fa-compress-arrows-alt::before { + content: "\f78c"; } + +.fa-monument::before { + content: "\f5a6"; } + +.fa-snowplow::before { + content: "\f7d2"; } + +.fa-angles-right::before { + content: "\f101"; } + +.fa-angle-double-right::before { + content: "\f101"; } + +.fa-cannabis::before { + content: "\f55f"; } + +.fa-circle-play::before { + content: "\f144"; } + +.fa-play-circle::before { + content: "\f144"; } + +.fa-tablets::before { + content: "\f490"; } + +.fa-ethernet::before { + content: "\f796"; } + +.fa-euro-sign::before { + content: "\f153"; } + +.fa-eur::before { + content: "\f153"; } + +.fa-euro::before { + content: "\f153"; } + +.fa-chair::before { + content: "\f6c0"; } + +.fa-circle-check::before { + content: "\f058"; } + +.fa-check-circle::before { + content: "\f058"; } + +.fa-circle-stop::before { + content: "\f28d"; } + +.fa-stop-circle::before { + content: "\f28d"; } + +.fa-compass-drafting::before { + content: "\f568"; } + +.fa-drafting-compass::before { + content: "\f568"; } + +.fa-plate-wheat::before { + content: "\e55a"; } + +.fa-icicles::before { + content: "\f7ad"; } + +.fa-person-shelter::before { + content: "\e54f"; } + +.fa-neuter::before { + content: "\f22c"; } + +.fa-id-badge::before { + content: "\f2c1"; } + +.fa-marker::before { + content: "\f5a1"; } + +.fa-face-laugh-beam::before { + content: "\f59a"; } + +.fa-laugh-beam::before { + content: "\f59a"; } + +.fa-helicopter-symbol::before { + content: "\e502"; } + +.fa-universal-access::before { + content: "\f29a"; } + +.fa-circle-chevron-up::before { + content: "\f139"; } + +.fa-chevron-circle-up::before { + content: "\f139"; } + +.fa-lari-sign::before { + content: "\e1c8"; } + +.fa-volcano::before { + content: "\f770"; } + +.fa-person-walking-dashed-line-arrow-right::before { + content: "\e553"; } + +.fa-sterling-sign::before { + content: "\f154"; } + +.fa-gbp::before { + content: "\f154"; } + +.fa-pound-sign::before { + content: "\f154"; } + +.fa-viruses::before { + content: "\e076"; } + +.fa-square-person-confined::before { + content: "\e577"; } + +.fa-user-tie::before { + content: "\f508"; } + +.fa-arrow-down-long::before { + content: "\f175"; } + +.fa-long-arrow-down::before { + content: "\f175"; } + +.fa-tent-arrow-down-to-line::before { + content: "\e57e"; } + +.fa-certificate::before { + content: "\f0a3"; } + +.fa-reply-all::before { + content: "\f122"; } + +.fa-mail-reply-all::before { + content: "\f122"; } + +.fa-suitcase::before { + content: "\f0f2"; } + +.fa-person-skating::before { + content: "\f7c5"; } + +.fa-skating::before { + content: "\f7c5"; } + +.fa-filter-circle-dollar::before { + content: "\f662"; } + +.fa-funnel-dollar::before { + content: "\f662"; } + +.fa-camera-retro::before { + content: "\f083"; } + +.fa-circle-arrow-down::before { + content: "\f0ab"; } + +.fa-arrow-circle-down::before { + content: "\f0ab"; } + +.fa-file-import::before { + content: "\f56f"; } + +.fa-arrow-right-to-file::before { + content: "\f56f"; } + +.fa-square-arrow-up-right::before { + content: "\f14c"; } + +.fa-external-link-square::before { + content: "\f14c"; } + +.fa-box-open::before { + content: "\f49e"; } + +.fa-scroll::before { + content: "\f70e"; } + +.fa-spa::before { + content: "\f5bb"; } + +.fa-location-pin-lock::before { + content: "\e51f"; } + +.fa-pause::before { + content: "\f04c"; } + +.fa-hill-avalanche::before { + content: "\e507"; } + +.fa-temperature-empty::before { + content: "\f2cb"; } + +.fa-temperature-0::before { + content: "\f2cb"; } + +.fa-thermometer-0::before { + content: "\f2cb"; } + +.fa-thermometer-empty::before { + content: "\f2cb"; } + +.fa-bomb::before { + content: "\f1e2"; } + +.fa-registered::before { + content: "\f25d"; } + +.fa-address-card::before { + content: "\f2bb"; } + +.fa-contact-card::before { + content: "\f2bb"; } + +.fa-vcard::before { + content: "\f2bb"; } + +.fa-scale-unbalanced-flip::before { + content: "\f516"; } + +.fa-balance-scale-right::before { + content: "\f516"; } + +.fa-subscript::before { + content: "\f12c"; } + +.fa-diamond-turn-right::before { + content: "\f5eb"; } + +.fa-directions::before { + content: "\f5eb"; } + +.fa-burst::before { + content: "\e4dc"; } + +.fa-house-laptop::before { + content: "\e066"; } + +.fa-laptop-house::before { + content: "\e066"; } + +.fa-face-tired::before { + content: "\f5c8"; } + +.fa-tired::before { + content: "\f5c8"; } + +.fa-money-bills::before { + content: "\e1f3"; } + +.fa-smog::before { + content: "\f75f"; } + +.fa-crutch::before { + content: "\f7f7"; } + +.fa-cloud-arrow-up::before { + content: "\f0ee"; } + +.fa-cloud-upload::before { + content: "\f0ee"; } + +.fa-cloud-upload-alt::before { + content: "\f0ee"; } + +.fa-palette::before { + content: "\f53f"; } + +.fa-arrows-turn-right::before { + content: "\e4c0"; } + +.fa-vest::before { + content: "\e085"; } + +.fa-ferry::before { + content: "\e4ea"; } + +.fa-arrows-down-to-people::before { + content: "\e4b9"; } + +.fa-seedling::before { + content: "\f4d8"; } + +.fa-sprout::before { + content: "\f4d8"; } + +.fa-left-right::before { + content: "\f337"; } + +.fa-arrows-alt-h::before { + content: "\f337"; } + +.fa-boxes-packing::before { + content: "\e4c7"; } + +.fa-circle-arrow-left::before { + content: "\f0a8"; } + +.fa-arrow-circle-left::before { + content: "\f0a8"; } + +.fa-group-arrows-rotate::before { + content: "\e4f6"; } + +.fa-bowl-food::before { + content: "\e4c6"; } + +.fa-candy-cane::before { + content: "\f786"; } + +.fa-arrow-down-wide-short::before { + content: "\f160"; } + +.fa-sort-amount-asc::before { + content: "\f160"; } + +.fa-sort-amount-down::before { + content: "\f160"; } + +.fa-cloud-bolt::before { + content: "\f76c"; } + +.fa-thunderstorm::before { + content: "\f76c"; } + +.fa-text-slash::before { + content: "\f87d"; } + +.fa-remove-format::before { + content: "\f87d"; } + +.fa-face-smile-wink::before { + content: "\f4da"; } + +.fa-smile-wink::before { + content: "\f4da"; } + +.fa-file-word::before { + content: "\f1c2"; } + +.fa-file-powerpoint::before { + content: "\f1c4"; } + +.fa-arrows-left-right::before { + content: "\f07e"; } + +.fa-arrows-h::before { + content: "\f07e"; } + +.fa-house-lock::before { + content: "\e510"; } + +.fa-cloud-arrow-down::before { + content: "\f0ed"; } + +.fa-cloud-download::before { + content: "\f0ed"; } + +.fa-cloud-download-alt::before { + content: "\f0ed"; } + +.fa-children::before { + content: "\e4e1"; } + +.fa-chalkboard::before { + content: "\f51b"; } + +.fa-blackboard::before { + content: "\f51b"; } + +.fa-user-large-slash::before { + content: "\f4fa"; } + +.fa-user-alt-slash::before { + content: "\f4fa"; } + +.fa-envelope-open::before { + content: "\f2b6"; } + +.fa-handshake-simple-slash::before { + content: "\e05f"; } + +.fa-handshake-alt-slash::before { + content: "\e05f"; } + +.fa-mattress-pillow::before { + content: "\e525"; } + +.fa-guarani-sign::before { + content: "\e19a"; } + +.fa-arrows-rotate::before { + content: "\f021"; } + +.fa-refresh::before { + content: "\f021"; } + +.fa-sync::before { + content: "\f021"; } + +.fa-fire-extinguisher::before { + content: "\f134"; } + +.fa-cruzeiro-sign::before { + content: "\e152"; } + +.fa-greater-than-equal::before { + content: "\f532"; } + +.fa-shield-halved::before { + content: "\f3ed"; } + +.fa-shield-alt::before { + content: "\f3ed"; } + +.fa-book-atlas::before { + content: "\f558"; } + +.fa-atlas::before { + content: "\f558"; } + +.fa-virus::before { + content: "\e074"; } + +.fa-envelope-circle-check::before { + content: "\e4e8"; } + +.fa-layer-group::before { + content: "\f5fd"; } + +.fa-arrows-to-dot::before { + content: "\e4be"; } + +.fa-archway::before { + content: "\f557"; } + +.fa-heart-circle-check::before { + content: "\e4fd"; } + +.fa-house-chimney-crack::before { + content: "\f6f1"; } + +.fa-house-damage::before { + content: "\f6f1"; } + +.fa-file-zipper::before { + content: "\f1c6"; } + +.fa-file-archive::before { + content: "\f1c6"; } + +.fa-square::before { + content: "\f0c8"; } + +.fa-martini-glass-empty::before { + content: "\f000"; } + +.fa-glass-martini::before { + content: "\f000"; } + +.fa-couch::before { + content: "\f4b8"; } + +.fa-cedi-sign::before { + content: "\e0df"; } + +.fa-italic::before { + content: "\f033"; } + +.fa-table-cells-column-lock::before { + content: "\e678"; } + +.fa-church::before { + content: "\f51d"; } + +.fa-comments-dollar::before { + content: "\f653"; } + +.fa-democrat::before { + content: "\f747"; } + +.fa-z::before { + content: "\5a"; } + +.fa-person-skiing::before { + content: "\f7c9"; } + +.fa-skiing::before { + content: "\f7c9"; } + +.fa-road-lock::before { + content: "\e567"; } + +.fa-a::before { + content: "\41"; } + +.fa-temperature-arrow-down::before { + content: "\e03f"; } + +.fa-temperature-down::before { + content: "\e03f"; } + +.fa-feather-pointed::before { + content: "\f56b"; } + +.fa-feather-alt::before { + content: "\f56b"; } + +.fa-p::before { + content: "\50"; } + +.fa-snowflake::before { + content: "\f2dc"; } + +.fa-newspaper::before { + content: "\f1ea"; } + +.fa-rectangle-ad::before { + content: "\f641"; } + +.fa-ad::before { + content: "\f641"; } + +.fa-circle-arrow-right::before { + content: "\f0a9"; } + +.fa-arrow-circle-right::before { + content: "\f0a9"; } + +.fa-filter-circle-xmark::before { + content: "\e17b"; } + +.fa-locust::before { + content: "\e520"; } + +.fa-sort::before { + content: "\f0dc"; } + +.fa-unsorted::before { + content: "\f0dc"; } + +.fa-list-ol::before { + content: "\f0cb"; } + +.fa-list-1-2::before { + content: "\f0cb"; } + +.fa-list-numeric::before { + content: "\f0cb"; } + +.fa-person-dress-burst::before { + content: "\e544"; } + +.fa-money-check-dollar::before { + content: "\f53d"; } + +.fa-money-check-alt::before { + content: "\f53d"; } + +.fa-vector-square::before { + content: "\f5cb"; } + +.fa-bread-slice::before { + content: "\f7ec"; } + +.fa-language::before { + content: "\f1ab"; } + +.fa-face-kiss-wink-heart::before { + content: "\f598"; } + +.fa-kiss-wink-heart::before { + content: "\f598"; } + +.fa-filter::before { + content: "\f0b0"; } + +.fa-question::before { + content: "\3f"; } + +.fa-file-signature::before { + content: "\f573"; } + +.fa-up-down-left-right::before { + content: "\f0b2"; } + +.fa-arrows-alt::before { + content: "\f0b2"; } + +.fa-house-chimney-user::before { + content: "\e065"; } + +.fa-hand-holding-heart::before { + content: "\f4be"; } + +.fa-puzzle-piece::before { + content: "\f12e"; } + +.fa-money-check::before { + content: "\f53c"; } + +.fa-star-half-stroke::before { + content: "\f5c0"; } + +.fa-star-half-alt::before { + content: "\f5c0"; } + +.fa-code::before { + content: "\f121"; } + +.fa-whiskey-glass::before { + content: "\f7a0"; } + +.fa-glass-whiskey::before { + content: "\f7a0"; } + +.fa-building-circle-exclamation::before { + content: "\e4d3"; } + +.fa-magnifying-glass-chart::before { + content: "\e522"; } + +.fa-arrow-up-right-from-square::before { + content: "\f08e"; } + +.fa-external-link::before { + content: "\f08e"; } + +.fa-cubes-stacked::before { + content: "\e4e6"; } + +.fa-won-sign::before { + content: "\f159"; } + +.fa-krw::before { + content: "\f159"; } + +.fa-won::before { + content: "\f159"; } + +.fa-virus-covid::before { + content: "\e4a8"; } + +.fa-austral-sign::before { + content: "\e0a9"; } + +.fa-f::before { + content: "\46"; } + +.fa-leaf::before { + content: "\f06c"; } + +.fa-road::before { + content: "\f018"; } + +.fa-taxi::before { + content: "\f1ba"; } + +.fa-cab::before { + content: "\f1ba"; } + +.fa-person-circle-plus::before { + content: "\e541"; } + +.fa-chart-pie::before { + content: "\f200"; } + +.fa-pie-chart::before { + content: "\f200"; } + +.fa-bolt-lightning::before { + content: "\e0b7"; } + +.fa-sack-xmark::before { + content: "\e56a"; } + +.fa-file-excel::before { + content: "\f1c3"; } + +.fa-file-contract::before { + content: "\f56c"; } + +.fa-fish-fins::before { + content: "\e4f2"; } + +.fa-building-flag::before { + content: "\e4d5"; } + +.fa-face-grin-beam::before { + content: "\f582"; } + +.fa-grin-beam::before { + content: "\f582"; } + +.fa-object-ungroup::before { + content: "\f248"; } + +.fa-poop::before { + content: "\f619"; } + +.fa-location-pin::before { + content: "\f041"; } + +.fa-map-marker::before { + content: "\f041"; } + +.fa-kaaba::before { + content: "\f66b"; } + +.fa-toilet-paper::before { + content: "\f71e"; } + +.fa-helmet-safety::before { + content: "\f807"; } + +.fa-hard-hat::before { + content: "\f807"; } + +.fa-hat-hard::before { + content: "\f807"; } + +.fa-eject::before { + content: "\f052"; } + +.fa-circle-right::before { + content: "\f35a"; } + +.fa-arrow-alt-circle-right::before { + content: "\f35a"; } + +.fa-plane-circle-check::before { + content: "\e555"; } + +.fa-face-rolling-eyes::before { + content: "\f5a5"; } + +.fa-meh-rolling-eyes::before { + content: "\f5a5"; } + +.fa-object-group::before { + content: "\f247"; } + +.fa-chart-line::before { + content: "\f201"; } + +.fa-line-chart::before { + content: "\f201"; } + +.fa-mask-ventilator::before { + content: "\e524"; } + +.fa-arrow-right::before { + content: "\f061"; } + +.fa-signs-post::before { + content: "\f277"; } + +.fa-map-signs::before { + content: "\f277"; } + +.fa-cash-register::before { + content: "\f788"; } + +.fa-person-circle-question::before { + content: "\e542"; } + +.fa-h::before { + content: "\48"; } + +.fa-tarp::before { + content: "\e57b"; } + +.fa-screwdriver-wrench::before { + content: "\f7d9"; } + +.fa-tools::before { + content: "\f7d9"; } + +.fa-arrows-to-eye::before { + content: "\e4bf"; } + +.fa-plug-circle-bolt::before { + content: "\e55b"; } + +.fa-heart::before { + content: "\f004"; } + +.fa-mars-and-venus::before { + content: "\f224"; } + +.fa-house-user::before { + content: "\e1b0"; } + +.fa-home-user::before { + content: "\e1b0"; } + +.fa-dumpster-fire::before { + content: "\f794"; } + +.fa-house-crack::before { + content: "\e3b1"; } + +.fa-martini-glass-citrus::before { + content: "\f561"; } + +.fa-cocktail::before { + content: "\f561"; } + +.fa-face-surprise::before { + content: "\f5c2"; } + +.fa-surprise::before { + content: "\f5c2"; } + +.fa-bottle-water::before { + content: "\e4c5"; } + +.fa-circle-pause::before { + content: "\f28b"; } + +.fa-pause-circle::before { + content: "\f28b"; } + +.fa-toilet-paper-slash::before { + content: "\e072"; } + +.fa-apple-whole::before { + content: "\f5d1"; } + +.fa-apple-alt::before { + content: "\f5d1"; } + +.fa-kitchen-set::before { + content: "\e51a"; } + +.fa-r::before { + content: "\52"; } + +.fa-temperature-quarter::before { + content: "\f2ca"; } + +.fa-temperature-1::before { + content: "\f2ca"; } + +.fa-thermometer-1::before { + content: "\f2ca"; } + +.fa-thermometer-quarter::before { + content: "\f2ca"; } + +.fa-cube::before { + content: "\f1b2"; } + +.fa-bitcoin-sign::before { + content: "\e0b4"; } + +.fa-shield-dog::before { + content: "\e573"; } + +.fa-solar-panel::before { + content: "\f5ba"; } + +.fa-lock-open::before { + content: "\f3c1"; } + +.fa-elevator::before { + content: "\e16d"; } + +.fa-money-bill-transfer::before { + content: "\e528"; } + +.fa-money-bill-trend-up::before { + content: "\e529"; } + +.fa-house-flood-water-circle-arrow-right::before { + content: "\e50f"; } + +.fa-square-poll-horizontal::before { + content: "\f682"; } + +.fa-poll-h::before { + content: "\f682"; } + +.fa-circle::before { + content: "\f111"; } + +.fa-backward-fast::before { + content: "\f049"; } + +.fa-fast-backward::before { + content: "\f049"; } + +.fa-recycle::before { + content: "\f1b8"; } + +.fa-user-astronaut::before { + content: "\f4fb"; } + +.fa-plane-slash::before { + content: "\e069"; } + +.fa-trademark::before { + content: "\f25c"; } + +.fa-basketball::before { + content: "\f434"; } + +.fa-basketball-ball::before { + content: "\f434"; } + +.fa-satellite-dish::before { + content: "\f7c0"; } + +.fa-circle-up::before { + content: "\f35b"; } + +.fa-arrow-alt-circle-up::before { + content: "\f35b"; } + +.fa-mobile-screen-button::before { + content: "\f3cd"; } + +.fa-mobile-alt::before { + content: "\f3cd"; } + +.fa-volume-high::before { + content: "\f028"; } + +.fa-volume-up::before { + content: "\f028"; } + +.fa-users-rays::before { + content: "\e593"; } + +.fa-wallet::before { + content: "\f555"; } + +.fa-clipboard-check::before { + content: "\f46c"; } + +.fa-file-audio::before { + content: "\f1c7"; } + +.fa-burger::before { + content: "\f805"; } + +.fa-hamburger::before { + content: "\f805"; } + +.fa-wrench::before { + content: "\f0ad"; } + +.fa-bugs::before { + content: "\e4d0"; } + +.fa-rupee-sign::before { + content: "\f156"; } + +.fa-rupee::before { + content: "\f156"; } + +.fa-file-image::before { + content: "\f1c5"; } + +.fa-circle-question::before { + content: "\f059"; } + +.fa-question-circle::before { + content: "\f059"; } + +.fa-plane-departure::before { + content: "\f5b0"; } + +.fa-handshake-slash::before { + content: "\e060"; } + +.fa-book-bookmark::before { + content: "\e0bb"; } + +.fa-code-branch::before { + content: "\f126"; } + +.fa-hat-cowboy::before { + content: "\f8c0"; } + +.fa-bridge::before { + content: "\e4c8"; } + +.fa-phone-flip::before { + content: "\f879"; } + +.fa-phone-alt::before { + content: "\f879"; } + +.fa-truck-front::before { + content: "\e2b7"; } + +.fa-cat::before { + content: "\f6be"; } + +.fa-anchor-circle-exclamation::before { + content: "\e4ab"; } + +.fa-truck-field::before { + content: "\e58d"; } + +.fa-route::before { + content: "\f4d7"; } + +.fa-clipboard-question::before { + content: "\e4e3"; } + +.fa-panorama::before { + content: "\e209"; } + +.fa-comment-medical::before { + content: "\f7f5"; } + +.fa-teeth-open::before { + content: "\f62f"; } + +.fa-file-circle-minus::before { + content: "\e4ed"; } + +.fa-tags::before { + content: "\f02c"; } + +.fa-wine-glass::before { + content: "\f4e3"; } + +.fa-forward-fast::before { + content: "\f050"; } + +.fa-fast-forward::before { + content: "\f050"; } + +.fa-face-meh-blank::before { + content: "\f5a4"; } + +.fa-meh-blank::before { + content: "\f5a4"; } + +.fa-square-parking::before { + content: "\f540"; } + +.fa-parking::before { + content: "\f540"; } + +.fa-house-signal::before { + content: "\e012"; } + +.fa-bars-progress::before { + content: "\f828"; } + +.fa-tasks-alt::before { + content: "\f828"; } + +.fa-faucet-drip::before { + content: "\e006"; } + +.fa-cart-flatbed::before { + content: "\f474"; } + +.fa-dolly-flatbed::before { + content: "\f474"; } + +.fa-ban-smoking::before { + content: "\f54d"; } + +.fa-smoking-ban::before { + content: "\f54d"; } + +.fa-terminal::before { + content: "\f120"; } + +.fa-mobile-button::before { + content: "\f10b"; } + +.fa-house-medical-flag::before { + content: "\e514"; } + +.fa-basket-shopping::before { + content: "\f291"; } + +.fa-shopping-basket::before { + content: "\f291"; } + +.fa-tape::before { + content: "\f4db"; } + +.fa-bus-simple::before { + content: "\f55e"; } + +.fa-bus-alt::before { + content: "\f55e"; } + +.fa-eye::before { + content: "\f06e"; } + +.fa-face-sad-cry::before { + content: "\f5b3"; } + +.fa-sad-cry::before { + content: "\f5b3"; } + +.fa-audio-description::before { + content: "\f29e"; } + +.fa-person-military-to-person::before { + content: "\e54c"; } + +.fa-file-shield::before { + content: "\e4f0"; } + +.fa-user-slash::before { + content: "\f506"; } + +.fa-pen::before { + content: "\f304"; } + +.fa-tower-observation::before { + content: "\e586"; } + +.fa-file-code::before { + content: "\f1c9"; } + +.fa-signal::before { + content: "\f012"; } + +.fa-signal-5::before { + content: "\f012"; } + +.fa-signal-perfect::before { + content: "\f012"; } + +.fa-bus::before { + content: "\f207"; } + +.fa-heart-circle-xmark::before { + content: "\e501"; } + +.fa-house-chimney::before { + content: "\e3af"; } + +.fa-home-lg::before { + content: "\e3af"; } + +.fa-window-maximize::before { + content: "\f2d0"; } + +.fa-face-frown::before { + content: "\f119"; } + +.fa-frown::before { + content: "\f119"; } + +.fa-prescription::before { + content: "\f5b1"; } + +.fa-shop::before { + content: "\f54f"; } + +.fa-store-alt::before { + content: "\f54f"; } + +.fa-floppy-disk::before { + content: "\f0c7"; } + +.fa-save::before { + content: "\f0c7"; } + +.fa-vihara::before { + content: "\f6a7"; } + +.fa-scale-unbalanced::before { + content: "\f515"; } + +.fa-balance-scale-left::before { + content: "\f515"; } + +.fa-sort-up::before { + content: "\f0de"; } + +.fa-sort-asc::before { + content: "\f0de"; } + +.fa-comment-dots::before { + content: "\f4ad"; } + +.fa-commenting::before { + content: "\f4ad"; } + +.fa-plant-wilt::before { + content: "\e5aa"; } + +.fa-diamond::before { + content: "\f219"; } + +.fa-face-grin-squint::before { + content: "\f585"; } + +.fa-grin-squint::before { + content: "\f585"; } + +.fa-hand-holding-dollar::before { + content: "\f4c0"; } + +.fa-hand-holding-usd::before { + content: "\f4c0"; } + +.fa-bacterium::before { + content: "\e05a"; } + +.fa-hand-pointer::before { + content: "\f25a"; } + +.fa-drum-steelpan::before { + content: "\f56a"; } + +.fa-hand-scissors::before { + content: "\f257"; } + +.fa-hands-praying::before { + content: "\f684"; } + +.fa-praying-hands::before { + content: "\f684"; } + +.fa-arrow-rotate-right::before { + content: "\f01e"; } + +.fa-arrow-right-rotate::before { + content: "\f01e"; } + +.fa-arrow-rotate-forward::before { + content: "\f01e"; } + +.fa-redo::before { + content: "\f01e"; } + +.fa-biohazard::before { + content: "\f780"; } + +.fa-location-crosshairs::before { + content: "\f601"; } + +.fa-location::before { + content: "\f601"; } + +.fa-mars-double::before { + content: "\f227"; } + +.fa-child-dress::before { + content: "\e59c"; } + +.fa-users-between-lines::before { + content: "\e591"; } + +.fa-lungs-virus::before { + content: "\e067"; } + +.fa-face-grin-tears::before { + content: "\f588"; } + +.fa-grin-tears::before { + content: "\f588"; } + +.fa-phone::before { + content: "\f095"; } + +.fa-calendar-xmark::before { + content: "\f273"; } + +.fa-calendar-times::before { + content: "\f273"; } + +.fa-child-reaching::before { + content: "\e59d"; } + +.fa-head-side-virus::before { + content: "\e064"; } + +.fa-user-gear::before { + content: "\f4fe"; } + +.fa-user-cog::before { + content: "\f4fe"; } + +.fa-arrow-up-1-9::before { + content: "\f163"; } + +.fa-sort-numeric-up::before { + content: "\f163"; } + +.fa-door-closed::before { + content: "\f52a"; } + +.fa-shield-virus::before { + content: "\e06c"; } + +.fa-dice-six::before { + content: "\f526"; } + +.fa-mosquito-net::before { + content: "\e52c"; } + +.fa-bridge-water::before { + content: "\e4ce"; } + +.fa-person-booth::before { + content: "\f756"; } + +.fa-text-width::before { + content: "\f035"; } + +.fa-hat-wizard::before { + content: "\f6e8"; } + +.fa-pen-fancy::before { + content: "\f5ac"; } + +.fa-person-digging::before { + content: "\f85e"; } + +.fa-digging::before { + content: "\f85e"; } + +.fa-trash::before { + content: "\f1f8"; } + +.fa-gauge-simple::before { + content: "\f629"; } + +.fa-gauge-simple-med::before { + content: "\f629"; } + +.fa-tachometer-average::before { + content: "\f629"; } + +.fa-book-medical::before { + content: "\f7e6"; } + +.fa-poo::before { + content: "\f2fe"; } + +.fa-quote-right::before { + content: "\f10e"; } + +.fa-quote-right-alt::before { + content: "\f10e"; } + +.fa-shirt::before { + content: "\f553"; } + +.fa-t-shirt::before { + content: "\f553"; } + +.fa-tshirt::before { + content: "\f553"; } + +.fa-cubes::before { + content: "\f1b3"; } + +.fa-divide::before { + content: "\f529"; } + +.fa-tenge-sign::before { + content: "\f7d7"; } + +.fa-tenge::before { + content: "\f7d7"; } + +.fa-headphones::before { + content: "\f025"; } + +.fa-hands-holding::before { + content: "\f4c2"; } + +.fa-hands-clapping::before { + content: "\e1a8"; } + +.fa-republican::before { + content: "\f75e"; } + +.fa-arrow-left::before { + content: "\f060"; } + +.fa-person-circle-xmark::before { + content: "\e543"; } + +.fa-ruler::before { + content: "\f545"; } + +.fa-align-left::before { + content: "\f036"; } + +.fa-dice-d6::before { + content: "\f6d1"; } + +.fa-restroom::before { + content: "\f7bd"; } + +.fa-j::before { + content: "\4a"; } + +.fa-users-viewfinder::before { + content: "\e595"; } + +.fa-file-video::before { + content: "\f1c8"; } + +.fa-up-right-from-square::before { + content: "\f35d"; } + +.fa-external-link-alt::before { + content: "\f35d"; } + +.fa-table-cells::before { + content: "\f00a"; } + +.fa-th::before { + content: "\f00a"; } + +.fa-file-pdf::before { + content: "\f1c1"; } + +.fa-book-bible::before { + content: "\f647"; } + +.fa-bible::before { + content: "\f647"; } + +.fa-o::before { + content: "\4f"; } + +.fa-suitcase-medical::before { + content: "\f0fa"; } + +.fa-medkit::before { + content: "\f0fa"; } + +.fa-user-secret::before { + content: "\f21b"; } + +.fa-otter::before { + content: "\f700"; } + +.fa-person-dress::before { + content: "\f182"; } + +.fa-female::before { + content: "\f182"; } + +.fa-comment-dollar::before { + content: "\f651"; } + +.fa-business-time::before { + content: "\f64a"; } + +.fa-briefcase-clock::before { + content: "\f64a"; } + +.fa-table-cells-large::before { + content: "\f009"; } + +.fa-th-large::before { + content: "\f009"; } + +.fa-book-tanakh::before { + content: "\f827"; } + +.fa-tanakh::before { + content: "\f827"; } + +.fa-phone-volume::before { + content: "\f2a0"; } + +.fa-volume-control-phone::before { + content: "\f2a0"; } + +.fa-hat-cowboy-side::before { + content: "\f8c1"; } + +.fa-clipboard-user::before { + content: "\f7f3"; } + +.fa-child::before { + content: "\f1ae"; } + +.fa-lira-sign::before { + content: "\f195"; } + +.fa-satellite::before { + content: "\f7bf"; } + +.fa-plane-lock::before { + content: "\e558"; } + +.fa-tag::before { + content: "\f02b"; } + +.fa-comment::before { + content: "\f075"; } + +.fa-cake-candles::before { + content: "\f1fd"; } + +.fa-birthday-cake::before { + content: "\f1fd"; } + +.fa-cake::before { + content: "\f1fd"; } + +.fa-envelope::before { + content: "\f0e0"; } + +.fa-angles-up::before { + content: "\f102"; } + +.fa-angle-double-up::before { + content: "\f102"; } + +.fa-paperclip::before { + content: "\f0c6"; } + +.fa-arrow-right-to-city::before { + content: "\e4b3"; } + +.fa-ribbon::before { + content: "\f4d6"; } + +.fa-lungs::before { + content: "\f604"; } + +.fa-arrow-up-9-1::before { + content: "\f887"; } + +.fa-sort-numeric-up-alt::before { + content: "\f887"; } + +.fa-litecoin-sign::before { + content: "\e1d3"; } + +.fa-border-none::before { + content: "\f850"; } + +.fa-circle-nodes::before { + content: "\e4e2"; } + +.fa-parachute-box::before { + content: "\f4cd"; } + +.fa-indent::before { + content: "\f03c"; } + +.fa-truck-field-un::before { + content: "\e58e"; } + +.fa-hourglass::before { + content: "\f254"; } + +.fa-hourglass-empty::before { + content: "\f254"; } + +.fa-mountain::before { + content: "\f6fc"; } + +.fa-user-doctor::before { + content: "\f0f0"; } + +.fa-user-md::before { + content: "\f0f0"; } + +.fa-circle-info::before { + content: "\f05a"; } + +.fa-info-circle::before { + content: "\f05a"; } + +.fa-cloud-meatball::before { + content: "\f73b"; } + +.fa-camera::before { + content: "\f030"; } + +.fa-camera-alt::before { + content: "\f030"; } + +.fa-square-virus::before { + content: "\e578"; } + +.fa-meteor::before { + content: "\f753"; } + +.fa-car-on::before { + content: "\e4dd"; } + +.fa-sleigh::before { + content: "\f7cc"; } + +.fa-arrow-down-1-9::before { + content: "\f162"; } + +.fa-sort-numeric-asc::before { + content: "\f162"; } + +.fa-sort-numeric-down::before { + content: "\f162"; } + +.fa-hand-holding-droplet::before { + content: "\f4c1"; } + +.fa-hand-holding-water::before { + content: "\f4c1"; } + +.fa-water::before { + content: "\f773"; } + +.fa-calendar-check::before { + content: "\f274"; } + +.fa-braille::before { + content: "\f2a1"; } + +.fa-prescription-bottle-medical::before { + content: "\f486"; } + +.fa-prescription-bottle-alt::before { + content: "\f486"; } + +.fa-landmark::before { + content: "\f66f"; } + +.fa-truck::before { + content: "\f0d1"; } + +.fa-crosshairs::before { + content: "\f05b"; } + +.fa-person-cane::before { + content: "\e53c"; } + +.fa-tent::before { + content: "\e57d"; } + +.fa-vest-patches::before { + content: "\e086"; } + +.fa-check-double::before { + content: "\f560"; } + +.fa-arrow-down-a-z::before { + content: "\f15d"; } + +.fa-sort-alpha-asc::before { + content: "\f15d"; } + +.fa-sort-alpha-down::before { + content: "\f15d"; } + +.fa-money-bill-wheat::before { + content: "\e52a"; } + +.fa-cookie::before { + content: "\f563"; } + +.fa-arrow-rotate-left::before { + content: "\f0e2"; } + +.fa-arrow-left-rotate::before { + content: "\f0e2"; } + +.fa-arrow-rotate-back::before { + content: "\f0e2"; } + +.fa-arrow-rotate-backward::before { + content: "\f0e2"; } + +.fa-undo::before { + content: "\f0e2"; } + +.fa-hard-drive::before { + content: "\f0a0"; } + +.fa-hdd::before { + content: "\f0a0"; } + +.fa-face-grin-squint-tears::before { + content: "\f586"; } + +.fa-grin-squint-tears::before { + content: "\f586"; } + +.fa-dumbbell::before { + content: "\f44b"; } + +.fa-rectangle-list::before { + content: "\f022"; } + +.fa-list-alt::before { + content: "\f022"; } + +.fa-tarp-droplet::before { + content: "\e57c"; } + +.fa-house-medical-circle-check::before { + content: "\e511"; } + +.fa-person-skiing-nordic::before { + content: "\f7ca"; } + +.fa-skiing-nordic::before { + content: "\f7ca"; } + +.fa-calendar-plus::before { + content: "\f271"; } + +.fa-plane-arrival::before { + content: "\f5af"; } + +.fa-circle-left::before { + content: "\f359"; } + +.fa-arrow-alt-circle-left::before { + content: "\f359"; } + +.fa-train-subway::before { + content: "\f239"; } + +.fa-subway::before { + content: "\f239"; } + +.fa-chart-gantt::before { + content: "\e0e4"; } + +.fa-indian-rupee-sign::before { + content: "\e1bc"; } + +.fa-indian-rupee::before { + content: "\e1bc"; } + +.fa-inr::before { + content: "\e1bc"; } + +.fa-crop-simple::before { + content: "\f565"; } + +.fa-crop-alt::before { + content: "\f565"; } + +.fa-money-bill-1::before { + content: "\f3d1"; } + +.fa-money-bill-alt::before { + content: "\f3d1"; } + +.fa-left-long::before { + content: "\f30a"; } + +.fa-long-arrow-alt-left::before { + content: "\f30a"; } + +.fa-dna::before { + content: "\f471"; } + +.fa-virus-slash::before { + content: "\e075"; } + +.fa-minus::before { + content: "\f068"; } + +.fa-subtract::before { + content: "\f068"; } + +.fa-chess::before { + content: "\f439"; } + +.fa-arrow-left-long::before { + content: "\f177"; } + +.fa-long-arrow-left::before { + content: "\f177"; } + +.fa-plug-circle-check::before { + content: "\e55c"; } + +.fa-street-view::before { + content: "\f21d"; } + +.fa-franc-sign::before { + content: "\e18f"; } + +.fa-volume-off::before { + content: "\f026"; } + +.fa-hands-asl-interpreting::before { + content: "\f2a3"; } + +.fa-american-sign-language-interpreting::before { + content: "\f2a3"; } + +.fa-asl-interpreting::before { + content: "\f2a3"; } + +.fa-hands-american-sign-language-interpreting::before { + content: "\f2a3"; } + +.fa-gear::before { + content: "\f013"; } + +.fa-cog::before { + content: "\f013"; } + +.fa-droplet-slash::before { + content: "\f5c7"; } + +.fa-tint-slash::before { + content: "\f5c7"; } + +.fa-mosque::before { + content: "\f678"; } + +.fa-mosquito::before { + content: "\e52b"; } + +.fa-star-of-david::before { + content: "\f69a"; } + +.fa-person-military-rifle::before { + content: "\e54b"; } + +.fa-cart-shopping::before { + content: "\f07a"; } + +.fa-shopping-cart::before { + content: "\f07a"; } + +.fa-vials::before { + content: "\f493"; } + +.fa-plug-circle-plus::before { + content: "\e55f"; } + +.fa-place-of-worship::before { + content: "\f67f"; } + +.fa-grip-vertical::before { + content: "\f58e"; } + +.fa-arrow-turn-up::before { + content: "\f148"; } + +.fa-level-up::before { + content: "\f148"; } + +.fa-u::before { + content: "\55"; } + +.fa-square-root-variable::before { + content: "\f698"; } + +.fa-square-root-alt::before { + content: "\f698"; } + +.fa-clock::before { + content: "\f017"; } + +.fa-clock-four::before { + content: "\f017"; } + +.fa-backward-step::before { + content: "\f048"; } + +.fa-step-backward::before { + content: "\f048"; } + +.fa-pallet::before { + content: "\f482"; } + +.fa-faucet::before { + content: "\e005"; } + +.fa-baseball-bat-ball::before { + content: "\f432"; } + +.fa-s::before { + content: "\53"; } + +.fa-timeline::before { + content: "\e29c"; } + +.fa-keyboard::before { + content: "\f11c"; } + +.fa-caret-down::before { + content: "\f0d7"; } + +.fa-house-chimney-medical::before { + content: "\f7f2"; } + +.fa-clinic-medical::before { + content: "\f7f2"; } + +.fa-temperature-three-quarters::before { + content: "\f2c8"; } + +.fa-temperature-3::before { + content: "\f2c8"; } + +.fa-thermometer-3::before { + content: "\f2c8"; } + +.fa-thermometer-three-quarters::before { + content: "\f2c8"; } + +.fa-mobile-screen::before { + content: "\f3cf"; } + +.fa-mobile-android-alt::before { + content: "\f3cf"; } + +.fa-plane-up::before { + content: "\e22d"; } + +.fa-piggy-bank::before { + content: "\f4d3"; } + +.fa-battery-half::before { + content: "\f242"; } + +.fa-battery-3::before { + content: "\f242"; } + +.fa-mountain-city::before { + content: "\e52e"; } + +.fa-coins::before { + content: "\f51e"; } + +.fa-khanda::before { + content: "\f66d"; } + +.fa-sliders::before { + content: "\f1de"; } + +.fa-sliders-h::before { + content: "\f1de"; } + +.fa-folder-tree::before { + content: "\f802"; } + +.fa-network-wired::before { + content: "\f6ff"; } + +.fa-map-pin::before { + content: "\f276"; } + +.fa-hamsa::before { + content: "\f665"; } + +.fa-cent-sign::before { + content: "\e3f5"; } + +.fa-flask::before { + content: "\f0c3"; } + +.fa-person-pregnant::before { + content: "\e31e"; } + +.fa-wand-sparkles::before { + content: "\f72b"; } + +.fa-ellipsis-vertical::before { + content: "\f142"; } + +.fa-ellipsis-v::before { + content: "\f142"; } + +.fa-ticket::before { + content: "\f145"; } + +.fa-power-off::before { + content: "\f011"; } + +.fa-right-long::before { + content: "\f30b"; } + +.fa-long-arrow-alt-right::before { + content: "\f30b"; } + +.fa-flag-usa::before { + content: "\f74d"; } + +.fa-laptop-file::before { + content: "\e51d"; } + +.fa-tty::before { + content: "\f1e4"; } + +.fa-teletype::before { + content: "\f1e4"; } + +.fa-diagram-next::before { + content: "\e476"; } + +.fa-person-rifle::before { + content: "\e54e"; } + +.fa-house-medical-circle-exclamation::before { + content: "\e512"; } + +.fa-closed-captioning::before { + content: "\f20a"; } + +.fa-person-hiking::before { + content: "\f6ec"; } + +.fa-hiking::before { + content: "\f6ec"; } + +.fa-venus-double::before { + content: "\f226"; } + +.fa-images::before { + content: "\f302"; } + +.fa-calculator::before { + content: "\f1ec"; } + +.fa-people-pulling::before { + content: "\e535"; } + +.fa-n::before { + content: "\4e"; } + +.fa-cable-car::before { + content: "\f7da"; } + +.fa-tram::before { + content: "\f7da"; } + +.fa-cloud-rain::before { + content: "\f73d"; } + +.fa-building-circle-xmark::before { + content: "\e4d4"; } + +.fa-ship::before { + content: "\f21a"; } + +.fa-arrows-down-to-line::before { + content: "\e4b8"; } + +.fa-download::before { + content: "\f019"; } + +.fa-face-grin::before { + content: "\f580"; } + +.fa-grin::before { + content: "\f580"; } + +.fa-delete-left::before { + content: "\f55a"; } + +.fa-backspace::before { + content: "\f55a"; } + +.fa-eye-dropper::before { + content: "\f1fb"; } + +.fa-eye-dropper-empty::before { + content: "\f1fb"; } + +.fa-eyedropper::before { + content: "\f1fb"; } + +.fa-file-circle-check::before { + content: "\e5a0"; } + +.fa-forward::before { + content: "\f04e"; } + +.fa-mobile::before { + content: "\f3ce"; } + +.fa-mobile-android::before { + content: "\f3ce"; } + +.fa-mobile-phone::before { + content: "\f3ce"; } + +.fa-face-meh::before { + content: "\f11a"; } + +.fa-meh::before { + content: "\f11a"; } + +.fa-align-center::before { + content: "\f037"; } + +.fa-book-skull::before { + content: "\f6b7"; } + +.fa-book-dead::before { + content: "\f6b7"; } + +.fa-id-card::before { + content: "\f2c2"; } + +.fa-drivers-license::before { + content: "\f2c2"; } + +.fa-outdent::before { + content: "\f03b"; } + +.fa-dedent::before { + content: "\f03b"; } + +.fa-heart-circle-exclamation::before { + content: "\e4fe"; } + +.fa-house::before { + content: "\f015"; } + +.fa-home::before { + content: "\f015"; } + +.fa-home-alt::before { + content: "\f015"; } + +.fa-home-lg-alt::before { + content: "\f015"; } + +.fa-calendar-week::before { + content: "\f784"; } + +.fa-laptop-medical::before { + content: "\f812"; } + +.fa-b::before { + content: "\42"; } + +.fa-file-medical::before { + content: "\f477"; } + +.fa-dice-one::before { + content: "\f525"; } + +.fa-kiwi-bird::before { + content: "\f535"; } + +.fa-arrow-right-arrow-left::before { + content: "\f0ec"; } + +.fa-exchange::before { + content: "\f0ec"; } + +.fa-rotate-right::before { + content: "\f2f9"; } + +.fa-redo-alt::before { + content: "\f2f9"; } + +.fa-rotate-forward::before { + content: "\f2f9"; } + +.fa-utensils::before { + content: "\f2e7"; } + +.fa-cutlery::before { + content: "\f2e7"; } + +.fa-arrow-up-wide-short::before { + content: "\f161"; } + +.fa-sort-amount-up::before { + content: "\f161"; } + +.fa-mill-sign::before { + content: "\e1ed"; } + +.fa-bowl-rice::before { + content: "\e2eb"; } + +.fa-skull::before { + content: "\f54c"; } + +.fa-tower-broadcast::before { + content: "\f519"; } + +.fa-broadcast-tower::before { + content: "\f519"; } + +.fa-truck-pickup::before { + content: "\f63c"; } + +.fa-up-long::before { + content: "\f30c"; } + +.fa-long-arrow-alt-up::before { + content: "\f30c"; } + +.fa-stop::before { + content: "\f04d"; } + +.fa-code-merge::before { + content: "\f387"; } + +.fa-upload::before { + content: "\f093"; } + +.fa-hurricane::before { + content: "\f751"; } + +.fa-mound::before { + content: "\e52d"; } + +.fa-toilet-portable::before { + content: "\e583"; } + +.fa-compact-disc::before { + content: "\f51f"; } + +.fa-file-arrow-down::before { + content: "\f56d"; } + +.fa-file-download::before { + content: "\f56d"; } + +.fa-caravan::before { + content: "\f8ff"; } + +.fa-shield-cat::before { + content: "\e572"; } + +.fa-bolt::before { + content: "\f0e7"; } + +.fa-zap::before { + content: "\f0e7"; } + +.fa-glass-water::before { + content: "\e4f4"; } + +.fa-oil-well::before { + content: "\e532"; } + +.fa-vault::before { + content: "\e2c5"; } + +.fa-mars::before { + content: "\f222"; } + +.fa-toilet::before { + content: "\f7d8"; } + +.fa-plane-circle-xmark::before { + content: "\e557"; } + +.fa-yen-sign::before { + content: "\f157"; } + +.fa-cny::before { + content: "\f157"; } + +.fa-jpy::before { + content: "\f157"; } + +.fa-rmb::before { + content: "\f157"; } + +.fa-yen::before { + content: "\f157"; } + +.fa-ruble-sign::before { + content: "\f158"; } + +.fa-rouble::before { + content: "\f158"; } + +.fa-rub::before { + content: "\f158"; } + +.fa-ruble::before { + content: "\f158"; } + +.fa-sun::before { + content: "\f185"; } + +.fa-guitar::before { + content: "\f7a6"; } + +.fa-face-laugh-wink::before { + content: "\f59c"; } + +.fa-laugh-wink::before { + content: "\f59c"; } + +.fa-horse-head::before { + content: "\f7ab"; } + +.fa-bore-hole::before { + content: "\e4c3"; } + +.fa-industry::before { + content: "\f275"; } + +.fa-circle-down::before { + content: "\f358"; } + +.fa-arrow-alt-circle-down::before { + content: "\f358"; } + +.fa-arrows-turn-to-dots::before { + content: "\e4c1"; } + +.fa-florin-sign::before { + content: "\e184"; } + +.fa-arrow-down-short-wide::before { + content: "\f884"; } + +.fa-sort-amount-desc::before { + content: "\f884"; } + +.fa-sort-amount-down-alt::before { + content: "\f884"; } + +.fa-less-than::before { + content: "\3c"; } + +.fa-angle-down::before { + content: "\f107"; } + +.fa-car-tunnel::before { + content: "\e4de"; } + +.fa-head-side-cough::before { + content: "\e061"; } + +.fa-grip-lines::before { + content: "\f7a4"; } + +.fa-thumbs-down::before { + content: "\f165"; } + +.fa-user-lock::before { + content: "\f502"; } + +.fa-arrow-right-long::before { + content: "\f178"; } + +.fa-long-arrow-right::before { + content: "\f178"; } + +.fa-anchor-circle-xmark::before { + content: "\e4ac"; } + +.fa-ellipsis::before { + content: "\f141"; } + +.fa-ellipsis-h::before { + content: "\f141"; } + +.fa-chess-pawn::before { + content: "\f443"; } + +.fa-kit-medical::before { + content: "\f479"; } + +.fa-first-aid::before { + content: "\f479"; } + +.fa-person-through-window::before { + content: "\e5a9"; } + +.fa-toolbox::before { + content: "\f552"; } + +.fa-hands-holding-circle::before { + content: "\e4fb"; } + +.fa-bug::before { + content: "\f188"; } + +.fa-credit-card::before { + content: "\f09d"; } + +.fa-credit-card-alt::before { + content: "\f09d"; } + +.fa-car::before { + content: "\f1b9"; } + +.fa-automobile::before { + content: "\f1b9"; } + +.fa-hand-holding-hand::before { + content: "\e4f7"; } + +.fa-book-open-reader::before { + content: "\f5da"; } + +.fa-book-reader::before { + content: "\f5da"; } + +.fa-mountain-sun::before { + content: "\e52f"; } + +.fa-arrows-left-right-to-line::before { + content: "\e4ba"; } + +.fa-dice-d20::before { + content: "\f6cf"; } + +.fa-truck-droplet::before { + content: "\e58c"; } + +.fa-file-circle-xmark::before { + content: "\e5a1"; } + +.fa-temperature-arrow-up::before { + content: "\e040"; } + +.fa-temperature-up::before { + content: "\e040"; } + +.fa-medal::before { + content: "\f5a2"; } + +.fa-bed::before { + content: "\f236"; } + +.fa-square-h::before { + content: "\f0fd"; } + +.fa-h-square::before { + content: "\f0fd"; } + +.fa-podcast::before { + content: "\f2ce"; } + +.fa-temperature-full::before { + content: "\f2c7"; } + +.fa-temperature-4::before { + content: "\f2c7"; } + +.fa-thermometer-4::before { + content: "\f2c7"; } + +.fa-thermometer-full::before { + content: "\f2c7"; } + +.fa-bell::before { + content: "\f0f3"; } + +.fa-superscript::before { + content: "\f12b"; } + +.fa-plug-circle-xmark::before { + content: "\e560"; } + +.fa-star-of-life::before { + content: "\f621"; } + +.fa-phone-slash::before { + content: "\f3dd"; } + +.fa-paint-roller::before { + content: "\f5aa"; } + +.fa-handshake-angle::before { + content: "\f4c4"; } + +.fa-hands-helping::before { + content: "\f4c4"; } + +.fa-location-dot::before { + content: "\f3c5"; } + +.fa-map-marker-alt::before { + content: "\f3c5"; } + +.fa-file::before { + content: "\f15b"; } + +.fa-greater-than::before { + content: "\3e"; } + +.fa-person-swimming::before { + content: "\f5c4"; } + +.fa-swimmer::before { + content: "\f5c4"; } + +.fa-arrow-down::before { + content: "\f063"; } + +.fa-droplet::before { + content: "\f043"; } + +.fa-tint::before { + content: "\f043"; } + +.fa-eraser::before { + content: "\f12d"; } + +.fa-earth-americas::before { + content: "\f57d"; } + +.fa-earth::before { + content: "\f57d"; } + +.fa-earth-america::before { + content: "\f57d"; } + +.fa-globe-americas::before { + content: "\f57d"; } + +.fa-person-burst::before { + content: "\e53b"; } + +.fa-dove::before { + content: "\f4ba"; } + +.fa-battery-empty::before { + content: "\f244"; } + +.fa-battery-0::before { + content: "\f244"; } + +.fa-socks::before { + content: "\f696"; } + +.fa-inbox::before { + content: "\f01c"; } + +.fa-section::before { + content: "\e447"; } + +.fa-gauge-high::before { + content: "\f625"; } + +.fa-tachometer-alt::before { + content: "\f625"; } + +.fa-tachometer-alt-fast::before { + content: "\f625"; } + +.fa-envelope-open-text::before { + content: "\f658"; } + +.fa-hospital::before { + content: "\f0f8"; } + +.fa-hospital-alt::before { + content: "\f0f8"; } + +.fa-hospital-wide::before { + content: "\f0f8"; } + +.fa-wine-bottle::before { + content: "\f72f"; } + +.fa-chess-rook::before { + content: "\f447"; } + +.fa-bars-staggered::before { + content: "\f550"; } + +.fa-reorder::before { + content: "\f550"; } + +.fa-stream::before { + content: "\f550"; } + +.fa-dharmachakra::before { + content: "\f655"; } + +.fa-hotdog::before { + content: "\f80f"; } + +.fa-person-walking-with-cane::before { + content: "\f29d"; } + +.fa-blind::before { + content: "\f29d"; } + +.fa-drum::before { + content: "\f569"; } + +.fa-ice-cream::before { + content: "\f810"; } + +.fa-heart-circle-bolt::before { + content: "\e4fc"; } + +.fa-fax::before { + content: "\f1ac"; } + +.fa-paragraph::before { + content: "\f1dd"; } + +.fa-check-to-slot::before { + content: "\f772"; } + +.fa-vote-yea::before { + content: "\f772"; } + +.fa-star-half::before { + content: "\f089"; } + +.fa-boxes-stacked::before { + content: "\f468"; } + +.fa-boxes::before { + content: "\f468"; } + +.fa-boxes-alt::before { + content: "\f468"; } + +.fa-link::before { + content: "\f0c1"; } + +.fa-chain::before { + content: "\f0c1"; } + +.fa-ear-listen::before { + content: "\f2a2"; } + +.fa-assistive-listening-systems::before { + content: "\f2a2"; } + +.fa-tree-city::before { + content: "\e587"; } + +.fa-play::before { + content: "\f04b"; } + +.fa-font::before { + content: "\f031"; } + +.fa-table-cells-row-lock::before { + content: "\e67a"; } + +.fa-rupiah-sign::before { + content: "\e23d"; } + +.fa-magnifying-glass::before { + content: "\f002"; } + +.fa-search::before { + content: "\f002"; } + +.fa-table-tennis-paddle-ball::before { + content: "\f45d"; } + +.fa-ping-pong-paddle-ball::before { + content: "\f45d"; } + +.fa-table-tennis::before { + content: "\f45d"; } + +.fa-person-dots-from-line::before { + content: "\f470"; } + +.fa-diagnoses::before { + content: "\f470"; } + +.fa-trash-can-arrow-up::before { + content: "\f82a"; } + +.fa-trash-restore-alt::before { + content: "\f82a"; } + +.fa-naira-sign::before { + content: "\e1f6"; } + +.fa-cart-arrow-down::before { + content: "\f218"; } + +.fa-walkie-talkie::before { + content: "\f8ef"; } + +.fa-file-pen::before { + content: "\f31c"; } + +.fa-file-edit::before { + content: "\f31c"; } + +.fa-receipt::before { + content: "\f543"; } + +.fa-square-pen::before { + content: "\f14b"; } + +.fa-pen-square::before { + content: "\f14b"; } + +.fa-pencil-square::before { + content: "\f14b"; } + +.fa-suitcase-rolling::before { + content: "\f5c1"; } + +.fa-person-circle-exclamation::before { + content: "\e53f"; } + +.fa-chevron-down::before { + content: "\f078"; } + +.fa-battery-full::before { + content: "\f240"; } + +.fa-battery::before { + content: "\f240"; } + +.fa-battery-5::before { + content: "\f240"; } + +.fa-skull-crossbones::before { + content: "\f714"; } + +.fa-code-compare::before { + content: "\e13a"; } + +.fa-list-ul::before { + content: "\f0ca"; } + +.fa-list-dots::before { + content: "\f0ca"; } + +.fa-school-lock::before { + content: "\e56f"; } + +.fa-tower-cell::before { + content: "\e585"; } + +.fa-down-long::before { + content: "\f309"; } + +.fa-long-arrow-alt-down::before { + content: "\f309"; } + +.fa-ranking-star::before { + content: "\e561"; } + +.fa-chess-king::before { + content: "\f43f"; } + +.fa-person-harassing::before { + content: "\e549"; } + +.fa-brazilian-real-sign::before { + content: "\e46c"; } + +.fa-landmark-dome::before { + content: "\f752"; } + +.fa-landmark-alt::before { + content: "\f752"; } + +.fa-arrow-up::before { + content: "\f062"; } + +.fa-tv::before { + content: "\f26c"; } + +.fa-television::before { + content: "\f26c"; } + +.fa-tv-alt::before { + content: "\f26c"; } + +.fa-shrimp::before { + content: "\e448"; } + +.fa-list-check::before { + content: "\f0ae"; } + +.fa-tasks::before { + content: "\f0ae"; } + +.fa-jug-detergent::before { + content: "\e519"; } + +.fa-circle-user::before { + content: "\f2bd"; } + +.fa-user-circle::before { + content: "\f2bd"; } + +.fa-user-shield::before { + content: "\f505"; } + +.fa-wind::before { + content: "\f72e"; } + +.fa-car-burst::before { + content: "\f5e1"; } + +.fa-car-crash::before { + content: "\f5e1"; } + +.fa-y::before { + content: "\59"; } + +.fa-person-snowboarding::before { + content: "\f7ce"; } + +.fa-snowboarding::before { + content: "\f7ce"; } + +.fa-truck-fast::before { + content: "\f48b"; } + +.fa-shipping-fast::before { + content: "\f48b"; } + +.fa-fish::before { + content: "\f578"; } + +.fa-user-graduate::before { + content: "\f501"; } + +.fa-circle-half-stroke::before { + content: "\f042"; } + +.fa-adjust::before { + content: "\f042"; } + +.fa-clapperboard::before { + content: "\e131"; } + +.fa-circle-radiation::before { + content: "\f7ba"; } + +.fa-radiation-alt::before { + content: "\f7ba"; } + +.fa-baseball::before { + content: "\f433"; } + +.fa-baseball-ball::before { + content: "\f433"; } + +.fa-jet-fighter-up::before { + content: "\e518"; } + +.fa-diagram-project::before { + content: "\f542"; } + +.fa-project-diagram::before { + content: "\f542"; } + +.fa-copy::before { + content: "\f0c5"; } + +.fa-volume-xmark::before { + content: "\f6a9"; } + +.fa-volume-mute::before { + content: "\f6a9"; } + +.fa-volume-times::before { + content: "\f6a9"; } + +.fa-hand-sparkles::before { + content: "\e05d"; } + +.fa-grip::before { + content: "\f58d"; } + +.fa-grip-horizontal::before { + content: "\f58d"; } + +.fa-share-from-square::before { + content: "\f14d"; } + +.fa-share-square::before { + content: "\f14d"; } + +.fa-child-combatant::before { + content: "\e4e0"; } + +.fa-child-rifle::before { + content: "\e4e0"; } + +.fa-gun::before { + content: "\e19b"; } + +.fa-square-phone::before { + content: "\f098"; } + +.fa-phone-square::before { + content: "\f098"; } + +.fa-plus::before { + content: "\2b"; } + +.fa-add::before { + content: "\2b"; } + +.fa-expand::before { + content: "\f065"; } + +.fa-computer::before { + content: "\e4e5"; } + +.fa-xmark::before { + content: "\f00d"; } + +.fa-close::before { + content: "\f00d"; } + +.fa-multiply::before { + content: "\f00d"; } + +.fa-remove::before { + content: "\f00d"; } + +.fa-times::before { + content: "\f00d"; } + +.fa-arrows-up-down-left-right::before { + content: "\f047"; } + +.fa-arrows::before { + content: "\f047"; } + +.fa-chalkboard-user::before { + content: "\f51c"; } + +.fa-chalkboard-teacher::before { + content: "\f51c"; } + +.fa-peso-sign::before { + content: "\e222"; } + +.fa-building-shield::before { + content: "\e4d8"; } + +.fa-baby::before { + content: "\f77c"; } + +.fa-users-line::before { + content: "\e592"; } + +.fa-quote-left::before { + content: "\f10d"; } + +.fa-quote-left-alt::before { + content: "\f10d"; } + +.fa-tractor::before { + content: "\f722"; } + +.fa-trash-arrow-up::before { + content: "\f829"; } + +.fa-trash-restore::before { + content: "\f829"; } + +.fa-arrow-down-up-lock::before { + content: "\e4b0"; } + +.fa-lines-leaning::before { + content: "\e51e"; } + +.fa-ruler-combined::before { + content: "\f546"; } + +.fa-copyright::before { + content: "\f1f9"; } + +.fa-equals::before { + content: "\3d"; } + +.fa-blender::before { + content: "\f517"; } + +.fa-teeth::before { + content: "\f62e"; } + +.fa-shekel-sign::before { + content: "\f20b"; } + +.fa-ils::before { + content: "\f20b"; } + +.fa-shekel::before { + content: "\f20b"; } + +.fa-sheqel::before { + content: "\f20b"; } + +.fa-sheqel-sign::before { + content: "\f20b"; } + +.fa-map::before { + content: "\f279"; } + +.fa-rocket::before { + content: "\f135"; } + +.fa-photo-film::before { + content: "\f87c"; } + +.fa-photo-video::before { + content: "\f87c"; } + +.fa-folder-minus::before { + content: "\f65d"; } + +.fa-store::before { + content: "\f54e"; } + +.fa-arrow-trend-up::before { + content: "\e098"; } + +.fa-plug-circle-minus::before { + content: "\e55e"; } + +.fa-sign-hanging::before { + content: "\f4d9"; } + +.fa-sign::before { + content: "\f4d9"; } + +.fa-bezier-curve::before { + content: "\f55b"; } + +.fa-bell-slash::before { + content: "\f1f6"; } + +.fa-tablet::before { + content: "\f3fb"; } + +.fa-tablet-android::before { + content: "\f3fb"; } + +.fa-school-flag::before { + content: "\e56e"; } + +.fa-fill::before { + content: "\f575"; } + +.fa-angle-up::before { + content: "\f106"; } + +.fa-drumstick-bite::before { + content: "\f6d7"; } + +.fa-holly-berry::before { + content: "\f7aa"; } + +.fa-chevron-left::before { + content: "\f053"; } + +.fa-bacteria::before { + content: "\e059"; } + +.fa-hand-lizard::before { + content: "\f258"; } + +.fa-notdef::before { + content: "\e1fe"; } + +.fa-disease::before { + content: "\f7fa"; } + +.fa-briefcase-medical::before { + content: "\f469"; } + +.fa-genderless::before { + content: "\f22d"; } + +.fa-chevron-right::before { + content: "\f054"; } + +.fa-retweet::before { + content: "\f079"; } + +.fa-car-rear::before { + content: "\f5de"; } + +.fa-car-alt::before { + content: "\f5de"; } + +.fa-pump-soap::before { + content: "\e06b"; } + +.fa-video-slash::before { + content: "\f4e2"; } + +.fa-battery-quarter::before { + content: "\f243"; } + +.fa-battery-2::before { + content: "\f243"; } + +.fa-radio::before { + content: "\f8d7"; } + +.fa-baby-carriage::before { + content: "\f77d"; } + +.fa-carriage-baby::before { + content: "\f77d"; } + +.fa-traffic-light::before { + content: "\f637"; } + +.fa-thermometer::before { + content: "\f491"; } + +.fa-vr-cardboard::before { + content: "\f729"; } + +.fa-hand-middle-finger::before { + content: "\f806"; } + +.fa-percent::before { + content: "\25"; } + +.fa-percentage::before { + content: "\25"; } + +.fa-truck-moving::before { + content: "\f4df"; } + +.fa-glass-water-droplet::before { + content: "\e4f5"; } + +.fa-display::before { + content: "\e163"; } + +.fa-face-smile::before { + content: "\f118"; } + +.fa-smile::before { + content: "\f118"; } + +.fa-thumbtack::before { + content: "\f08d"; } + +.fa-thumb-tack::before { + content: "\f08d"; } + +.fa-trophy::before { + content: "\f091"; } + +.fa-person-praying::before { + content: "\f683"; } + +.fa-pray::before { + content: "\f683"; } + +.fa-hammer::before { + content: "\f6e3"; } + +.fa-hand-peace::before { + content: "\f25b"; } + +.fa-rotate::before { + content: "\f2f1"; } + +.fa-sync-alt::before { + content: "\f2f1"; } + +.fa-spinner::before { + content: "\f110"; } + +.fa-robot::before { + content: "\f544"; } + +.fa-peace::before { + content: "\f67c"; } + +.fa-gears::before { + content: "\f085"; } + +.fa-cogs::before { + content: "\f085"; } + +.fa-warehouse::before { + content: "\f494"; } + +.fa-arrow-up-right-dots::before { + content: "\e4b7"; } + +.fa-splotch::before { + content: "\f5bc"; } + +.fa-face-grin-hearts::before { + content: "\f584"; } + +.fa-grin-hearts::before { + content: "\f584"; } + +.fa-dice-four::before { + content: "\f524"; } + +.fa-sim-card::before { + content: "\f7c4"; } + +.fa-transgender::before { + content: "\f225"; } + +.fa-transgender-alt::before { + content: "\f225"; } + +.fa-mercury::before { + content: "\f223"; } + +.fa-arrow-turn-down::before { + content: "\f149"; } + +.fa-level-down::before { + content: "\f149"; } + +.fa-person-falling-burst::before { + content: "\e547"; } + +.fa-award::before { + content: "\f559"; } + +.fa-ticket-simple::before { + content: "\f3ff"; } + +.fa-ticket-alt::before { + content: "\f3ff"; } + +.fa-building::before { + content: "\f1ad"; } + +.fa-angles-left::before { + content: "\f100"; } + +.fa-angle-double-left::before { + content: "\f100"; } + +.fa-qrcode::before { + content: "\f029"; } + +.fa-clock-rotate-left::before { + content: "\f1da"; } + +.fa-history::before { + content: "\f1da"; } + +.fa-face-grin-beam-sweat::before { + content: "\f583"; } + +.fa-grin-beam-sweat::before { + content: "\f583"; } + +.fa-file-export::before { + content: "\f56e"; } + +.fa-arrow-right-from-file::before { + content: "\f56e"; } + +.fa-shield::before { + content: "\f132"; } + +.fa-shield-blank::before { + content: "\f132"; } + +.fa-arrow-up-short-wide::before { + content: "\f885"; } + +.fa-sort-amount-up-alt::before { + content: "\f885"; } + +.fa-house-medical::before { + content: "\e3b2"; } + +.fa-golf-ball-tee::before { + content: "\f450"; } + +.fa-golf-ball::before { + content: "\f450"; } + +.fa-circle-chevron-left::before { + content: "\f137"; } + +.fa-chevron-circle-left::before { + content: "\f137"; } + +.fa-house-chimney-window::before { + content: "\e00d"; } + +.fa-pen-nib::before { + content: "\f5ad"; } + +.fa-tent-arrow-turn-left::before { + content: "\e580"; } + +.fa-tents::before { + content: "\e582"; } + +.fa-wand-magic::before { + content: "\f0d0"; } + +.fa-magic::before { + content: "\f0d0"; } + +.fa-dog::before { + content: "\f6d3"; } + +.fa-carrot::before { + content: "\f787"; } + +.fa-moon::before { + content: "\f186"; } + +.fa-wine-glass-empty::before { + content: "\f5ce"; } + +.fa-wine-glass-alt::before { + content: "\f5ce"; } + +.fa-cheese::before { + content: "\f7ef"; } + +.fa-yin-yang::before { + content: "\f6ad"; } + +.fa-music::before { + content: "\f001"; } + +.fa-code-commit::before { + content: "\f386"; } + +.fa-temperature-low::before { + content: "\f76b"; } + +.fa-person-biking::before { + content: "\f84a"; } + +.fa-biking::before { + content: "\f84a"; } + +.fa-broom::before { + content: "\f51a"; } + +.fa-shield-heart::before { + content: "\e574"; } + +.fa-gopuram::before { + content: "\f664"; } + +.fa-earth-oceania::before { + content: "\e47b"; } + +.fa-globe-oceania::before { + content: "\e47b"; } + +.fa-square-xmark::before { + content: "\f2d3"; } + +.fa-times-square::before { + content: "\f2d3"; } + +.fa-xmark-square::before { + content: "\f2d3"; } + +.fa-hashtag::before { + content: "\23"; } + +.fa-up-right-and-down-left-from-center::before { + content: "\f424"; } + +.fa-expand-alt::before { + content: "\f424"; } + +.fa-oil-can::before { + content: "\f613"; } + +.fa-t::before { + content: "\54"; } + +.fa-hippo::before { + content: "\f6ed"; } + +.fa-chart-column::before { + content: "\e0e3"; } + +.fa-infinity::before { + content: "\f534"; } + +.fa-vial-circle-check::before { + content: "\e596"; } + +.fa-person-arrow-down-to-line::before { + content: "\e538"; } + +.fa-voicemail::before { + content: "\f897"; } + +.fa-fan::before { + content: "\f863"; } + +.fa-person-walking-luggage::before { + content: "\e554"; } + +.fa-up-down::before { + content: "\f338"; } + +.fa-arrows-alt-v::before { + content: "\f338"; } + +.fa-cloud-moon-rain::before { + content: "\f73c"; } + +.fa-calendar::before { + content: "\f133"; } + +.fa-trailer::before { + content: "\e041"; } + +.fa-bahai::before { + content: "\f666"; } + +.fa-haykal::before { + content: "\f666"; } + +.fa-sd-card::before { + content: "\f7c2"; } + +.fa-dragon::before { + content: "\f6d5"; } + +.fa-shoe-prints::before { + content: "\f54b"; } + +.fa-circle-plus::before { + content: "\f055"; } + +.fa-plus-circle::before { + content: "\f055"; } + +.fa-face-grin-tongue-wink::before { + content: "\f58b"; } + +.fa-grin-tongue-wink::before { + content: "\f58b"; } + +.fa-hand-holding::before { + content: "\f4bd"; } + +.fa-plug-circle-exclamation::before { + content: "\e55d"; } + +.fa-link-slash::before { + content: "\f127"; } + +.fa-chain-broken::before { + content: "\f127"; } + +.fa-chain-slash::before { + content: "\f127"; } + +.fa-unlink::before { + content: "\f127"; } + +.fa-clone::before { + content: "\f24d"; } + +.fa-person-walking-arrow-loop-left::before { + content: "\e551"; } + +.fa-arrow-up-z-a::before { + content: "\f882"; } + +.fa-sort-alpha-up-alt::before { + content: "\f882"; } + +.fa-fire-flame-curved::before { + content: "\f7e4"; } + +.fa-fire-alt::before { + content: "\f7e4"; } + +.fa-tornado::before { + content: "\f76f"; } + +.fa-file-circle-plus::before { + content: "\e494"; } + +.fa-book-quran::before { + content: "\f687"; } + +.fa-quran::before { + content: "\f687"; } + +.fa-anchor::before { + content: "\f13d"; } + +.fa-border-all::before { + content: "\f84c"; } + +.fa-face-angry::before { + content: "\f556"; } + +.fa-angry::before { + content: "\f556"; } + +.fa-cookie-bite::before { + content: "\f564"; } + +.fa-arrow-trend-down::before { + content: "\e097"; } + +.fa-rss::before { + content: "\f09e"; } + +.fa-feed::before { + content: "\f09e"; } + +.fa-draw-polygon::before { + content: "\f5ee"; } + +.fa-scale-balanced::before { + content: "\f24e"; } + +.fa-balance-scale::before { + content: "\f24e"; } + +.fa-gauge-simple-high::before { + content: "\f62a"; } + +.fa-tachometer::before { + content: "\f62a"; } + +.fa-tachometer-fast::before { + content: "\f62a"; } + +.fa-shower::before { + content: "\f2cc"; } + +.fa-desktop::before { + content: "\f390"; } + +.fa-desktop-alt::before { + content: "\f390"; } + +.fa-m::before { + content: "\4d"; } + +.fa-table-list::before { + content: "\f00b"; } + +.fa-th-list::before { + content: "\f00b"; } + +.fa-comment-sms::before { + content: "\f7cd"; } + +.fa-sms::before { + content: "\f7cd"; } + +.fa-book::before { + content: "\f02d"; } + +.fa-user-plus::before { + content: "\f234"; } + +.fa-check::before { + content: "\f00c"; } + +.fa-battery-three-quarters::before { + content: "\f241"; } + +.fa-battery-4::before { + content: "\f241"; } + +.fa-house-circle-check::before { + content: "\e509"; } + +.fa-angle-left::before { + content: "\f104"; } + +.fa-diagram-successor::before { + content: "\e47a"; } + +.fa-truck-arrow-right::before { + content: "\e58b"; } + +.fa-arrows-split-up-and-left::before { + content: "\e4bc"; } + +.fa-hand-fist::before { + content: "\f6de"; } + +.fa-fist-raised::before { + content: "\f6de"; } + +.fa-cloud-moon::before { + content: "\f6c3"; } + +.fa-briefcase::before { + content: "\f0b1"; } + +.fa-person-falling::before { + content: "\e546"; } + +.fa-image-portrait::before { + content: "\f3e0"; } + +.fa-portrait::before { + content: "\f3e0"; } + +.fa-user-tag::before { + content: "\f507"; } + +.fa-rug::before { + content: "\e569"; } + +.fa-earth-europe::before { + content: "\f7a2"; } + +.fa-globe-europe::before { + content: "\f7a2"; } + +.fa-cart-flatbed-suitcase::before { + content: "\f59d"; } + +.fa-luggage-cart::before { + content: "\f59d"; } + +.fa-rectangle-xmark::before { + content: "\f410"; } + +.fa-rectangle-times::before { + content: "\f410"; } + +.fa-times-rectangle::before { + content: "\f410"; } + +.fa-window-close::before { + content: "\f410"; } + +.fa-baht-sign::before { + content: "\e0ac"; } + +.fa-book-open::before { + content: "\f518"; } + +.fa-book-journal-whills::before { + content: "\f66a"; } + +.fa-journal-whills::before { + content: "\f66a"; } + +.fa-handcuffs::before { + content: "\e4f8"; } + +.fa-triangle-exclamation::before { + content: "\f071"; } + +.fa-exclamation-triangle::before { + content: "\f071"; } + +.fa-warning::before { + content: "\f071"; } + +.fa-database::before { + content: "\f1c0"; } + +.fa-share::before { + content: "\f064"; } + +.fa-mail-forward::before { + content: "\f064"; } + +.fa-bottle-droplet::before { + content: "\e4c4"; } + +.fa-mask-face::before { + content: "\e1d7"; } + +.fa-hill-rockslide::before { + content: "\e508"; } + +.fa-right-left::before { + content: "\f362"; } + +.fa-exchange-alt::before { + content: "\f362"; } + +.fa-paper-plane::before { + content: "\f1d8"; } + +.fa-road-circle-exclamation::before { + content: "\e565"; } + +.fa-dungeon::before { + content: "\f6d9"; } + +.fa-align-right::before { + content: "\f038"; } + +.fa-money-bill-1-wave::before { + content: "\f53b"; } + +.fa-money-bill-wave-alt::before { + content: "\f53b"; } + +.fa-life-ring::before { + content: "\f1cd"; } + +.fa-hands::before { + content: "\f2a7"; } + +.fa-sign-language::before { + content: "\f2a7"; } + +.fa-signing::before { + content: "\f2a7"; } + +.fa-calendar-day::before { + content: "\f783"; } + +.fa-water-ladder::before { + content: "\f5c5"; } + +.fa-ladder-water::before { + content: "\f5c5"; } + +.fa-swimming-pool::before { + content: "\f5c5"; } + +.fa-arrows-up-down::before { + content: "\f07d"; } + +.fa-arrows-v::before { + content: "\f07d"; } + +.fa-face-grimace::before { + content: "\f57f"; } + +.fa-grimace::before { + content: "\f57f"; } + +.fa-wheelchair-move::before { + content: "\e2ce"; } + +.fa-wheelchair-alt::before { + content: "\e2ce"; } + +.fa-turn-down::before { + content: "\f3be"; } + +.fa-level-down-alt::before { + content: "\f3be"; } + +.fa-person-walking-arrow-right::before { + content: "\e552"; } + +.fa-square-envelope::before { + content: "\f199"; } + +.fa-envelope-square::before { + content: "\f199"; } + +.fa-dice::before { + content: "\f522"; } + +.fa-bowling-ball::before { + content: "\f436"; } + +.fa-brain::before { + content: "\f5dc"; } + +.fa-bandage::before { + content: "\f462"; } + +.fa-band-aid::before { + content: "\f462"; } + +.fa-calendar-minus::before { + content: "\f272"; } + +.fa-circle-xmark::before { + content: "\f057"; } + +.fa-times-circle::before { + content: "\f057"; } + +.fa-xmark-circle::before { + content: "\f057"; } + +.fa-gifts::before { + content: "\f79c"; } + +.fa-hotel::before { + content: "\f594"; } + +.fa-earth-asia::before { + content: "\f57e"; } + +.fa-globe-asia::before { + content: "\f57e"; } + +.fa-id-card-clip::before { + content: "\f47f"; } + +.fa-id-card-alt::before { + content: "\f47f"; } + +.fa-magnifying-glass-plus::before { + content: "\f00e"; } + +.fa-search-plus::before { + content: "\f00e"; } + +.fa-thumbs-up::before { + content: "\f164"; } + +.fa-user-clock::before { + content: "\f4fd"; } + +.fa-hand-dots::before { + content: "\f461"; } + +.fa-allergies::before { + content: "\f461"; } + +.fa-file-invoice::before { + content: "\f570"; } + +.fa-window-minimize::before { + content: "\f2d1"; } + +.fa-mug-saucer::before { + content: "\f0f4"; } + +.fa-coffee::before { + content: "\f0f4"; } + +.fa-brush::before { + content: "\f55d"; } + +.fa-mask::before { + content: "\f6fa"; } + +.fa-magnifying-glass-minus::before { + content: "\f010"; } + +.fa-search-minus::before { + content: "\f010"; } + +.fa-ruler-vertical::before { + content: "\f548"; } + +.fa-user-large::before { + content: "\f406"; } + +.fa-user-alt::before { + content: "\f406"; } + +.fa-train-tram::before { + content: "\e5b4"; } + +.fa-user-nurse::before { + content: "\f82f"; } + +.fa-syringe::before { + content: "\f48e"; } + +.fa-cloud-sun::before { + content: "\f6c4"; } + +.fa-stopwatch-20::before { + content: "\e06f"; } + +.fa-square-full::before { + content: "\f45c"; } + +.fa-magnet::before { + content: "\f076"; } + +.fa-jar::before { + content: "\e516"; } + +.fa-note-sticky::before { + content: "\f249"; } + +.fa-sticky-note::before { + content: "\f249"; } + +.fa-bug-slash::before { + content: "\e490"; } + +.fa-arrow-up-from-water-pump::before { + content: "\e4b6"; } + +.fa-bone::before { + content: "\f5d7"; } + +.fa-user-injured::before { + content: "\f728"; } + +.fa-face-sad-tear::before { + content: "\f5b4"; } + +.fa-sad-tear::before { + content: "\f5b4"; } + +.fa-plane::before { + content: "\f072"; } + +.fa-tent-arrows-down::before { + content: "\e581"; } + +.fa-exclamation::before { + content: "\21"; } + +.fa-arrows-spin::before { + content: "\e4bb"; } + +.fa-print::before { + content: "\f02f"; } + +.fa-turkish-lira-sign::before { + content: "\e2bb"; } + +.fa-try::before { + content: "\e2bb"; } + +.fa-turkish-lira::before { + content: "\e2bb"; } + +.fa-dollar-sign::before { + content: "\24"; } + +.fa-dollar::before { + content: "\24"; } + +.fa-usd::before { + content: "\24"; } + +.fa-x::before { + content: "\58"; } + +.fa-magnifying-glass-dollar::before { + content: "\f688"; } + +.fa-search-dollar::before { + content: "\f688"; } + +.fa-users-gear::before { + content: "\f509"; } + +.fa-users-cog::before { + content: "\f509"; } + +.fa-person-military-pointing::before { + content: "\e54a"; } + +.fa-building-columns::before { + content: "\f19c"; } + +.fa-bank::before { + content: "\f19c"; } + +.fa-institution::before { + content: "\f19c"; } + +.fa-museum::before { + content: "\f19c"; } + +.fa-university::before { + content: "\f19c"; } + +.fa-umbrella::before { + content: "\f0e9"; } + +.fa-trowel::before { + content: "\e589"; } + +.fa-d::before { + content: "\44"; } + +.fa-stapler::before { + content: "\e5af"; } + +.fa-masks-theater::before { + content: "\f630"; } + +.fa-theater-masks::before { + content: "\f630"; } + +.fa-kip-sign::before { + content: "\e1c4"; } + +.fa-hand-point-left::before { + content: "\f0a5"; } + +.fa-handshake-simple::before { + content: "\f4c6"; } + +.fa-handshake-alt::before { + content: "\f4c6"; } + +.fa-jet-fighter::before { + content: "\f0fb"; } + +.fa-fighter-jet::before { + content: "\f0fb"; } + +.fa-square-share-nodes::before { + content: "\f1e1"; } + +.fa-share-alt-square::before { + content: "\f1e1"; } + +.fa-barcode::before { + content: "\f02a"; } + +.fa-plus-minus::before { + content: "\e43c"; } + +.fa-video::before { + content: "\f03d"; } + +.fa-video-camera::before { + content: "\f03d"; } + +.fa-graduation-cap::before { + content: "\f19d"; } + +.fa-mortar-board::before { + content: "\f19d"; } + +.fa-hand-holding-medical::before { + content: "\e05c"; } + +.fa-person-circle-check::before { + content: "\e53e"; } + +.fa-turn-up::before { + content: "\f3bf"; } + +.fa-level-up-alt::before { + content: "\f3bf"; } + +.sr-only, +.fa-sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; } + +.sr-only-focusable:not(:focus), +.fa-sr-only-focusable:not(:focus) { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; } +:root, :host { + --fa-style-family-brands: 'Font Awesome 6 Brands'; + --fa-font-brands: normal 400 1em/1 'Font Awesome 6 Brands'; } + +@font-face { + font-family: 'Font Awesome 6 Brands'; + font-style: normal; + font-weight: 400; + font-display: block; + src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); } + +.fab, +.fa-brands { + font-weight: 400; } + +.fa-monero:before { + content: "\f3d0"; } + +.fa-hooli:before { + content: "\f427"; } + +.fa-yelp:before { + content: "\f1e9"; } + +.fa-cc-visa:before { + content: "\f1f0"; } + +.fa-lastfm:before { + content: "\f202"; } + +.fa-shopware:before { + content: "\f5b5"; } + +.fa-creative-commons-nc:before { + content: "\f4e8"; } + +.fa-aws:before { + content: "\f375"; } + +.fa-redhat:before { + content: "\f7bc"; } + +.fa-yoast:before { + content: "\f2b1"; } + +.fa-cloudflare:before { + content: "\e07d"; } + +.fa-ups:before { + content: "\f7e0"; } + +.fa-pixiv:before { + content: "\e640"; } + +.fa-wpexplorer:before { + content: "\f2de"; } + +.fa-dyalog:before { + content: "\f399"; } + +.fa-bity:before { + content: "\f37a"; } + +.fa-stackpath:before { + content: "\f842"; } + +.fa-buysellads:before { + content: "\f20d"; } + +.fa-first-order:before { + content: "\f2b0"; } + +.fa-modx:before { + content: "\f285"; } + +.fa-guilded:before { + content: "\e07e"; } + +.fa-vnv:before { + content: "\f40b"; } + +.fa-square-js:before { + content: "\f3b9"; } + +.fa-js-square:before { + content: "\f3b9"; } + +.fa-microsoft:before { + content: "\f3ca"; } + +.fa-qq:before { + content: "\f1d6"; } + +.fa-orcid:before { + content: "\f8d2"; } + +.fa-java:before { + content: "\f4e4"; } + +.fa-invision:before { + content: "\f7b0"; } + +.fa-creative-commons-pd-alt:before { + content: "\f4ed"; } + +.fa-centercode:before { + content: "\f380"; } + +.fa-glide-g:before { + content: "\f2a6"; } + +.fa-drupal:before { + content: "\f1a9"; } + +.fa-jxl:before { + content: "\e67b"; } + +.fa-hire-a-helper:before { + content: "\f3b0"; } + +.fa-creative-commons-by:before { + content: "\f4e7"; } + +.fa-unity:before { + content: "\e049"; } + +.fa-whmcs:before { + content: "\f40d"; } + +.fa-rocketchat:before { + content: "\f3e8"; } + +.fa-vk:before { + content: "\f189"; } + +.fa-untappd:before { + content: "\f405"; } + +.fa-mailchimp:before { + content: "\f59e"; } + +.fa-css3-alt:before { + content: "\f38b"; } + +.fa-square-reddit:before { + content: "\f1a2"; } + +.fa-reddit-square:before { + content: "\f1a2"; } + +.fa-vimeo-v:before { + content: "\f27d"; } + +.fa-contao:before { + content: "\f26d"; } + +.fa-square-font-awesome:before { + content: "\e5ad"; } + +.fa-deskpro:before { + content: "\f38f"; } + +.fa-brave:before { + content: "\e63c"; } + +.fa-sistrix:before { + content: "\f3ee"; } + +.fa-square-instagram:before { + content: "\e055"; } + +.fa-instagram-square:before { + content: "\e055"; } + +.fa-battle-net:before { + content: "\f835"; } + +.fa-the-red-yeti:before { + content: "\f69d"; } + +.fa-square-hacker-news:before { + content: "\f3af"; } + +.fa-hacker-news-square:before { + content: "\f3af"; } + +.fa-edge:before { + content: "\f282"; } + +.fa-threads:before { + content: "\e618"; } + +.fa-napster:before { + content: "\f3d2"; } + +.fa-square-snapchat:before { + content: "\f2ad"; } + +.fa-snapchat-square:before { + content: "\f2ad"; } + +.fa-google-plus-g:before { + content: "\f0d5"; } + +.fa-artstation:before { + content: "\f77a"; } + +.fa-markdown:before { + content: "\f60f"; } + +.fa-sourcetree:before { + content: "\f7d3"; } + +.fa-google-plus:before { + content: "\f2b3"; } + +.fa-diaspora:before { + content: "\f791"; } + +.fa-foursquare:before { + content: "\f180"; } + +.fa-stack-overflow:before { + content: "\f16c"; } + +.fa-github-alt:before { + content: "\f113"; } + +.fa-phoenix-squadron:before { + content: "\f511"; } + +.fa-pagelines:before { + content: "\f18c"; } + +.fa-algolia:before { + content: "\f36c"; } + +.fa-red-river:before { + content: "\f3e3"; } + +.fa-creative-commons-sa:before { + content: "\f4ef"; } + +.fa-safari:before { + content: "\f267"; } + +.fa-google:before { + content: "\f1a0"; } + +.fa-square-font-awesome-stroke:before { + content: "\f35c"; } + +.fa-font-awesome-alt:before { + content: "\f35c"; } + +.fa-atlassian:before { + content: "\f77b"; } + +.fa-linkedin-in:before { + content: "\f0e1"; } + +.fa-digital-ocean:before { + content: "\f391"; } + +.fa-nimblr:before { + content: "\f5a8"; } + +.fa-chromecast:before { + content: "\f838"; } + +.fa-evernote:before { + content: "\f839"; } + +.fa-hacker-news:before { + content: "\f1d4"; } + +.fa-creative-commons-sampling:before { + content: "\f4f0"; } + +.fa-adversal:before { + content: "\f36a"; } + +.fa-creative-commons:before { + content: "\f25e"; } + +.fa-watchman-monitoring:before { + content: "\e087"; } + +.fa-fonticons:before { + content: "\f280"; } + +.fa-weixin:before { + content: "\f1d7"; } + +.fa-shirtsinbulk:before { + content: "\f214"; } + +.fa-codepen:before { + content: "\f1cb"; } + +.fa-git-alt:before { + content: "\f841"; } + +.fa-lyft:before { + content: "\f3c3"; } + +.fa-rev:before { + content: "\f5b2"; } + +.fa-windows:before { + content: "\f17a"; } + +.fa-wizards-of-the-coast:before { + content: "\f730"; } + +.fa-square-viadeo:before { + content: "\f2aa"; } + +.fa-viadeo-square:before { + content: "\f2aa"; } + +.fa-meetup:before { + content: "\f2e0"; } + +.fa-centos:before { + content: "\f789"; } + +.fa-adn:before { + content: "\f170"; } + +.fa-cloudsmith:before { + content: "\f384"; } + +.fa-opensuse:before { + content: "\e62b"; } + +.fa-pied-piper-alt:before { + content: "\f1a8"; } + +.fa-square-dribbble:before { + content: "\f397"; } + +.fa-dribbble-square:before { + content: "\f397"; } + +.fa-codiepie:before { + content: "\f284"; } + +.fa-node:before { + content: "\f419"; } + +.fa-mix:before { + content: "\f3cb"; } + +.fa-steam:before { + content: "\f1b6"; } + +.fa-cc-apple-pay:before { + content: "\f416"; } + +.fa-scribd:before { + content: "\f28a"; } + +.fa-debian:before { + content: "\e60b"; } + +.fa-openid:before { + content: "\f19b"; } + +.fa-instalod:before { + content: "\e081"; } + +.fa-expeditedssl:before { + content: "\f23e"; } + +.fa-sellcast:before { + content: "\f2da"; } + +.fa-square-twitter:before { + content: "\f081"; } + +.fa-twitter-square:before { + content: "\f081"; } + +.fa-r-project:before { + content: "\f4f7"; } + +.fa-delicious:before { + content: "\f1a5"; } + +.fa-freebsd:before { + content: "\f3a4"; } + +.fa-vuejs:before { + content: "\f41f"; } + +.fa-accusoft:before { + content: "\f369"; } + +.fa-ioxhost:before { + content: "\f208"; } + +.fa-fonticons-fi:before { + content: "\f3a2"; } + +.fa-app-store:before { + content: "\f36f"; } + +.fa-cc-mastercard:before { + content: "\f1f1"; } + +.fa-itunes-note:before { + content: "\f3b5"; } + +.fa-golang:before { + content: "\e40f"; } + +.fa-kickstarter:before { + content: "\f3bb"; } + +.fa-square-kickstarter:before { + content: "\f3bb"; } + +.fa-grav:before { + content: "\f2d6"; } + +.fa-weibo:before { + content: "\f18a"; } + +.fa-uncharted:before { + content: "\e084"; } + +.fa-firstdraft:before { + content: "\f3a1"; } + +.fa-square-youtube:before { + content: "\f431"; } + +.fa-youtube-square:before { + content: "\f431"; } + +.fa-wikipedia-w:before { + content: "\f266"; } + +.fa-wpressr:before { + content: "\f3e4"; } + +.fa-rendact:before { + content: "\f3e4"; } + +.fa-angellist:before { + content: "\f209"; } + +.fa-galactic-republic:before { + content: "\f50c"; } + +.fa-nfc-directional:before { + content: "\e530"; } + +.fa-skype:before { + content: "\f17e"; } + +.fa-joget:before { + content: "\f3b7"; } + +.fa-fedora:before { + content: "\f798"; } + +.fa-stripe-s:before { + content: "\f42a"; } + +.fa-meta:before { + content: "\e49b"; } + +.fa-laravel:before { + content: "\f3bd"; } + +.fa-hotjar:before { + content: "\f3b1"; } + +.fa-bluetooth-b:before { + content: "\f294"; } + +.fa-square-letterboxd:before { + content: "\e62e"; } + +.fa-sticker-mule:before { + content: "\f3f7"; } + +.fa-creative-commons-zero:before { + content: "\f4f3"; } + +.fa-hips:before { + content: "\f452"; } + +.fa-behance:before { + content: "\f1b4"; } + +.fa-reddit:before { + content: "\f1a1"; } + +.fa-discord:before { + content: "\f392"; } + +.fa-chrome:before { + content: "\f268"; } + +.fa-app-store-ios:before { + content: "\f370"; } + +.fa-cc-discover:before { + content: "\f1f2"; } + +.fa-wpbeginner:before { + content: "\f297"; } + +.fa-confluence:before { + content: "\f78d"; } + +.fa-shoelace:before { + content: "\e60c"; } + +.fa-mdb:before { + content: "\f8ca"; } + +.fa-dochub:before { + content: "\f394"; } + +.fa-accessible-icon:before { + content: "\f368"; } + +.fa-ebay:before { + content: "\f4f4"; } + +.fa-amazon:before { + content: "\f270"; } + +.fa-unsplash:before { + content: "\e07c"; } + +.fa-yarn:before { + content: "\f7e3"; } + +.fa-square-steam:before { + content: "\f1b7"; } + +.fa-steam-square:before { + content: "\f1b7"; } + +.fa-500px:before { + content: "\f26e"; } + +.fa-square-vimeo:before { + content: "\f194"; } + +.fa-vimeo-square:before { + content: "\f194"; } + +.fa-asymmetrik:before { + content: "\f372"; } + +.fa-font-awesome:before { + content: "\f2b4"; } + +.fa-font-awesome-flag:before { + content: "\f2b4"; } + +.fa-font-awesome-logo-full:before { + content: "\f2b4"; } + +.fa-gratipay:before { + content: "\f184"; } + +.fa-apple:before { + content: "\f179"; } + +.fa-hive:before { + content: "\e07f"; } + +.fa-gitkraken:before { + content: "\f3a6"; } + +.fa-keybase:before { + content: "\f4f5"; } + +.fa-apple-pay:before { + content: "\f415"; } + +.fa-padlet:before { + content: "\e4a0"; } + +.fa-amazon-pay:before { + content: "\f42c"; } + +.fa-square-github:before { + content: "\f092"; } + +.fa-github-square:before { + content: "\f092"; } + +.fa-stumbleupon:before { + content: "\f1a4"; } + +.fa-fedex:before { + content: "\f797"; } + +.fa-phoenix-framework:before { + content: "\f3dc"; } + +.fa-shopify:before { + content: "\e057"; } + +.fa-neos:before { + content: "\f612"; } + +.fa-square-threads:before { + content: "\e619"; } + +.fa-hackerrank:before { + content: "\f5f7"; } + +.fa-researchgate:before { + content: "\f4f8"; } + +.fa-swift:before { + content: "\f8e1"; } + +.fa-angular:before { + content: "\f420"; } + +.fa-speakap:before { + content: "\f3f3"; } + +.fa-angrycreative:before { + content: "\f36e"; } + +.fa-y-combinator:before { + content: "\f23b"; } + +.fa-empire:before { + content: "\f1d1"; } + +.fa-envira:before { + content: "\f299"; } + +.fa-google-scholar:before { + content: "\e63b"; } + +.fa-square-gitlab:before { + content: "\e5ae"; } + +.fa-gitlab-square:before { + content: "\e5ae"; } + +.fa-studiovinari:before { + content: "\f3f8"; } + +.fa-pied-piper:before { + content: "\f2ae"; } + +.fa-wordpress:before { + content: "\f19a"; } + +.fa-product-hunt:before { + content: "\f288"; } + +.fa-firefox:before { + content: "\f269"; } + +.fa-linode:before { + content: "\f2b8"; } + +.fa-goodreads:before { + content: "\f3a8"; } + +.fa-square-odnoklassniki:before { + content: "\f264"; } + +.fa-odnoklassniki-square:before { + content: "\f264"; } + +.fa-jsfiddle:before { + content: "\f1cc"; } + +.fa-sith:before { + content: "\f512"; } + +.fa-themeisle:before { + content: "\f2b2"; } + +.fa-page4:before { + content: "\f3d7"; } + +.fa-hashnode:before { + content: "\e499"; } + +.fa-react:before { + content: "\f41b"; } + +.fa-cc-paypal:before { + content: "\f1f4"; } + +.fa-squarespace:before { + content: "\f5be"; } + +.fa-cc-stripe:before { + content: "\f1f5"; } + +.fa-creative-commons-share:before { + content: "\f4f2"; } + +.fa-bitcoin:before { + content: "\f379"; } + +.fa-keycdn:before { + content: "\f3ba"; } + +.fa-opera:before { + content: "\f26a"; } + +.fa-itch-io:before { + content: "\f83a"; } + +.fa-umbraco:before { + content: "\f8e8"; } + +.fa-galactic-senate:before { + content: "\f50d"; } + +.fa-ubuntu:before { + content: "\f7df"; } + +.fa-draft2digital:before { + content: "\f396"; } + +.fa-stripe:before { + content: "\f429"; } + +.fa-houzz:before { + content: "\f27c"; } + +.fa-gg:before { + content: "\f260"; } + +.fa-dhl:before { + content: "\f790"; } + +.fa-square-pinterest:before { + content: "\f0d3"; } + +.fa-pinterest-square:before { + content: "\f0d3"; } + +.fa-xing:before { + content: "\f168"; } + +.fa-blackberry:before { + content: "\f37b"; } + +.fa-creative-commons-pd:before { + content: "\f4ec"; } + +.fa-playstation:before { + content: "\f3df"; } + +.fa-quinscape:before { + content: "\f459"; } + +.fa-less:before { + content: "\f41d"; } + +.fa-blogger-b:before { + content: "\f37d"; } + +.fa-opencart:before { + content: "\f23d"; } + +.fa-vine:before { + content: "\f1ca"; } + +.fa-signal-messenger:before { + content: "\e663"; } + +.fa-paypal:before { + content: "\f1ed"; } + +.fa-gitlab:before { + content: "\f296"; } + +.fa-typo3:before { + content: "\f42b"; } + +.fa-reddit-alien:before { + content: "\f281"; } + +.fa-yahoo:before { + content: "\f19e"; } + +.fa-dailymotion:before { + content: "\e052"; } + +.fa-affiliatetheme:before { + content: "\f36b"; } + +.fa-pied-piper-pp:before { + content: "\f1a7"; } + +.fa-bootstrap:before { + content: "\f836"; } + +.fa-odnoklassniki:before { + content: "\f263"; } + +.fa-nfc-symbol:before { + content: "\e531"; } + +.fa-mintbit:before { + content: "\e62f"; } + +.fa-ethereum:before { + content: "\f42e"; } + +.fa-speaker-deck:before { + content: "\f83c"; } + +.fa-creative-commons-nc-eu:before { + content: "\f4e9"; } + +.fa-patreon:before { + content: "\f3d9"; } + +.fa-avianex:before { + content: "\f374"; } + +.fa-ello:before { + content: "\f5f1"; } + +.fa-gofore:before { + content: "\f3a7"; } + +.fa-bimobject:before { + content: "\f378"; } + +.fa-brave-reverse:before { + content: "\e63d"; } + +.fa-facebook-f:before { + content: "\f39e"; } + +.fa-square-google-plus:before { + content: "\f0d4"; } + +.fa-google-plus-square:before { + content: "\f0d4"; } + +.fa-web-awesome:before { + content: "\e682"; } + +.fa-mandalorian:before { + content: "\f50f"; } + +.fa-first-order-alt:before { + content: "\f50a"; } + +.fa-osi:before { + content: "\f41a"; } + +.fa-google-wallet:before { + content: "\f1ee"; } + +.fa-d-and-d-beyond:before { + content: "\f6ca"; } + +.fa-periscope:before { + content: "\f3da"; } + +.fa-fulcrum:before { + content: "\f50b"; } + +.fa-cloudscale:before { + content: "\f383"; } + +.fa-forumbee:before { + content: "\f211"; } + +.fa-mizuni:before { + content: "\f3cc"; } + +.fa-schlix:before { + content: "\f3ea"; } + +.fa-square-xing:before { + content: "\f169"; } + +.fa-xing-square:before { + content: "\f169"; } + +.fa-bandcamp:before { + content: "\f2d5"; } + +.fa-wpforms:before { + content: "\f298"; } + +.fa-cloudversify:before { + content: "\f385"; } + +.fa-usps:before { + content: "\f7e1"; } + +.fa-megaport:before { + content: "\f5a3"; } + +.fa-magento:before { + content: "\f3c4"; } + +.fa-spotify:before { + content: "\f1bc"; } + +.fa-optin-monster:before { + content: "\f23c"; } + +.fa-fly:before { + content: "\f417"; } + +.fa-aviato:before { + content: "\f421"; } + +.fa-itunes:before { + content: "\f3b4"; } + +.fa-cuttlefish:before { + content: "\f38c"; } + +.fa-blogger:before { + content: "\f37c"; } + +.fa-flickr:before { + content: "\f16e"; } + +.fa-viber:before { + content: "\f409"; } + +.fa-soundcloud:before { + content: "\f1be"; } + +.fa-digg:before { + content: "\f1a6"; } + +.fa-tencent-weibo:before { + content: "\f1d5"; } + +.fa-letterboxd:before { + content: "\e62d"; } + +.fa-symfony:before { + content: "\f83d"; } + +.fa-maxcdn:before { + content: "\f136"; } + +.fa-etsy:before { + content: "\f2d7"; } + +.fa-facebook-messenger:before { + content: "\f39f"; } + +.fa-audible:before { + content: "\f373"; } + +.fa-think-peaks:before { + content: "\f731"; } + +.fa-bilibili:before { + content: "\e3d9"; } + +.fa-erlang:before { + content: "\f39d"; } + +.fa-x-twitter:before { + content: "\e61b"; } + +.fa-cotton-bureau:before { + content: "\f89e"; } + +.fa-dashcube:before { + content: "\f210"; } + +.fa-42-group:before { + content: "\e080"; } + +.fa-innosoft:before { + content: "\e080"; } + +.fa-stack-exchange:before { + content: "\f18d"; } + +.fa-elementor:before { + content: "\f430"; } + +.fa-square-pied-piper:before { + content: "\e01e"; } + +.fa-pied-piper-square:before { + content: "\e01e"; } + +.fa-creative-commons-nd:before { + content: "\f4eb"; } + +.fa-palfed:before { + content: "\f3d8"; } + +.fa-superpowers:before { + content: "\f2dd"; } + +.fa-resolving:before { + content: "\f3e7"; } + +.fa-xbox:before { + content: "\f412"; } + +.fa-square-web-awesome-stroke:before { + content: "\e684"; } + +.fa-searchengin:before { + content: "\f3eb"; } + +.fa-tiktok:before { + content: "\e07b"; } + +.fa-square-facebook:before { + content: "\f082"; } + +.fa-facebook-square:before { + content: "\f082"; } + +.fa-renren:before { + content: "\f18b"; } + +.fa-linux:before { + content: "\f17c"; } + +.fa-glide:before { + content: "\f2a5"; } + +.fa-linkedin:before { + content: "\f08c"; } + +.fa-hubspot:before { + content: "\f3b2"; } + +.fa-deploydog:before { + content: "\f38e"; } + +.fa-twitch:before { + content: "\f1e8"; } + +.fa-ravelry:before { + content: "\f2d9"; } + +.fa-mixer:before { + content: "\e056"; } + +.fa-square-lastfm:before { + content: "\f203"; } + +.fa-lastfm-square:before { + content: "\f203"; } + +.fa-vimeo:before { + content: "\f40a"; } + +.fa-mendeley:before { + content: "\f7b3"; } + +.fa-uniregistry:before { + content: "\f404"; } + +.fa-figma:before { + content: "\f799"; } + +.fa-creative-commons-remix:before { + content: "\f4ee"; } + +.fa-cc-amazon-pay:before { + content: "\f42d"; } + +.fa-dropbox:before { + content: "\f16b"; } + +.fa-instagram:before { + content: "\f16d"; } + +.fa-cmplid:before { + content: "\e360"; } + +.fa-upwork:before { + content: "\e641"; } + +.fa-facebook:before { + content: "\f09a"; } + +.fa-gripfire:before { + content: "\f3ac"; } + +.fa-jedi-order:before { + content: "\f50e"; } + +.fa-uikit:before { + content: "\f403"; } + +.fa-fort-awesome-alt:before { + content: "\f3a3"; } + +.fa-phabricator:before { + content: "\f3db"; } + +.fa-ussunnah:before { + content: "\f407"; } + +.fa-earlybirds:before { + content: "\f39a"; } + +.fa-trade-federation:before { + content: "\f513"; } + +.fa-autoprefixer:before { + content: "\f41c"; } + +.fa-whatsapp:before { + content: "\f232"; } + +.fa-square-upwork:before { + content: "\e67c"; } + +.fa-slideshare:before { + content: "\f1e7"; } + +.fa-google-play:before { + content: "\f3ab"; } + +.fa-viadeo:before { + content: "\f2a9"; } + +.fa-line:before { + content: "\f3c0"; } + +.fa-google-drive:before { + content: "\f3aa"; } + +.fa-servicestack:before { + content: "\f3ec"; } + +.fa-simplybuilt:before { + content: "\f215"; } + +.fa-bitbucket:before { + content: "\f171"; } + +.fa-imdb:before { + content: "\f2d8"; } + +.fa-deezer:before { + content: "\e077"; } + +.fa-raspberry-pi:before { + content: "\f7bb"; } + +.fa-jira:before { + content: "\f7b1"; } + +.fa-docker:before { + content: "\f395"; } + +.fa-screenpal:before { + content: "\e570"; } + +.fa-bluetooth:before { + content: "\f293"; } + +.fa-gitter:before { + content: "\f426"; } + +.fa-d-and-d:before { + content: "\f38d"; } + +.fa-microblog:before { + content: "\e01a"; } + +.fa-cc-diners-club:before { + content: "\f24c"; } + +.fa-gg-circle:before { + content: "\f261"; } + +.fa-pied-piper-hat:before { + content: "\f4e5"; } + +.fa-kickstarter-k:before { + content: "\f3bc"; } + +.fa-yandex:before { + content: "\f413"; } + +.fa-readme:before { + content: "\f4d5"; } + +.fa-html5:before { + content: "\f13b"; } + +.fa-sellsy:before { + content: "\f213"; } + +.fa-square-web-awesome:before { + content: "\e683"; } + +.fa-sass:before { + content: "\f41e"; } + +.fa-wirsindhandwerk:before { + content: "\e2d0"; } + +.fa-wsh:before { + content: "\e2d0"; } + +.fa-buromobelexperte:before { + content: "\f37f"; } + +.fa-salesforce:before { + content: "\f83b"; } + +.fa-octopus-deploy:before { + content: "\e082"; } + +.fa-medapps:before { + content: "\f3c6"; } + +.fa-ns8:before { + content: "\f3d5"; } + +.fa-pinterest-p:before { + content: "\f231"; } + +.fa-apper:before { + content: "\f371"; } + +.fa-fort-awesome:before { + content: "\f286"; } + +.fa-waze:before { + content: "\f83f"; } + +.fa-bluesky:before { + content: "\e671"; } + +.fa-cc-jcb:before { + content: "\f24b"; } + +.fa-snapchat:before { + content: "\f2ab"; } + +.fa-snapchat-ghost:before { + content: "\f2ab"; } + +.fa-fantasy-flight-games:before { + content: "\f6dc"; } + +.fa-rust:before { + content: "\e07a"; } + +.fa-wix:before { + content: "\f5cf"; } + +.fa-square-behance:before { + content: "\f1b5"; } + +.fa-behance-square:before { + content: "\f1b5"; } + +.fa-supple:before { + content: "\f3f9"; } + +.fa-webflow:before { + content: "\e65c"; } + +.fa-rebel:before { + content: "\f1d0"; } + +.fa-css3:before { + content: "\f13c"; } + +.fa-staylinked:before { + content: "\f3f5"; } + +.fa-kaggle:before { + content: "\f5fa"; } + +.fa-space-awesome:before { + content: "\e5ac"; } + +.fa-deviantart:before { + content: "\f1bd"; } + +.fa-cpanel:before { + content: "\f388"; } + +.fa-goodreads-g:before { + content: "\f3a9"; } + +.fa-square-git:before { + content: "\f1d2"; } + +.fa-git-square:before { + content: "\f1d2"; } + +.fa-square-tumblr:before { + content: "\f174"; } + +.fa-tumblr-square:before { + content: "\f174"; } + +.fa-trello:before { + content: "\f181"; } + +.fa-creative-commons-nc-jp:before { + content: "\f4ea"; } + +.fa-get-pocket:before { + content: "\f265"; } + +.fa-perbyte:before { + content: "\e083"; } + +.fa-grunt:before { + content: "\f3ad"; } + +.fa-weebly:before { + content: "\f5cc"; } + +.fa-connectdevelop:before { + content: "\f20e"; } + +.fa-leanpub:before { + content: "\f212"; } + +.fa-black-tie:before { + content: "\f27e"; } + +.fa-themeco:before { + content: "\f5c6"; } + +.fa-python:before { + content: "\f3e2"; } + +.fa-android:before { + content: "\f17b"; } + +.fa-bots:before { + content: "\e340"; } + +.fa-free-code-camp:before { + content: "\f2c5"; } + +.fa-hornbill:before { + content: "\f592"; } + +.fa-js:before { + content: "\f3b8"; } + +.fa-ideal:before { + content: "\e013"; } + +.fa-git:before { + content: "\f1d3"; } + +.fa-dev:before { + content: "\f6cc"; } + +.fa-sketch:before { + content: "\f7c6"; } + +.fa-yandex-international:before { + content: "\f414"; } + +.fa-cc-amex:before { + content: "\f1f3"; } + +.fa-uber:before { + content: "\f402"; } + +.fa-github:before { + content: "\f09b"; } + +.fa-php:before { + content: "\f457"; } + +.fa-alipay:before { + content: "\f642"; } + +.fa-youtube:before { + content: "\f167"; } + +.fa-skyatlas:before { + content: "\f216"; } + +.fa-firefox-browser:before { + content: "\e007"; } + +.fa-replyd:before { + content: "\f3e6"; } + +.fa-suse:before { + content: "\f7d6"; } + +.fa-jenkins:before { + content: "\f3b6"; } + +.fa-twitter:before { + content: "\f099"; } + +.fa-rockrms:before { + content: "\f3e9"; } + +.fa-pinterest:before { + content: "\f0d2"; } + +.fa-buffer:before { + content: "\f837"; } + +.fa-npm:before { + content: "\f3d4"; } + +.fa-yammer:before { + content: "\f840"; } + +.fa-btc:before { + content: "\f15a"; } + +.fa-dribbble:before { + content: "\f17d"; } + +.fa-stumbleupon-circle:before { + content: "\f1a3"; } + +.fa-internet-explorer:before { + content: "\f26b"; } + +.fa-stubber:before { + content: "\e5c7"; } + +.fa-telegram:before { + content: "\f2c6"; } + +.fa-telegram-plane:before { + content: "\f2c6"; } + +.fa-old-republic:before { + content: "\f510"; } + +.fa-odysee:before { + content: "\e5c6"; } + +.fa-square-whatsapp:before { + content: "\f40c"; } + +.fa-whatsapp-square:before { + content: "\f40c"; } + +.fa-node-js:before { + content: "\f3d3"; } + +.fa-edge-legacy:before { + content: "\e078"; } + +.fa-slack:before { + content: "\f198"; } + +.fa-slack-hash:before { + content: "\f198"; } + +.fa-medrt:before { + content: "\f3c8"; } + +.fa-usb:before { + content: "\f287"; } + +.fa-tumblr:before { + content: "\f173"; } + +.fa-vaadin:before { + content: "\f408"; } + +.fa-quora:before { + content: "\f2c4"; } + +.fa-square-x-twitter:before { + content: "\e61a"; } + +.fa-reacteurope:before { + content: "\f75d"; } + +.fa-medium:before { + content: "\f23a"; } + +.fa-medium-m:before { + content: "\f23a"; } + +.fa-amilia:before { + content: "\f36d"; } + +.fa-mixcloud:before { + content: "\f289"; } + +.fa-flipboard:before { + content: "\f44d"; } + +.fa-viacoin:before { + content: "\f237"; } + +.fa-critical-role:before { + content: "\f6c9"; } + +.fa-sitrox:before { + content: "\e44a"; } + +.fa-discourse:before { + content: "\f393"; } + +.fa-joomla:before { + content: "\f1aa"; } + +.fa-mastodon:before { + content: "\f4f6"; } + +.fa-airbnb:before { + content: "\f834"; } + +.fa-wolf-pack-battalion:before { + content: "\f514"; } + +.fa-buy-n-large:before { + content: "\f8a6"; } + +.fa-gulp:before { + content: "\f3ae"; } + +.fa-creative-commons-sampling-plus:before { + content: "\f4f1"; } + +.fa-strava:before { + content: "\f428"; } + +.fa-ember:before { + content: "\f423"; } + +.fa-canadian-maple-leaf:before { + content: "\f785"; } + +.fa-teamspeak:before { + content: "\f4f9"; } + +.fa-pushed:before { + content: "\f3e1"; } + +.fa-wordpress-simple:before { + content: "\f411"; } + +.fa-nutritionix:before { + content: "\f3d6"; } + +.fa-wodu:before { + content: "\e088"; } + +.fa-google-pay:before { + content: "\e079"; } + +.fa-intercom:before { + content: "\f7af"; } + +.fa-zhihu:before { + content: "\f63f"; } + +.fa-korvue:before { + content: "\f42f"; } + +.fa-pix:before { + content: "\e43a"; } + +.fa-steam-symbol:before { + content: "\f3f6"; } +:root, :host { + --fa-style-family-classic: 'Font Awesome 6 Free'; + --fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free'; } + +@font-face { + font-family: 'Font Awesome 6 Free'; + font-style: normal; + font-weight: 400; + font-display: block; + src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); } + +.far, +.fa-regular { + font-weight: 400; } +:root, :host { + --fa-style-family-classic: 'Font Awesome 6 Free'; + --fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free'; } + +@font-face { + font-family: 'Font Awesome 6 Free'; + font-style: normal; + font-weight: 900; + font-display: block; + src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); } + +.fas, +.fa-solid { + font-weight: 900; } +@font-face { + font-family: 'Font Awesome 5 Brands'; + font-display: block; + font-weight: 400; + src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); } + +@font-face { + font-family: 'Font Awesome 5 Free'; + font-display: block; + font-weight: 900; + src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); } + +@font-face { + font-family: 'Font Awesome 5 Free'; + font-display: block; + font-weight: 400; + src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); } +@font-face { + font-family: 'FontAwesome'; + font-display: block; + src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); } + +@font-face { + font-family: 'FontAwesome'; + font-display: block; + src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); } + +@font-face { + font-family: 'FontAwesome'; + font-display: block; + src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); } + +@font-face { + font-family: 'FontAwesome'; + font-display: block; + src: url("../webfonts/fa-v4compatibility.woff2") format("woff2"), url("../webfonts/fa-v4compatibility.ttf") format("truetype"); } diff --git a/docs/deps/font-awesome-6.5.2/css/all.min.css b/docs/deps/font-awesome-6.5.2/css/all.min.css new file mode 100644 index 0000000..269bcee --- /dev/null +++ b/docs/deps/font-awesome-6.5.2/css/all.min.css @@ -0,0 +1,9 @@ +/*! + * Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +.fa{font-family:var(--fa-style-family,"Font Awesome 6 Free");font-weight:var(--fa-style,900)}.fa,.fa-brands,.fa-classic,.fa-regular,.fa-sharp,.fa-solid,.fab,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:var(--fa-display,inline-block);font-style:normal;font-variant:normal;line-height:1;text-rendering:auto}.fa-classic,.fa-regular,.fa-solid,.far,.fas{font-family:"Font Awesome 6 Free"}.fa-brands,.fab{font-family:"Font Awesome 6 Brands"}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-2xs{font-size:.625em;line-height:.1em;vertical-align:.225em}.fa-xs{font-size:.75em;line-height:.08333em;vertical-align:.125em}.fa-sm{font-size:.875em;line-height:.07143em;vertical-align:.05357em}.fa-lg{font-size:1.25em;line-height:.05em;vertical-align:-.075em}.fa-xl{font-size:1.5em;line-height:.04167em;vertical-align:-.125em}.fa-2xl{font-size:2em;line-height:.03125em;vertical-align:-.1875em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:var(--fa-li-margin,2.5em);padding-left:0}.fa-ul>li{position:relative}.fa-li{left:calc(var(--fa-li-width, 2em)*-1);position:absolute;text-align:center;width:var(--fa-li-width,2em);line-height:inherit}.fa-border{border-radius:var(--fa-border-radius,.1em);border:var(--fa-border-width,.08em) var(--fa-border-style,solid) var(--fa-border-color,#eee);padding:var(--fa-border-padding,.2em .25em .15em)}.fa-pull-left{float:left;margin-right:var(--fa-pull-margin,.3em)}.fa-pull-right{float:right;margin-left:var(--fa-pull-margin,.3em)}.fa-beat{-webkit-animation-name:fa-beat;animation-name:fa-beat;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,ease-in-out);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-bounce{-webkit-animation-name:fa-bounce;animation-name:fa-bounce;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1))}.fa-fade{-webkit-animation-name:fa-fade;animation-name:fa-fade;-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-beat-fade,.fa-fade{-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s)}.fa-beat-fade{-webkit-animation-name:fa-beat-fade;animation-name:fa-beat-fade;-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-flip{-webkit-animation-name:fa-flip;animation-name:fa-flip;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,ease-in-out);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-shake{-webkit-animation-name:fa-shake;animation-name:fa-shake;-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,linear);animation-timing-function:var(--fa-animation-timing,linear)}.fa-shake,.fa-spin{-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal)}.fa-spin{-webkit-animation-name:fa-spin;animation-name:fa-spin;-webkit-animation-duration:var(--fa-animation-duration,2s);animation-duration:var(--fa-animation-duration,2s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,linear);animation-timing-function:var(--fa-animation-timing,linear)}.fa-spin-reverse{--fa-animation-direction:reverse}.fa-pulse,.fa-spin-pulse{-webkit-animation-name:fa-spin;animation-name:fa-spin;-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,steps(8));animation-timing-function:var(--fa-animation-timing,steps(8))}@media (prefers-reduced-motion:reduce){.fa-beat,.fa-beat-fade,.fa-bounce,.fa-fade,.fa-flip,.fa-pulse,.fa-shake,.fa-spin,.fa-spin-pulse{-webkit-animation-delay:-1ms;animation-delay:-1ms;-webkit-animation-duration:1ms;animation-duration:1ms;-webkit-animation-iteration-count:1;animation-iteration-count:1;-webkit-transition-delay:0s;transition-delay:0s;-webkit-transition-duration:0s;transition-duration:0s}}@-webkit-keyframes fa-beat{0%,90%{-webkit-transform:scale(1);transform:scale(1)}45%{-webkit-transform:scale(var(--fa-beat-scale,1.25));transform:scale(var(--fa-beat-scale,1.25))}}@keyframes fa-beat{0%,90%{-webkit-transform:scale(1);transform:scale(1)}45%{-webkit-transform:scale(var(--fa-beat-scale,1.25));transform:scale(var(--fa-beat-scale,1.25))}}@-webkit-keyframes fa-bounce{0%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}10%{-webkit-transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0);transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{-webkit-transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em));transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{-webkit-transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0);transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{-webkit-transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em));transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}to{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}}@keyframes fa-bounce{0%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}10%{-webkit-transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0);transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{-webkit-transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em));transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{-webkit-transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0);transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{-webkit-transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em));transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}to{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}}@-webkit-keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@-webkit-keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);-webkit-transform:scale(1);transform:scale(1)}50%{opacity:1;-webkit-transform:scale(var(--fa-beat-fade-scale,1.125));transform:scale(var(--fa-beat-fade-scale,1.125))}}@keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);-webkit-transform:scale(1);transform:scale(1)}50%{opacity:1;-webkit-transform:scale(var(--fa-beat-fade-scale,1.125));transform:scale(var(--fa-beat-fade-scale,1.125))}}@-webkit-keyframes fa-flip{50%{-webkit-transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg));transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@keyframes fa-flip{50%{-webkit-transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg));transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@-webkit-keyframes fa-shake{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}4%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}8%,24%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}12%,28%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}20%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}32%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}36%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}40%,to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@keyframes fa-shake{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}4%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}8%,24%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}12%,28%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}20%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}32%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}36%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}40%,to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}.fa-rotate-by{-webkit-transform:rotate(var(--fa-rotate-angle,0));transform:rotate(var(--fa-rotate-angle,0))}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%;z-index:var(--fa-stack-z-index,auto)}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:var(--fa-inverse,#fff)} + +.fa-0:before{content:"\30"}.fa-1:before{content:"\31"}.fa-2:before{content:"\32"}.fa-3:before{content:"\33"}.fa-4:before{content:"\34"}.fa-5:before{content:"\35"}.fa-6:before{content:"\36"}.fa-7:before{content:"\37"}.fa-8:before{content:"\38"}.fa-9:before{content:"\39"}.fa-fill-drip:before{content:"\f576"}.fa-arrows-to-circle:before{content:"\e4bd"}.fa-chevron-circle-right:before,.fa-circle-chevron-right:before{content:"\f138"}.fa-at:before{content:"\40"}.fa-trash-alt:before,.fa-trash-can:before{content:"\f2ed"}.fa-text-height:before{content:"\f034"}.fa-user-times:before,.fa-user-xmark:before{content:"\f235"}.fa-stethoscope:before{content:"\f0f1"}.fa-comment-alt:before,.fa-message:before{content:"\f27a"}.fa-info:before{content:"\f129"}.fa-compress-alt:before,.fa-down-left-and-up-right-to-center:before{content:"\f422"}.fa-explosion:before{content:"\e4e9"}.fa-file-alt:before,.fa-file-lines:before,.fa-file-text:before{content:"\f15c"}.fa-wave-square:before{content:"\f83e"}.fa-ring:before{content:"\f70b"}.fa-building-un:before{content:"\e4d9"}.fa-dice-three:before{content:"\f527"}.fa-calendar-alt:before,.fa-calendar-days:before{content:"\f073"}.fa-anchor-circle-check:before{content:"\e4aa"}.fa-building-circle-arrow-right:before{content:"\e4d1"}.fa-volleyball-ball:before,.fa-volleyball:before{content:"\f45f"}.fa-arrows-up-to-line:before{content:"\e4c2"}.fa-sort-desc:before,.fa-sort-down:before{content:"\f0dd"}.fa-circle-minus:before,.fa-minus-circle:before{content:"\f056"}.fa-door-open:before{content:"\f52b"}.fa-right-from-bracket:before,.fa-sign-out-alt:before{content:"\f2f5"}.fa-atom:before{content:"\f5d2"}.fa-soap:before{content:"\e06e"}.fa-heart-music-camera-bolt:before,.fa-icons:before{content:"\f86d"}.fa-microphone-alt-slash:before,.fa-microphone-lines-slash:before{content:"\f539"}.fa-bridge-circle-check:before{content:"\e4c9"}.fa-pump-medical:before{content:"\e06a"}.fa-fingerprint:before{content:"\f577"}.fa-hand-point-right:before{content:"\f0a4"}.fa-magnifying-glass-location:before,.fa-search-location:before{content:"\f689"}.fa-forward-step:before,.fa-step-forward:before{content:"\f051"}.fa-face-smile-beam:before,.fa-smile-beam:before{content:"\f5b8"}.fa-flag-checkered:before{content:"\f11e"}.fa-football-ball:before,.fa-football:before{content:"\f44e"}.fa-school-circle-exclamation:before{content:"\e56c"}.fa-crop:before{content:"\f125"}.fa-angle-double-down:before,.fa-angles-down:before{content:"\f103"}.fa-users-rectangle:before{content:"\e594"}.fa-people-roof:before{content:"\e537"}.fa-people-line:before{content:"\e534"}.fa-beer-mug-empty:before,.fa-beer:before{content:"\f0fc"}.fa-diagram-predecessor:before{content:"\e477"}.fa-arrow-up-long:before,.fa-long-arrow-up:before{content:"\f176"}.fa-burn:before,.fa-fire-flame-simple:before{content:"\f46a"}.fa-male:before,.fa-person:before{content:"\f183"}.fa-laptop:before{content:"\f109"}.fa-file-csv:before{content:"\f6dd"}.fa-menorah:before{content:"\f676"}.fa-truck-plane:before{content:"\e58f"}.fa-record-vinyl:before{content:"\f8d9"}.fa-face-grin-stars:before,.fa-grin-stars:before{content:"\f587"}.fa-bong:before{content:"\f55c"}.fa-pastafarianism:before,.fa-spaghetti-monster-flying:before{content:"\f67b"}.fa-arrow-down-up-across-line:before{content:"\e4af"}.fa-spoon:before,.fa-utensil-spoon:before{content:"\f2e5"}.fa-jar-wheat:before{content:"\e517"}.fa-envelopes-bulk:before,.fa-mail-bulk:before{content:"\f674"}.fa-file-circle-exclamation:before{content:"\e4eb"}.fa-circle-h:before,.fa-hospital-symbol:before{content:"\f47e"}.fa-pager:before{content:"\f815"}.fa-address-book:before,.fa-contact-book:before{content:"\f2b9"}.fa-strikethrough:before{content:"\f0cc"}.fa-k:before{content:"\4b"}.fa-landmark-flag:before{content:"\e51c"}.fa-pencil-alt:before,.fa-pencil:before{content:"\f303"}.fa-backward:before{content:"\f04a"}.fa-caret-right:before{content:"\f0da"}.fa-comments:before{content:"\f086"}.fa-file-clipboard:before,.fa-paste:before{content:"\f0ea"}.fa-code-pull-request:before{content:"\e13c"}.fa-clipboard-list:before{content:"\f46d"}.fa-truck-loading:before,.fa-truck-ramp-box:before{content:"\f4de"}.fa-user-check:before{content:"\f4fc"}.fa-vial-virus:before{content:"\e597"}.fa-sheet-plastic:before{content:"\e571"}.fa-blog:before{content:"\f781"}.fa-user-ninja:before{content:"\f504"}.fa-person-arrow-up-from-line:before{content:"\e539"}.fa-scroll-torah:before,.fa-torah:before{content:"\f6a0"}.fa-broom-ball:before,.fa-quidditch-broom-ball:before,.fa-quidditch:before{content:"\f458"}.fa-toggle-off:before{content:"\f204"}.fa-archive:before,.fa-box-archive:before{content:"\f187"}.fa-person-drowning:before{content:"\e545"}.fa-arrow-down-9-1:before,.fa-sort-numeric-desc:before,.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-face-grin-tongue-squint:before,.fa-grin-tongue-squint:before{content:"\f58a"}.fa-spray-can:before{content:"\f5bd"}.fa-truck-monster:before{content:"\f63b"}.fa-w:before{content:"\57"}.fa-earth-africa:before,.fa-globe-africa:before{content:"\f57c"}.fa-rainbow:before{content:"\f75b"}.fa-circle-notch:before{content:"\f1ce"}.fa-tablet-alt:before,.fa-tablet-screen-button:before{content:"\f3fa"}.fa-paw:before{content:"\f1b0"}.fa-cloud:before{content:"\f0c2"}.fa-trowel-bricks:before{content:"\e58a"}.fa-face-flushed:before,.fa-flushed:before{content:"\f579"}.fa-hospital-user:before{content:"\f80d"}.fa-tent-arrow-left-right:before{content:"\e57f"}.fa-gavel:before,.fa-legal:before{content:"\f0e3"}.fa-binoculars:before{content:"\f1e5"}.fa-microphone-slash:before{content:"\f131"}.fa-box-tissue:before{content:"\e05b"}.fa-motorcycle:before{content:"\f21c"}.fa-bell-concierge:before,.fa-concierge-bell:before{content:"\f562"}.fa-pen-ruler:before,.fa-pencil-ruler:before{content:"\f5ae"}.fa-people-arrows-left-right:before,.fa-people-arrows:before{content:"\e068"}.fa-mars-and-venus-burst:before{content:"\e523"}.fa-caret-square-right:before,.fa-square-caret-right:before{content:"\f152"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-sun-plant-wilt:before{content:"\e57a"}.fa-toilets-portable:before{content:"\e584"}.fa-hockey-puck:before{content:"\f453"}.fa-table:before{content:"\f0ce"}.fa-magnifying-glass-arrow-right:before{content:"\e521"}.fa-digital-tachograph:before,.fa-tachograph-digital:before{content:"\f566"}.fa-users-slash:before{content:"\e073"}.fa-clover:before{content:"\e139"}.fa-mail-reply:before,.fa-reply:before{content:"\f3e5"}.fa-star-and-crescent:before{content:"\f699"}.fa-house-fire:before{content:"\e50c"}.fa-minus-square:before,.fa-square-minus:before{content:"\f146"}.fa-helicopter:before{content:"\f533"}.fa-compass:before{content:"\f14e"}.fa-caret-square-down:before,.fa-square-caret-down:before{content:"\f150"}.fa-file-circle-question:before{content:"\e4ef"}.fa-laptop-code:before{content:"\f5fc"}.fa-swatchbook:before{content:"\f5c3"}.fa-prescription-bottle:before{content:"\f485"}.fa-bars:before,.fa-navicon:before{content:"\f0c9"}.fa-people-group:before{content:"\e533"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-heart-broken:before,.fa-heart-crack:before{content:"\f7a9"}.fa-external-link-square-alt:before,.fa-square-up-right:before{content:"\f360"}.fa-face-kiss-beam:before,.fa-kiss-beam:before{content:"\f597"}.fa-film:before{content:"\f008"}.fa-ruler-horizontal:before{content:"\f547"}.fa-people-robbery:before{content:"\e536"}.fa-lightbulb:before{content:"\f0eb"}.fa-caret-left:before{content:"\f0d9"}.fa-circle-exclamation:before,.fa-exclamation-circle:before{content:"\f06a"}.fa-school-circle-xmark:before{content:"\e56d"}.fa-arrow-right-from-bracket:before,.fa-sign-out:before{content:"\f08b"}.fa-chevron-circle-down:before,.fa-circle-chevron-down:before{content:"\f13a"}.fa-unlock-alt:before,.fa-unlock-keyhole:before{content:"\f13e"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-headphones-alt:before,.fa-headphones-simple:before{content:"\f58f"}.fa-sitemap:before{content:"\f0e8"}.fa-circle-dollar-to-slot:before,.fa-donate:before{content:"\f4b9"}.fa-memory:before{content:"\f538"}.fa-road-spikes:before{content:"\e568"}.fa-fire-burner:before{content:"\e4f1"}.fa-flag:before{content:"\f024"}.fa-hanukiah:before{content:"\f6e6"}.fa-feather:before{content:"\f52d"}.fa-volume-down:before,.fa-volume-low:before{content:"\f027"}.fa-comment-slash:before{content:"\f4b3"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-compress:before{content:"\f066"}.fa-wheat-alt:before,.fa-wheat-awn:before{content:"\e2cd"}.fa-ankh:before{content:"\f644"}.fa-hands-holding-child:before{content:"\e4fa"}.fa-asterisk:before{content:"\2a"}.fa-check-square:before,.fa-square-check:before{content:"\f14a"}.fa-peseta-sign:before{content:"\e221"}.fa-header:before,.fa-heading:before{content:"\f1dc"}.fa-ghost:before{content:"\f6e2"}.fa-list-squares:before,.fa-list:before{content:"\f03a"}.fa-phone-square-alt:before,.fa-square-phone-flip:before{content:"\f87b"}.fa-cart-plus:before{content:"\f217"}.fa-gamepad:before{content:"\f11b"}.fa-circle-dot:before,.fa-dot-circle:before{content:"\f192"}.fa-dizzy:before,.fa-face-dizzy:before{content:"\f567"}.fa-egg:before{content:"\f7fb"}.fa-house-medical-circle-xmark:before{content:"\e513"}.fa-campground:before{content:"\f6bb"}.fa-folder-plus:before{content:"\f65e"}.fa-futbol-ball:before,.fa-futbol:before,.fa-soccer-ball:before{content:"\f1e3"}.fa-paint-brush:before,.fa-paintbrush:before{content:"\f1fc"}.fa-lock:before{content:"\f023"}.fa-gas-pump:before{content:"\f52f"}.fa-hot-tub-person:before,.fa-hot-tub:before{content:"\f593"}.fa-map-location:before,.fa-map-marked:before{content:"\f59f"}.fa-house-flood-water:before{content:"\e50e"}.fa-tree:before{content:"\f1bb"}.fa-bridge-lock:before{content:"\e4cc"}.fa-sack-dollar:before{content:"\f81d"}.fa-edit:before,.fa-pen-to-square:before{content:"\f044"}.fa-car-side:before{content:"\f5e4"}.fa-share-alt:before,.fa-share-nodes:before{content:"\f1e0"}.fa-heart-circle-minus:before{content:"\e4ff"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-microscope:before{content:"\f610"}.fa-sink:before{content:"\e06d"}.fa-bag-shopping:before,.fa-shopping-bag:before{content:"\f290"}.fa-arrow-down-z-a:before,.fa-sort-alpha-desc:before,.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-mitten:before{content:"\f7b5"}.fa-person-rays:before{content:"\e54d"}.fa-users:before{content:"\f0c0"}.fa-eye-slash:before{content:"\f070"}.fa-flask-vial:before{content:"\e4f3"}.fa-hand-paper:before,.fa-hand:before{content:"\f256"}.fa-om:before{content:"\f679"}.fa-worm:before{content:"\e599"}.fa-house-circle-xmark:before{content:"\e50b"}.fa-plug:before{content:"\f1e6"}.fa-chevron-up:before{content:"\f077"}.fa-hand-spock:before{content:"\f259"}.fa-stopwatch:before{content:"\f2f2"}.fa-face-kiss:before,.fa-kiss:before{content:"\f596"}.fa-bridge-circle-xmark:before{content:"\e4cb"}.fa-face-grin-tongue:before,.fa-grin-tongue:before{content:"\f589"}.fa-chess-bishop:before{content:"\f43a"}.fa-face-grin-wink:before,.fa-grin-wink:before{content:"\f58c"}.fa-deaf:before,.fa-deafness:before,.fa-ear-deaf:before,.fa-hard-of-hearing:before{content:"\f2a4"}.fa-road-circle-check:before{content:"\e564"}.fa-dice-five:before{content:"\f523"}.fa-rss-square:before,.fa-square-rss:before{content:"\f143"}.fa-land-mine-on:before{content:"\e51b"}.fa-i-cursor:before{content:"\f246"}.fa-stamp:before{content:"\f5bf"}.fa-stairs:before{content:"\e289"}.fa-i:before{content:"\49"}.fa-hryvnia-sign:before,.fa-hryvnia:before{content:"\f6f2"}.fa-pills:before{content:"\f484"}.fa-face-grin-wide:before,.fa-grin-alt:before{content:"\f581"}.fa-tooth:before{content:"\f5c9"}.fa-v:before{content:"\56"}.fa-bangladeshi-taka-sign:before{content:"\e2e6"}.fa-bicycle:before{content:"\f206"}.fa-rod-asclepius:before,.fa-rod-snake:before,.fa-staff-aesculapius:before,.fa-staff-snake:before{content:"\e579"}.fa-head-side-cough-slash:before{content:"\e062"}.fa-ambulance:before,.fa-truck-medical:before{content:"\f0f9"}.fa-wheat-awn-circle-exclamation:before{content:"\e598"}.fa-snowman:before{content:"\f7d0"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-road-barrier:before{content:"\e562"}.fa-school:before{content:"\f549"}.fa-igloo:before{content:"\f7ae"}.fa-joint:before{content:"\f595"}.fa-angle-right:before{content:"\f105"}.fa-horse:before{content:"\f6f0"}.fa-q:before{content:"\51"}.fa-g:before{content:"\47"}.fa-notes-medical:before{content:"\f481"}.fa-temperature-2:before,.fa-temperature-half:before,.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-dong-sign:before{content:"\e169"}.fa-capsules:before{content:"\f46b"}.fa-poo-bolt:before,.fa-poo-storm:before{content:"\f75a"}.fa-face-frown-open:before,.fa-frown-open:before{content:"\f57a"}.fa-hand-point-up:before{content:"\f0a6"}.fa-money-bill:before{content:"\f0d6"}.fa-bookmark:before{content:"\f02e"}.fa-align-justify:before{content:"\f039"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-helmet-un:before{content:"\e503"}.fa-bullseye:before{content:"\f140"}.fa-bacon:before{content:"\f7e5"}.fa-hand-point-down:before{content:"\f0a7"}.fa-arrow-up-from-bracket:before{content:"\e09a"}.fa-folder-blank:before,.fa-folder:before{content:"\f07b"}.fa-file-medical-alt:before,.fa-file-waveform:before{content:"\f478"}.fa-radiation:before{content:"\f7b9"}.fa-chart-simple:before{content:"\e473"}.fa-mars-stroke:before{content:"\f229"}.fa-vial:before{content:"\f492"}.fa-dashboard:before,.fa-gauge-med:before,.fa-gauge:before,.fa-tachometer-alt-average:before{content:"\f624"}.fa-magic-wand-sparkles:before,.fa-wand-magic-sparkles:before{content:"\e2ca"}.fa-e:before{content:"\45"}.fa-pen-alt:before,.fa-pen-clip:before{content:"\f305"}.fa-bridge-circle-exclamation:before{content:"\e4ca"}.fa-user:before{content:"\f007"}.fa-school-circle-check:before{content:"\e56b"}.fa-dumpster:before{content:"\f793"}.fa-shuttle-van:before,.fa-van-shuttle:before{content:"\f5b6"}.fa-building-user:before{content:"\e4da"}.fa-caret-square-left:before,.fa-square-caret-left:before{content:"\f191"}.fa-highlighter:before{content:"\f591"}.fa-key:before{content:"\f084"}.fa-bullhorn:before{content:"\f0a1"}.fa-globe:before{content:"\f0ac"}.fa-synagogue:before{content:"\f69b"}.fa-person-half-dress:before{content:"\e548"}.fa-road-bridge:before{content:"\e563"}.fa-location-arrow:before{content:"\f124"}.fa-c:before{content:"\43"}.fa-tablet-button:before{content:"\f10a"}.fa-building-lock:before{content:"\e4d6"}.fa-pizza-slice:before{content:"\f818"}.fa-money-bill-wave:before{content:"\f53a"}.fa-area-chart:before,.fa-chart-area:before{content:"\f1fe"}.fa-house-flag:before{content:"\e50d"}.fa-person-circle-minus:before{content:"\e540"}.fa-ban:before,.fa-cancel:before{content:"\f05e"}.fa-camera-rotate:before{content:"\e0d8"}.fa-air-freshener:before,.fa-spray-can-sparkles:before{content:"\f5d0"}.fa-star:before{content:"\f005"}.fa-repeat:before{content:"\f363"}.fa-cross:before{content:"\f654"}.fa-box:before{content:"\f466"}.fa-venus-mars:before{content:"\f228"}.fa-arrow-pointer:before,.fa-mouse-pointer:before{content:"\f245"}.fa-expand-arrows-alt:before,.fa-maximize:before{content:"\f31e"}.fa-charging-station:before{content:"\f5e7"}.fa-shapes:before,.fa-triangle-circle-square:before{content:"\f61f"}.fa-random:before,.fa-shuffle:before{content:"\f074"}.fa-person-running:before,.fa-running:before{content:"\f70c"}.fa-mobile-retro:before{content:"\e527"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-spider:before{content:"\f717"}.fa-hands-bound:before{content:"\e4f9"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-plane-circle-exclamation:before{content:"\e556"}.fa-x-ray:before{content:"\f497"}.fa-spell-check:before{content:"\f891"}.fa-slash:before{content:"\f715"}.fa-computer-mouse:before,.fa-mouse:before{content:"\f8cc"}.fa-arrow-right-to-bracket:before,.fa-sign-in:before{content:"\f090"}.fa-shop-slash:before,.fa-store-alt-slash:before{content:"\e070"}.fa-server:before{content:"\f233"}.fa-virus-covid-slash:before{content:"\e4a9"}.fa-shop-lock:before{content:"\e4a5"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-blender-phone:before{content:"\f6b6"}.fa-building-wheat:before{content:"\e4db"}.fa-person-breastfeeding:before{content:"\e53a"}.fa-right-to-bracket:before,.fa-sign-in-alt:before{content:"\f2f6"}.fa-venus:before{content:"\f221"}.fa-passport:before{content:"\f5ab"}.fa-heart-pulse:before,.fa-heartbeat:before{content:"\f21e"}.fa-people-carry-box:before,.fa-people-carry:before{content:"\f4ce"}.fa-temperature-high:before{content:"\f769"}.fa-microchip:before{content:"\f2db"}.fa-crown:before{content:"\f521"}.fa-weight-hanging:before{content:"\f5cd"}.fa-xmarks-lines:before{content:"\e59a"}.fa-file-prescription:before{content:"\f572"}.fa-weight-scale:before,.fa-weight:before{content:"\f496"}.fa-user-friends:before,.fa-user-group:before{content:"\f500"}.fa-arrow-up-a-z:before,.fa-sort-alpha-up:before{content:"\f15e"}.fa-chess-knight:before{content:"\f441"}.fa-face-laugh-squint:before,.fa-laugh-squint:before{content:"\f59b"}.fa-wheelchair:before{content:"\f193"}.fa-arrow-circle-up:before,.fa-circle-arrow-up:before{content:"\f0aa"}.fa-toggle-on:before{content:"\f205"}.fa-person-walking:before,.fa-walking:before{content:"\f554"}.fa-l:before{content:"\4c"}.fa-fire:before{content:"\f06d"}.fa-bed-pulse:before,.fa-procedures:before{content:"\f487"}.fa-shuttle-space:before,.fa-space-shuttle:before{content:"\f197"}.fa-face-laugh:before,.fa-laugh:before{content:"\f599"}.fa-folder-open:before{content:"\f07c"}.fa-heart-circle-plus:before{content:"\e500"}.fa-code-fork:before{content:"\e13b"}.fa-city:before{content:"\f64f"}.fa-microphone-alt:before,.fa-microphone-lines:before{content:"\f3c9"}.fa-pepper-hot:before{content:"\f816"}.fa-unlock:before{content:"\f09c"}.fa-colon-sign:before{content:"\e140"}.fa-headset:before{content:"\f590"}.fa-store-slash:before{content:"\e071"}.fa-road-circle-xmark:before{content:"\e566"}.fa-user-minus:before{content:"\f503"}.fa-mars-stroke-up:before,.fa-mars-stroke-v:before{content:"\f22a"}.fa-champagne-glasses:before,.fa-glass-cheers:before{content:"\f79f"}.fa-clipboard:before{content:"\f328"}.fa-house-circle-exclamation:before{content:"\e50a"}.fa-file-arrow-up:before,.fa-file-upload:before{content:"\f574"}.fa-wifi-3:before,.fa-wifi-strong:before,.fa-wifi:before{content:"\f1eb"}.fa-bath:before,.fa-bathtub:before{content:"\f2cd"}.fa-underline:before{content:"\f0cd"}.fa-user-edit:before,.fa-user-pen:before{content:"\f4ff"}.fa-signature:before{content:"\f5b7"}.fa-stroopwafel:before{content:"\f551"}.fa-bold:before{content:"\f032"}.fa-anchor-lock:before{content:"\e4ad"}.fa-building-ngo:before{content:"\e4d7"}.fa-manat-sign:before{content:"\e1d5"}.fa-not-equal:before{content:"\f53e"}.fa-border-style:before,.fa-border-top-left:before{content:"\f853"}.fa-map-location-dot:before,.fa-map-marked-alt:before{content:"\f5a0"}.fa-jedi:before{content:"\f669"}.fa-poll:before,.fa-square-poll-vertical:before{content:"\f681"}.fa-mug-hot:before{content:"\f7b6"}.fa-battery-car:before,.fa-car-battery:before{content:"\f5df"}.fa-gift:before{content:"\f06b"}.fa-dice-two:before{content:"\f528"}.fa-chess-queen:before{content:"\f445"}.fa-glasses:before{content:"\f530"}.fa-chess-board:before{content:"\f43c"}.fa-building-circle-check:before{content:"\e4d2"}.fa-person-chalkboard:before{content:"\e53d"}.fa-mars-stroke-h:before,.fa-mars-stroke-right:before{content:"\f22b"}.fa-hand-back-fist:before,.fa-hand-rock:before{content:"\f255"}.fa-caret-square-up:before,.fa-square-caret-up:before{content:"\f151"}.fa-cloud-showers-water:before{content:"\e4e4"}.fa-bar-chart:before,.fa-chart-bar:before{content:"\f080"}.fa-hands-bubbles:before,.fa-hands-wash:before{content:"\e05e"}.fa-less-than-equal:before{content:"\f537"}.fa-train:before{content:"\f238"}.fa-eye-low-vision:before,.fa-low-vision:before{content:"\f2a8"}.fa-crow:before{content:"\f520"}.fa-sailboat:before{content:"\e445"}.fa-window-restore:before{content:"\f2d2"}.fa-plus-square:before,.fa-square-plus:before{content:"\f0fe"}.fa-torii-gate:before{content:"\f6a1"}.fa-frog:before{content:"\f52e"}.fa-bucket:before{content:"\e4cf"}.fa-image:before{content:"\f03e"}.fa-microphone:before{content:"\f130"}.fa-cow:before{content:"\f6c8"}.fa-caret-up:before{content:"\f0d8"}.fa-screwdriver:before{content:"\f54a"}.fa-folder-closed:before{content:"\e185"}.fa-house-tsunami:before{content:"\e515"}.fa-square-nfi:before{content:"\e576"}.fa-arrow-up-from-ground-water:before{content:"\e4b5"}.fa-glass-martini-alt:before,.fa-martini-glass:before{content:"\f57b"}.fa-rotate-back:before,.fa-rotate-backward:before,.fa-rotate-left:before,.fa-undo-alt:before{content:"\f2ea"}.fa-columns:before,.fa-table-columns:before{content:"\f0db"}.fa-lemon:before{content:"\f094"}.fa-head-side-mask:before{content:"\e063"}.fa-handshake:before{content:"\f2b5"}.fa-gem:before{content:"\f3a5"}.fa-dolly-box:before,.fa-dolly:before{content:"\f472"}.fa-smoking:before{content:"\f48d"}.fa-compress-arrows-alt:before,.fa-minimize:before{content:"\f78c"}.fa-monument:before{content:"\f5a6"}.fa-snowplow:before{content:"\f7d2"}.fa-angle-double-right:before,.fa-angles-right:before{content:"\f101"}.fa-cannabis:before{content:"\f55f"}.fa-circle-play:before,.fa-play-circle:before{content:"\f144"}.fa-tablets:before{content:"\f490"}.fa-ethernet:before{content:"\f796"}.fa-eur:before,.fa-euro-sign:before,.fa-euro:before{content:"\f153"}.fa-chair:before{content:"\f6c0"}.fa-check-circle:before,.fa-circle-check:before{content:"\f058"}.fa-circle-stop:before,.fa-stop-circle:before{content:"\f28d"}.fa-compass-drafting:before,.fa-drafting-compass:before{content:"\f568"}.fa-plate-wheat:before{content:"\e55a"}.fa-icicles:before{content:"\f7ad"}.fa-person-shelter:before{content:"\e54f"}.fa-neuter:before{content:"\f22c"}.fa-id-badge:before{content:"\f2c1"}.fa-marker:before{content:"\f5a1"}.fa-face-laugh-beam:before,.fa-laugh-beam:before{content:"\f59a"}.fa-helicopter-symbol:before{content:"\e502"}.fa-universal-access:before{content:"\f29a"}.fa-chevron-circle-up:before,.fa-circle-chevron-up:before{content:"\f139"}.fa-lari-sign:before{content:"\e1c8"}.fa-volcano:before{content:"\f770"}.fa-person-walking-dashed-line-arrow-right:before{content:"\e553"}.fa-gbp:before,.fa-pound-sign:before,.fa-sterling-sign:before{content:"\f154"}.fa-viruses:before{content:"\e076"}.fa-square-person-confined:before{content:"\e577"}.fa-user-tie:before{content:"\f508"}.fa-arrow-down-long:before,.fa-long-arrow-down:before{content:"\f175"}.fa-tent-arrow-down-to-line:before{content:"\e57e"}.fa-certificate:before{content:"\f0a3"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-suitcase:before{content:"\f0f2"}.fa-person-skating:before,.fa-skating:before{content:"\f7c5"}.fa-filter-circle-dollar:before,.fa-funnel-dollar:before{content:"\f662"}.fa-camera-retro:before{content:"\f083"}.fa-arrow-circle-down:before,.fa-circle-arrow-down:before{content:"\f0ab"}.fa-arrow-right-to-file:before,.fa-file-import:before{content:"\f56f"}.fa-external-link-square:before,.fa-square-arrow-up-right:before{content:"\f14c"}.fa-box-open:before{content:"\f49e"}.fa-scroll:before{content:"\f70e"}.fa-spa:before{content:"\f5bb"}.fa-location-pin-lock:before{content:"\e51f"}.fa-pause:before{content:"\f04c"}.fa-hill-avalanche:before{content:"\e507"}.fa-temperature-0:before,.fa-temperature-empty:before,.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-bomb:before{content:"\f1e2"}.fa-registered:before{content:"\f25d"}.fa-address-card:before,.fa-contact-card:before,.fa-vcard:before{content:"\f2bb"}.fa-balance-scale-right:before,.fa-scale-unbalanced-flip:before{content:"\f516"}.fa-subscript:before{content:"\f12c"}.fa-diamond-turn-right:before,.fa-directions:before{content:"\f5eb"}.fa-burst:before{content:"\e4dc"}.fa-house-laptop:before,.fa-laptop-house:before{content:"\e066"}.fa-face-tired:before,.fa-tired:before{content:"\f5c8"}.fa-money-bills:before{content:"\e1f3"}.fa-smog:before{content:"\f75f"}.fa-crutch:before{content:"\f7f7"}.fa-cloud-arrow-up:before,.fa-cloud-upload-alt:before,.fa-cloud-upload:before{content:"\f0ee"}.fa-palette:before{content:"\f53f"}.fa-arrows-turn-right:before{content:"\e4c0"}.fa-vest:before{content:"\e085"}.fa-ferry:before{content:"\e4ea"}.fa-arrows-down-to-people:before{content:"\e4b9"}.fa-seedling:before,.fa-sprout:before{content:"\f4d8"}.fa-arrows-alt-h:before,.fa-left-right:before{content:"\f337"}.fa-boxes-packing:before{content:"\e4c7"}.fa-arrow-circle-left:before,.fa-circle-arrow-left:before{content:"\f0a8"}.fa-group-arrows-rotate:before{content:"\e4f6"}.fa-bowl-food:before{content:"\e4c6"}.fa-candy-cane:before{content:"\f786"}.fa-arrow-down-wide-short:before,.fa-sort-amount-asc:before,.fa-sort-amount-down:before{content:"\f160"}.fa-cloud-bolt:before,.fa-thunderstorm:before{content:"\f76c"}.fa-remove-format:before,.fa-text-slash:before{content:"\f87d"}.fa-face-smile-wink:before,.fa-smile-wink:before{content:"\f4da"}.fa-file-word:before{content:"\f1c2"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-arrows-h:before,.fa-arrows-left-right:before{content:"\f07e"}.fa-house-lock:before{content:"\e510"}.fa-cloud-arrow-down:before,.fa-cloud-download-alt:before,.fa-cloud-download:before{content:"\f0ed"}.fa-children:before{content:"\e4e1"}.fa-blackboard:before,.fa-chalkboard:before{content:"\f51b"}.fa-user-alt-slash:before,.fa-user-large-slash:before{content:"\f4fa"}.fa-envelope-open:before{content:"\f2b6"}.fa-handshake-alt-slash:before,.fa-handshake-simple-slash:before{content:"\e05f"}.fa-mattress-pillow:before{content:"\e525"}.fa-guarani-sign:before{content:"\e19a"}.fa-arrows-rotate:before,.fa-refresh:before,.fa-sync:before{content:"\f021"}.fa-fire-extinguisher:before{content:"\f134"}.fa-cruzeiro-sign:before{content:"\e152"}.fa-greater-than-equal:before{content:"\f532"}.fa-shield-alt:before,.fa-shield-halved:before{content:"\f3ed"}.fa-atlas:before,.fa-book-atlas:before{content:"\f558"}.fa-virus:before{content:"\e074"}.fa-envelope-circle-check:before{content:"\e4e8"}.fa-layer-group:before{content:"\f5fd"}.fa-arrows-to-dot:before{content:"\e4be"}.fa-archway:before{content:"\f557"}.fa-heart-circle-check:before{content:"\e4fd"}.fa-house-chimney-crack:before,.fa-house-damage:before{content:"\f6f1"}.fa-file-archive:before,.fa-file-zipper:before{content:"\f1c6"}.fa-square:before{content:"\f0c8"}.fa-glass-martini:before,.fa-martini-glass-empty:before{content:"\f000"}.fa-couch:before{content:"\f4b8"}.fa-cedi-sign:before{content:"\e0df"}.fa-italic:before{content:"\f033"}.fa-table-cells-column-lock:before{content:"\e678"}.fa-church:before{content:"\f51d"}.fa-comments-dollar:before{content:"\f653"}.fa-democrat:before{content:"\f747"}.fa-z:before{content:"\5a"}.fa-person-skiing:before,.fa-skiing:before{content:"\f7c9"}.fa-road-lock:before{content:"\e567"}.fa-a:before{content:"\41"}.fa-temperature-arrow-down:before,.fa-temperature-down:before{content:"\e03f"}.fa-feather-alt:before,.fa-feather-pointed:before{content:"\f56b"}.fa-p:before{content:"\50"}.fa-snowflake:before{content:"\f2dc"}.fa-newspaper:before{content:"\f1ea"}.fa-ad:before,.fa-rectangle-ad:before{content:"\f641"}.fa-arrow-circle-right:before,.fa-circle-arrow-right:before{content:"\f0a9"}.fa-filter-circle-xmark:before{content:"\e17b"}.fa-locust:before{content:"\e520"}.fa-sort:before,.fa-unsorted:before{content:"\f0dc"}.fa-list-1-2:before,.fa-list-numeric:before,.fa-list-ol:before{content:"\f0cb"}.fa-person-dress-burst:before{content:"\e544"}.fa-money-check-alt:before,.fa-money-check-dollar:before{content:"\f53d"}.fa-vector-square:before{content:"\f5cb"}.fa-bread-slice:before{content:"\f7ec"}.fa-language:before{content:"\f1ab"}.fa-face-kiss-wink-heart:before,.fa-kiss-wink-heart:before{content:"\f598"}.fa-filter:before{content:"\f0b0"}.fa-question:before{content:"\3f"}.fa-file-signature:before{content:"\f573"}.fa-arrows-alt:before,.fa-up-down-left-right:before{content:"\f0b2"}.fa-house-chimney-user:before{content:"\e065"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-puzzle-piece:before{content:"\f12e"}.fa-money-check:before{content:"\f53c"}.fa-star-half-alt:before,.fa-star-half-stroke:before{content:"\f5c0"}.fa-code:before{content:"\f121"}.fa-glass-whiskey:before,.fa-whiskey-glass:before{content:"\f7a0"}.fa-building-circle-exclamation:before{content:"\e4d3"}.fa-magnifying-glass-chart:before{content:"\e522"}.fa-arrow-up-right-from-square:before,.fa-external-link:before{content:"\f08e"}.fa-cubes-stacked:before{content:"\e4e6"}.fa-krw:before,.fa-won-sign:before,.fa-won:before{content:"\f159"}.fa-virus-covid:before{content:"\e4a8"}.fa-austral-sign:before{content:"\e0a9"}.fa-f:before{content:"\46"}.fa-leaf:before{content:"\f06c"}.fa-road:before{content:"\f018"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-person-circle-plus:before{content:"\e541"}.fa-chart-pie:before,.fa-pie-chart:before{content:"\f200"}.fa-bolt-lightning:before{content:"\e0b7"}.fa-sack-xmark:before{content:"\e56a"}.fa-file-excel:before{content:"\f1c3"}.fa-file-contract:before{content:"\f56c"}.fa-fish-fins:before{content:"\e4f2"}.fa-building-flag:before{content:"\e4d5"}.fa-face-grin-beam:before,.fa-grin-beam:before{content:"\f582"}.fa-object-ungroup:before{content:"\f248"}.fa-poop:before{content:"\f619"}.fa-location-pin:before,.fa-map-marker:before{content:"\f041"}.fa-kaaba:before{content:"\f66b"}.fa-toilet-paper:before{content:"\f71e"}.fa-hard-hat:before,.fa-hat-hard:before,.fa-helmet-safety:before{content:"\f807"}.fa-eject:before{content:"\f052"}.fa-arrow-alt-circle-right:before,.fa-circle-right:before{content:"\f35a"}.fa-plane-circle-check:before{content:"\e555"}.fa-face-rolling-eyes:before,.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-object-group:before{content:"\f247"}.fa-chart-line:before,.fa-line-chart:before{content:"\f201"}.fa-mask-ventilator:before{content:"\e524"}.fa-arrow-right:before{content:"\f061"}.fa-map-signs:before,.fa-signs-post:before{content:"\f277"}.fa-cash-register:before{content:"\f788"}.fa-person-circle-question:before{content:"\e542"}.fa-h:before{content:"\48"}.fa-tarp:before{content:"\e57b"}.fa-screwdriver-wrench:before,.fa-tools:before{content:"\f7d9"}.fa-arrows-to-eye:before{content:"\e4bf"}.fa-plug-circle-bolt:before{content:"\e55b"}.fa-heart:before{content:"\f004"}.fa-mars-and-venus:before{content:"\f224"}.fa-home-user:before,.fa-house-user:before{content:"\e1b0"}.fa-dumpster-fire:before{content:"\f794"}.fa-house-crack:before{content:"\e3b1"}.fa-cocktail:before,.fa-martini-glass-citrus:before{content:"\f561"}.fa-face-surprise:before,.fa-surprise:before{content:"\f5c2"}.fa-bottle-water:before{content:"\e4c5"}.fa-circle-pause:before,.fa-pause-circle:before{content:"\f28b"}.fa-toilet-paper-slash:before{content:"\e072"}.fa-apple-alt:before,.fa-apple-whole:before{content:"\f5d1"}.fa-kitchen-set:before{content:"\e51a"}.fa-r:before{content:"\52"}.fa-temperature-1:before,.fa-temperature-quarter:before,.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-cube:before{content:"\f1b2"}.fa-bitcoin-sign:before{content:"\e0b4"}.fa-shield-dog:before{content:"\e573"}.fa-solar-panel:before{content:"\f5ba"}.fa-lock-open:before{content:"\f3c1"}.fa-elevator:before{content:"\e16d"}.fa-money-bill-transfer:before{content:"\e528"}.fa-money-bill-trend-up:before{content:"\e529"}.fa-house-flood-water-circle-arrow-right:before{content:"\e50f"}.fa-poll-h:before,.fa-square-poll-horizontal:before{content:"\f682"}.fa-circle:before{content:"\f111"}.fa-backward-fast:before,.fa-fast-backward:before{content:"\f049"}.fa-recycle:before{content:"\f1b8"}.fa-user-astronaut:before{content:"\f4fb"}.fa-plane-slash:before{content:"\e069"}.fa-trademark:before{content:"\f25c"}.fa-basketball-ball:before,.fa-basketball:before{content:"\f434"}.fa-satellite-dish:before{content:"\f7c0"}.fa-arrow-alt-circle-up:before,.fa-circle-up:before{content:"\f35b"}.fa-mobile-alt:before,.fa-mobile-screen-button:before{content:"\f3cd"}.fa-volume-high:before,.fa-volume-up:before{content:"\f028"}.fa-users-rays:before{content:"\e593"}.fa-wallet:before{content:"\f555"}.fa-clipboard-check:before{content:"\f46c"}.fa-file-audio:before{content:"\f1c7"}.fa-burger:before,.fa-hamburger:before{content:"\f805"}.fa-wrench:before{content:"\f0ad"}.fa-bugs:before{content:"\e4d0"}.fa-rupee-sign:before,.fa-rupee:before{content:"\f156"}.fa-file-image:before{content:"\f1c5"}.fa-circle-question:before,.fa-question-circle:before{content:"\f059"}.fa-plane-departure:before{content:"\f5b0"}.fa-handshake-slash:before{content:"\e060"}.fa-book-bookmark:before{content:"\e0bb"}.fa-code-branch:before{content:"\f126"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-bridge:before{content:"\e4c8"}.fa-phone-alt:before,.fa-phone-flip:before{content:"\f879"}.fa-truck-front:before{content:"\e2b7"}.fa-cat:before{content:"\f6be"}.fa-anchor-circle-exclamation:before{content:"\e4ab"}.fa-truck-field:before{content:"\e58d"}.fa-route:before{content:"\f4d7"}.fa-clipboard-question:before{content:"\e4e3"}.fa-panorama:before{content:"\e209"}.fa-comment-medical:before{content:"\f7f5"}.fa-teeth-open:before{content:"\f62f"}.fa-file-circle-minus:before{content:"\e4ed"}.fa-tags:before{content:"\f02c"}.fa-wine-glass:before{content:"\f4e3"}.fa-fast-forward:before,.fa-forward-fast:before{content:"\f050"}.fa-face-meh-blank:before,.fa-meh-blank:before{content:"\f5a4"}.fa-parking:before,.fa-square-parking:before{content:"\f540"}.fa-house-signal:before{content:"\e012"}.fa-bars-progress:before,.fa-tasks-alt:before{content:"\f828"}.fa-faucet-drip:before{content:"\e006"}.fa-cart-flatbed:before,.fa-dolly-flatbed:before{content:"\f474"}.fa-ban-smoking:before,.fa-smoking-ban:before{content:"\f54d"}.fa-terminal:before{content:"\f120"}.fa-mobile-button:before{content:"\f10b"}.fa-house-medical-flag:before{content:"\e514"}.fa-basket-shopping:before,.fa-shopping-basket:before{content:"\f291"}.fa-tape:before{content:"\f4db"}.fa-bus-alt:before,.fa-bus-simple:before{content:"\f55e"}.fa-eye:before{content:"\f06e"}.fa-face-sad-cry:before,.fa-sad-cry:before{content:"\f5b3"}.fa-audio-description:before{content:"\f29e"}.fa-person-military-to-person:before{content:"\e54c"}.fa-file-shield:before{content:"\e4f0"}.fa-user-slash:before{content:"\f506"}.fa-pen:before{content:"\f304"}.fa-tower-observation:before{content:"\e586"}.fa-file-code:before{content:"\f1c9"}.fa-signal-5:before,.fa-signal-perfect:before,.fa-signal:before{content:"\f012"}.fa-bus:before{content:"\f207"}.fa-heart-circle-xmark:before{content:"\e501"}.fa-home-lg:before,.fa-house-chimney:before{content:"\e3af"}.fa-window-maximize:before{content:"\f2d0"}.fa-face-frown:before,.fa-frown:before{content:"\f119"}.fa-prescription:before{content:"\f5b1"}.fa-shop:before,.fa-store-alt:before{content:"\f54f"}.fa-floppy-disk:before,.fa-save:before{content:"\f0c7"}.fa-vihara:before{content:"\f6a7"}.fa-balance-scale-left:before,.fa-scale-unbalanced:before{content:"\f515"}.fa-sort-asc:before,.fa-sort-up:before{content:"\f0de"}.fa-comment-dots:before,.fa-commenting:before{content:"\f4ad"}.fa-plant-wilt:before{content:"\e5aa"}.fa-diamond:before{content:"\f219"}.fa-face-grin-squint:before,.fa-grin-squint:before{content:"\f585"}.fa-hand-holding-dollar:before,.fa-hand-holding-usd:before{content:"\f4c0"}.fa-bacterium:before{content:"\e05a"}.fa-hand-pointer:before{content:"\f25a"}.fa-drum-steelpan:before{content:"\f56a"}.fa-hand-scissors:before{content:"\f257"}.fa-hands-praying:before,.fa-praying-hands:before{content:"\f684"}.fa-arrow-right-rotate:before,.fa-arrow-rotate-forward:before,.fa-arrow-rotate-right:before,.fa-redo:before{content:"\f01e"}.fa-biohazard:before{content:"\f780"}.fa-location-crosshairs:before,.fa-location:before{content:"\f601"}.fa-mars-double:before{content:"\f227"}.fa-child-dress:before{content:"\e59c"}.fa-users-between-lines:before{content:"\e591"}.fa-lungs-virus:before{content:"\e067"}.fa-face-grin-tears:before,.fa-grin-tears:before{content:"\f588"}.fa-phone:before{content:"\f095"}.fa-calendar-times:before,.fa-calendar-xmark:before{content:"\f273"}.fa-child-reaching:before{content:"\e59d"}.fa-head-side-virus:before{content:"\e064"}.fa-user-cog:before,.fa-user-gear:before{content:"\f4fe"}.fa-arrow-up-1-9:before,.fa-sort-numeric-up:before{content:"\f163"}.fa-door-closed:before{content:"\f52a"}.fa-shield-virus:before{content:"\e06c"}.fa-dice-six:before{content:"\f526"}.fa-mosquito-net:before{content:"\e52c"}.fa-bridge-water:before{content:"\e4ce"}.fa-person-booth:before{content:"\f756"}.fa-text-width:before{content:"\f035"}.fa-hat-wizard:before{content:"\f6e8"}.fa-pen-fancy:before{content:"\f5ac"}.fa-digging:before,.fa-person-digging:before{content:"\f85e"}.fa-trash:before{content:"\f1f8"}.fa-gauge-simple-med:before,.fa-gauge-simple:before,.fa-tachometer-average:before{content:"\f629"}.fa-book-medical:before{content:"\f7e6"}.fa-poo:before{content:"\f2fe"}.fa-quote-right-alt:before,.fa-quote-right:before{content:"\f10e"}.fa-shirt:before,.fa-t-shirt:before,.fa-tshirt:before{content:"\f553"}.fa-cubes:before{content:"\f1b3"}.fa-divide:before{content:"\f529"}.fa-tenge-sign:before,.fa-tenge:before{content:"\f7d7"}.fa-headphones:before{content:"\f025"}.fa-hands-holding:before{content:"\f4c2"}.fa-hands-clapping:before{content:"\e1a8"}.fa-republican:before{content:"\f75e"}.fa-arrow-left:before{content:"\f060"}.fa-person-circle-xmark:before{content:"\e543"}.fa-ruler:before{content:"\f545"}.fa-align-left:before{content:"\f036"}.fa-dice-d6:before{content:"\f6d1"}.fa-restroom:before{content:"\f7bd"}.fa-j:before{content:"\4a"}.fa-users-viewfinder:before{content:"\e595"}.fa-file-video:before{content:"\f1c8"}.fa-external-link-alt:before,.fa-up-right-from-square:before{content:"\f35d"}.fa-table-cells:before,.fa-th:before{content:"\f00a"}.fa-file-pdf:before{content:"\f1c1"}.fa-bible:before,.fa-book-bible:before{content:"\f647"}.fa-o:before{content:"\4f"}.fa-medkit:before,.fa-suitcase-medical:before{content:"\f0fa"}.fa-user-secret:before{content:"\f21b"}.fa-otter:before{content:"\f700"}.fa-female:before,.fa-person-dress:before{content:"\f182"}.fa-comment-dollar:before{content:"\f651"}.fa-briefcase-clock:before,.fa-business-time:before{content:"\f64a"}.fa-table-cells-large:before,.fa-th-large:before{content:"\f009"}.fa-book-tanakh:before,.fa-tanakh:before{content:"\f827"}.fa-phone-volume:before,.fa-volume-control-phone:before{content:"\f2a0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-clipboard-user:before{content:"\f7f3"}.fa-child:before{content:"\f1ae"}.fa-lira-sign:before{content:"\f195"}.fa-satellite:before{content:"\f7bf"}.fa-plane-lock:before{content:"\e558"}.fa-tag:before{content:"\f02b"}.fa-comment:before{content:"\f075"}.fa-birthday-cake:before,.fa-cake-candles:before,.fa-cake:before{content:"\f1fd"}.fa-envelope:before{content:"\f0e0"}.fa-angle-double-up:before,.fa-angles-up:before{content:"\f102"}.fa-paperclip:before{content:"\f0c6"}.fa-arrow-right-to-city:before{content:"\e4b3"}.fa-ribbon:before{content:"\f4d6"}.fa-lungs:before{content:"\f604"}.fa-arrow-up-9-1:before,.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-litecoin-sign:before{content:"\e1d3"}.fa-border-none:before{content:"\f850"}.fa-circle-nodes:before{content:"\e4e2"}.fa-parachute-box:before{content:"\f4cd"}.fa-indent:before{content:"\f03c"}.fa-truck-field-un:before{content:"\e58e"}.fa-hourglass-empty:before,.fa-hourglass:before{content:"\f254"}.fa-mountain:before{content:"\f6fc"}.fa-user-doctor:before,.fa-user-md:before{content:"\f0f0"}.fa-circle-info:before,.fa-info-circle:before{content:"\f05a"}.fa-cloud-meatball:before{content:"\f73b"}.fa-camera-alt:before,.fa-camera:before{content:"\f030"}.fa-square-virus:before{content:"\e578"}.fa-meteor:before{content:"\f753"}.fa-car-on:before{content:"\e4dd"}.fa-sleigh:before{content:"\f7cc"}.fa-arrow-down-1-9:before,.fa-sort-numeric-asc:before,.fa-sort-numeric-down:before{content:"\f162"}.fa-hand-holding-droplet:before,.fa-hand-holding-water:before{content:"\f4c1"}.fa-water:before{content:"\f773"}.fa-calendar-check:before{content:"\f274"}.fa-braille:before{content:"\f2a1"}.fa-prescription-bottle-alt:before,.fa-prescription-bottle-medical:before{content:"\f486"}.fa-landmark:before{content:"\f66f"}.fa-truck:before{content:"\f0d1"}.fa-crosshairs:before{content:"\f05b"}.fa-person-cane:before{content:"\e53c"}.fa-tent:before{content:"\e57d"}.fa-vest-patches:before{content:"\e086"}.fa-check-double:before{content:"\f560"}.fa-arrow-down-a-z:before,.fa-sort-alpha-asc:before,.fa-sort-alpha-down:before{content:"\f15d"}.fa-money-bill-wheat:before{content:"\e52a"}.fa-cookie:before{content:"\f563"}.fa-arrow-left-rotate:before,.fa-arrow-rotate-back:before,.fa-arrow-rotate-backward:before,.fa-arrow-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-hard-drive:before,.fa-hdd:before{content:"\f0a0"}.fa-face-grin-squint-tears:before,.fa-grin-squint-tears:before{content:"\f586"}.fa-dumbbell:before{content:"\f44b"}.fa-list-alt:before,.fa-rectangle-list:before{content:"\f022"}.fa-tarp-droplet:before{content:"\e57c"}.fa-house-medical-circle-check:before{content:"\e511"}.fa-person-skiing-nordic:before,.fa-skiing-nordic:before{content:"\f7ca"}.fa-calendar-plus:before{content:"\f271"}.fa-plane-arrival:before{content:"\f5af"}.fa-arrow-alt-circle-left:before,.fa-circle-left:before{content:"\f359"}.fa-subway:before,.fa-train-subway:before{content:"\f239"}.fa-chart-gantt:before{content:"\e0e4"}.fa-indian-rupee-sign:before,.fa-indian-rupee:before,.fa-inr:before{content:"\e1bc"}.fa-crop-alt:before,.fa-crop-simple:before{content:"\f565"}.fa-money-bill-1:before,.fa-money-bill-alt:before{content:"\f3d1"}.fa-left-long:before,.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-dna:before{content:"\f471"}.fa-virus-slash:before{content:"\e075"}.fa-minus:before,.fa-subtract:before{content:"\f068"}.fa-chess:before{content:"\f439"}.fa-arrow-left-long:before,.fa-long-arrow-left:before{content:"\f177"}.fa-plug-circle-check:before{content:"\e55c"}.fa-street-view:before{content:"\f21d"}.fa-franc-sign:before{content:"\e18f"}.fa-volume-off:before{content:"\f026"}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before,.fa-hands-american-sign-language-interpreting:before,.fa-hands-asl-interpreting:before{content:"\f2a3"}.fa-cog:before,.fa-gear:before{content:"\f013"}.fa-droplet-slash:before,.fa-tint-slash:before{content:"\f5c7"}.fa-mosque:before{content:"\f678"}.fa-mosquito:before{content:"\e52b"}.fa-star-of-david:before{content:"\f69a"}.fa-person-military-rifle:before{content:"\e54b"}.fa-cart-shopping:before,.fa-shopping-cart:before{content:"\f07a"}.fa-vials:before{content:"\f493"}.fa-plug-circle-plus:before{content:"\e55f"}.fa-place-of-worship:before{content:"\f67f"}.fa-grip-vertical:before{content:"\f58e"}.fa-arrow-turn-up:before,.fa-level-up:before{content:"\f148"}.fa-u:before{content:"\55"}.fa-square-root-alt:before,.fa-square-root-variable:before{content:"\f698"}.fa-clock-four:before,.fa-clock:before{content:"\f017"}.fa-backward-step:before,.fa-step-backward:before{content:"\f048"}.fa-pallet:before{content:"\f482"}.fa-faucet:before{content:"\e005"}.fa-baseball-bat-ball:before{content:"\f432"}.fa-s:before{content:"\53"}.fa-timeline:before{content:"\e29c"}.fa-keyboard:before{content:"\f11c"}.fa-caret-down:before{content:"\f0d7"}.fa-clinic-medical:before,.fa-house-chimney-medical:before{content:"\f7f2"}.fa-temperature-3:before,.fa-temperature-three-quarters:before,.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-mobile-android-alt:before,.fa-mobile-screen:before{content:"\f3cf"}.fa-plane-up:before{content:"\e22d"}.fa-piggy-bank:before{content:"\f4d3"}.fa-battery-3:before,.fa-battery-half:before{content:"\f242"}.fa-mountain-city:before{content:"\e52e"}.fa-coins:before{content:"\f51e"}.fa-khanda:before{content:"\f66d"}.fa-sliders-h:before,.fa-sliders:before{content:"\f1de"}.fa-folder-tree:before{content:"\f802"}.fa-network-wired:before{content:"\f6ff"}.fa-map-pin:before{content:"\f276"}.fa-hamsa:before{content:"\f665"}.fa-cent-sign:before{content:"\e3f5"}.fa-flask:before{content:"\f0c3"}.fa-person-pregnant:before{content:"\e31e"}.fa-wand-sparkles:before{content:"\f72b"}.fa-ellipsis-v:before,.fa-ellipsis-vertical:before{content:"\f142"}.fa-ticket:before{content:"\f145"}.fa-power-off:before{content:"\f011"}.fa-long-arrow-alt-right:before,.fa-right-long:before{content:"\f30b"}.fa-flag-usa:before{content:"\f74d"}.fa-laptop-file:before{content:"\e51d"}.fa-teletype:before,.fa-tty:before{content:"\f1e4"}.fa-diagram-next:before{content:"\e476"}.fa-person-rifle:before{content:"\e54e"}.fa-house-medical-circle-exclamation:before{content:"\e512"}.fa-closed-captioning:before{content:"\f20a"}.fa-hiking:before,.fa-person-hiking:before{content:"\f6ec"}.fa-venus-double:before{content:"\f226"}.fa-images:before{content:"\f302"}.fa-calculator:before{content:"\f1ec"}.fa-people-pulling:before{content:"\e535"}.fa-n:before{content:"\4e"}.fa-cable-car:before,.fa-tram:before{content:"\f7da"}.fa-cloud-rain:before{content:"\f73d"}.fa-building-circle-xmark:before{content:"\e4d4"}.fa-ship:before{content:"\f21a"}.fa-arrows-down-to-line:before{content:"\e4b8"}.fa-download:before{content:"\f019"}.fa-face-grin:before,.fa-grin:before{content:"\f580"}.fa-backspace:before,.fa-delete-left:before{content:"\f55a"}.fa-eye-dropper-empty:before,.fa-eye-dropper:before,.fa-eyedropper:before{content:"\f1fb"}.fa-file-circle-check:before{content:"\e5a0"}.fa-forward:before{content:"\f04e"}.fa-mobile-android:before,.fa-mobile-phone:before,.fa-mobile:before{content:"\f3ce"}.fa-face-meh:before,.fa-meh:before{content:"\f11a"}.fa-align-center:before{content:"\f037"}.fa-book-dead:before,.fa-book-skull:before{content:"\f6b7"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-heart-circle-exclamation:before{content:"\e4fe"}.fa-home-alt:before,.fa-home-lg-alt:before,.fa-home:before,.fa-house:before{content:"\f015"}.fa-calendar-week:before{content:"\f784"}.fa-laptop-medical:before{content:"\f812"}.fa-b:before{content:"\42"}.fa-file-medical:before{content:"\f477"}.fa-dice-one:before{content:"\f525"}.fa-kiwi-bird:before{content:"\f535"}.fa-arrow-right-arrow-left:before,.fa-exchange:before{content:"\f0ec"}.fa-redo-alt:before,.fa-rotate-forward:before,.fa-rotate-right:before{content:"\f2f9"}.fa-cutlery:before,.fa-utensils:before{content:"\f2e7"}.fa-arrow-up-wide-short:before,.fa-sort-amount-up:before{content:"\f161"}.fa-mill-sign:before{content:"\e1ed"}.fa-bowl-rice:before{content:"\e2eb"}.fa-skull:before{content:"\f54c"}.fa-broadcast-tower:before,.fa-tower-broadcast:before{content:"\f519"}.fa-truck-pickup:before{content:"\f63c"}.fa-long-arrow-alt-up:before,.fa-up-long:before{content:"\f30c"}.fa-stop:before{content:"\f04d"}.fa-code-merge:before{content:"\f387"}.fa-upload:before{content:"\f093"}.fa-hurricane:before{content:"\f751"}.fa-mound:before{content:"\e52d"}.fa-toilet-portable:before{content:"\e583"}.fa-compact-disc:before{content:"\f51f"}.fa-file-arrow-down:before,.fa-file-download:before{content:"\f56d"}.fa-caravan:before{content:"\f8ff"}.fa-shield-cat:before{content:"\e572"}.fa-bolt:before,.fa-zap:before{content:"\f0e7"}.fa-glass-water:before{content:"\e4f4"}.fa-oil-well:before{content:"\e532"}.fa-vault:before{content:"\e2c5"}.fa-mars:before{content:"\f222"}.fa-toilet:before{content:"\f7d8"}.fa-plane-circle-xmark:before{content:"\e557"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen-sign:before,.fa-yen:before{content:"\f157"}.fa-rouble:before,.fa-rub:before,.fa-ruble-sign:before,.fa-ruble:before{content:"\f158"}.fa-sun:before{content:"\f185"}.fa-guitar:before{content:"\f7a6"}.fa-face-laugh-wink:before,.fa-laugh-wink:before{content:"\f59c"}.fa-horse-head:before{content:"\f7ab"}.fa-bore-hole:before{content:"\e4c3"}.fa-industry:before{content:"\f275"}.fa-arrow-alt-circle-down:before,.fa-circle-down:before{content:"\f358"}.fa-arrows-turn-to-dots:before{content:"\e4c1"}.fa-florin-sign:before{content:"\e184"}.fa-arrow-down-short-wide:before,.fa-sort-amount-desc:before,.fa-sort-amount-down-alt:before{content:"\f884"}.fa-less-than:before{content:"\3c"}.fa-angle-down:before{content:"\f107"}.fa-car-tunnel:before{content:"\e4de"}.fa-head-side-cough:before{content:"\e061"}.fa-grip-lines:before{content:"\f7a4"}.fa-thumbs-down:before{content:"\f165"}.fa-user-lock:before{content:"\f502"}.fa-arrow-right-long:before,.fa-long-arrow-right:before{content:"\f178"}.fa-anchor-circle-xmark:before{content:"\e4ac"}.fa-ellipsis-h:before,.fa-ellipsis:before{content:"\f141"}.fa-chess-pawn:before{content:"\f443"}.fa-first-aid:before,.fa-kit-medical:before{content:"\f479"}.fa-person-through-window:before{content:"\e5a9"}.fa-toolbox:before{content:"\f552"}.fa-hands-holding-circle:before{content:"\e4fb"}.fa-bug:before{content:"\f188"}.fa-credit-card-alt:before,.fa-credit-card:before{content:"\f09d"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-hand-holding-hand:before{content:"\e4f7"}.fa-book-open-reader:before,.fa-book-reader:before{content:"\f5da"}.fa-mountain-sun:before{content:"\e52f"}.fa-arrows-left-right-to-line:before{content:"\e4ba"}.fa-dice-d20:before{content:"\f6cf"}.fa-truck-droplet:before{content:"\e58c"}.fa-file-circle-xmark:before{content:"\e5a1"}.fa-temperature-arrow-up:before,.fa-temperature-up:before{content:"\e040"}.fa-medal:before{content:"\f5a2"}.fa-bed:before{content:"\f236"}.fa-h-square:before,.fa-square-h:before{content:"\f0fd"}.fa-podcast:before{content:"\f2ce"}.fa-temperature-4:before,.fa-temperature-full:before,.fa-thermometer-4:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-bell:before{content:"\f0f3"}.fa-superscript:before{content:"\f12b"}.fa-plug-circle-xmark:before{content:"\e560"}.fa-star-of-life:before{content:"\f621"}.fa-phone-slash:before{content:"\f3dd"}.fa-paint-roller:before{content:"\f5aa"}.fa-hands-helping:before,.fa-handshake-angle:before{content:"\f4c4"}.fa-location-dot:before,.fa-map-marker-alt:before{content:"\f3c5"}.fa-file:before{content:"\f15b"}.fa-greater-than:before{content:"\3e"}.fa-person-swimming:before,.fa-swimmer:before{content:"\f5c4"}.fa-arrow-down:before{content:"\f063"}.fa-droplet:before,.fa-tint:before{content:"\f043"}.fa-eraser:before{content:"\f12d"}.fa-earth-america:before,.fa-earth-americas:before,.fa-earth:before,.fa-globe-americas:before{content:"\f57d"}.fa-person-burst:before{content:"\e53b"}.fa-dove:before{content:"\f4ba"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-socks:before{content:"\f696"}.fa-inbox:before{content:"\f01c"}.fa-section:before{content:"\e447"}.fa-gauge-high:before,.fa-tachometer-alt-fast:before,.fa-tachometer-alt:before{content:"\f625"}.fa-envelope-open-text:before{content:"\f658"}.fa-hospital-alt:before,.fa-hospital-wide:before,.fa-hospital:before{content:"\f0f8"}.fa-wine-bottle:before{content:"\f72f"}.fa-chess-rook:before{content:"\f447"}.fa-bars-staggered:before,.fa-reorder:before,.fa-stream:before{content:"\f550"}.fa-dharmachakra:before{content:"\f655"}.fa-hotdog:before{content:"\f80f"}.fa-blind:before,.fa-person-walking-with-cane:before{content:"\f29d"}.fa-drum:before{content:"\f569"}.fa-ice-cream:before{content:"\f810"}.fa-heart-circle-bolt:before{content:"\e4fc"}.fa-fax:before{content:"\f1ac"}.fa-paragraph:before{content:"\f1dd"}.fa-check-to-slot:before,.fa-vote-yea:before{content:"\f772"}.fa-star-half:before{content:"\f089"}.fa-boxes-alt:before,.fa-boxes-stacked:before,.fa-boxes:before{content:"\f468"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-assistive-listening-systems:before,.fa-ear-listen:before{content:"\f2a2"}.fa-tree-city:before{content:"\e587"}.fa-play:before{content:"\f04b"}.fa-font:before{content:"\f031"}.fa-table-cells-row-lock:before{content:"\e67a"}.fa-rupiah-sign:before{content:"\e23d"}.fa-magnifying-glass:before,.fa-search:before{content:"\f002"}.fa-ping-pong-paddle-ball:before,.fa-table-tennis-paddle-ball:before,.fa-table-tennis:before{content:"\f45d"}.fa-diagnoses:before,.fa-person-dots-from-line:before{content:"\f470"}.fa-trash-can-arrow-up:before,.fa-trash-restore-alt:before{content:"\f82a"}.fa-naira-sign:before{content:"\e1f6"}.fa-cart-arrow-down:before{content:"\f218"}.fa-walkie-talkie:before{content:"\f8ef"}.fa-file-edit:before,.fa-file-pen:before{content:"\f31c"}.fa-receipt:before{content:"\f543"}.fa-pen-square:before,.fa-pencil-square:before,.fa-square-pen:before{content:"\f14b"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-person-circle-exclamation:before{content:"\e53f"}.fa-chevron-down:before{content:"\f078"}.fa-battery-5:before,.fa-battery-full:before,.fa-battery:before{content:"\f240"}.fa-skull-crossbones:before{content:"\f714"}.fa-code-compare:before{content:"\e13a"}.fa-list-dots:before,.fa-list-ul:before{content:"\f0ca"}.fa-school-lock:before{content:"\e56f"}.fa-tower-cell:before{content:"\e585"}.fa-down-long:before,.fa-long-arrow-alt-down:before{content:"\f309"}.fa-ranking-star:before{content:"\e561"}.fa-chess-king:before{content:"\f43f"}.fa-person-harassing:before{content:"\e549"}.fa-brazilian-real-sign:before{content:"\e46c"}.fa-landmark-alt:before,.fa-landmark-dome:before{content:"\f752"}.fa-arrow-up:before{content:"\f062"}.fa-television:before,.fa-tv-alt:before,.fa-tv:before{content:"\f26c"}.fa-shrimp:before{content:"\e448"}.fa-list-check:before,.fa-tasks:before{content:"\f0ae"}.fa-jug-detergent:before{content:"\e519"}.fa-circle-user:before,.fa-user-circle:before{content:"\f2bd"}.fa-user-shield:before{content:"\f505"}.fa-wind:before{content:"\f72e"}.fa-car-burst:before,.fa-car-crash:before{content:"\f5e1"}.fa-y:before{content:"\59"}.fa-person-snowboarding:before,.fa-snowboarding:before{content:"\f7ce"}.fa-shipping-fast:before,.fa-truck-fast:before{content:"\f48b"}.fa-fish:before{content:"\f578"}.fa-user-graduate:before{content:"\f501"}.fa-adjust:before,.fa-circle-half-stroke:before{content:"\f042"}.fa-clapperboard:before{content:"\e131"}.fa-circle-radiation:before,.fa-radiation-alt:before{content:"\f7ba"}.fa-baseball-ball:before,.fa-baseball:before{content:"\f433"}.fa-jet-fighter-up:before{content:"\e518"}.fa-diagram-project:before,.fa-project-diagram:before{content:"\f542"}.fa-copy:before{content:"\f0c5"}.fa-volume-mute:before,.fa-volume-times:before,.fa-volume-xmark:before{content:"\f6a9"}.fa-hand-sparkles:before{content:"\e05d"}.fa-grip-horizontal:before,.fa-grip:before{content:"\f58d"}.fa-share-from-square:before,.fa-share-square:before{content:"\f14d"}.fa-child-combatant:before,.fa-child-rifle:before{content:"\e4e0"}.fa-gun:before{content:"\e19b"}.fa-phone-square:before,.fa-square-phone:before{content:"\f098"}.fa-add:before,.fa-plus:before{content:"\2b"}.fa-expand:before{content:"\f065"}.fa-computer:before{content:"\e4e5"}.fa-close:before,.fa-multiply:before,.fa-remove:before,.fa-times:before,.fa-xmark:before{content:"\f00d"}.fa-arrows-up-down-left-right:before,.fa-arrows:before{content:"\f047"}.fa-chalkboard-teacher:before,.fa-chalkboard-user:before{content:"\f51c"}.fa-peso-sign:before{content:"\e222"}.fa-building-shield:before{content:"\e4d8"}.fa-baby:before{content:"\f77c"}.fa-users-line:before{content:"\e592"}.fa-quote-left-alt:before,.fa-quote-left:before{content:"\f10d"}.fa-tractor:before{content:"\f722"}.fa-trash-arrow-up:before,.fa-trash-restore:before{content:"\f829"}.fa-arrow-down-up-lock:before{content:"\e4b0"}.fa-lines-leaning:before{content:"\e51e"}.fa-ruler-combined:before{content:"\f546"}.fa-copyright:before{content:"\f1f9"}.fa-equals:before{content:"\3d"}.fa-blender:before{content:"\f517"}.fa-teeth:before{content:"\f62e"}.fa-ils:before,.fa-shekel-sign:before,.fa-shekel:before,.fa-sheqel-sign:before,.fa-sheqel:before{content:"\f20b"}.fa-map:before{content:"\f279"}.fa-rocket:before{content:"\f135"}.fa-photo-film:before,.fa-photo-video:before{content:"\f87c"}.fa-folder-minus:before{content:"\f65d"}.fa-store:before{content:"\f54e"}.fa-arrow-trend-up:before{content:"\e098"}.fa-plug-circle-minus:before{content:"\e55e"}.fa-sign-hanging:before,.fa-sign:before{content:"\f4d9"}.fa-bezier-curve:before{content:"\f55b"}.fa-bell-slash:before{content:"\f1f6"}.fa-tablet-android:before,.fa-tablet:before{content:"\f3fb"}.fa-school-flag:before{content:"\e56e"}.fa-fill:before{content:"\f575"}.fa-angle-up:before{content:"\f106"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-holly-berry:before{content:"\f7aa"}.fa-chevron-left:before{content:"\f053"}.fa-bacteria:before{content:"\e059"}.fa-hand-lizard:before{content:"\f258"}.fa-notdef:before{content:"\e1fe"}.fa-disease:before{content:"\f7fa"}.fa-briefcase-medical:before{content:"\f469"}.fa-genderless:before{content:"\f22d"}.fa-chevron-right:before{content:"\f054"}.fa-retweet:before{content:"\f079"}.fa-car-alt:before,.fa-car-rear:before{content:"\f5de"}.fa-pump-soap:before{content:"\e06b"}.fa-video-slash:before{content:"\f4e2"}.fa-battery-2:before,.fa-battery-quarter:before{content:"\f243"}.fa-radio:before{content:"\f8d7"}.fa-baby-carriage:before,.fa-carriage-baby:before{content:"\f77d"}.fa-traffic-light:before{content:"\f637"}.fa-thermometer:before{content:"\f491"}.fa-vr-cardboard:before{content:"\f729"}.fa-hand-middle-finger:before{content:"\f806"}.fa-percent:before,.fa-percentage:before{content:"\25"}.fa-truck-moving:before{content:"\f4df"}.fa-glass-water-droplet:before{content:"\e4f5"}.fa-display:before{content:"\e163"}.fa-face-smile:before,.fa-smile:before{content:"\f118"}.fa-thumb-tack:before,.fa-thumbtack:before{content:"\f08d"}.fa-trophy:before{content:"\f091"}.fa-person-praying:before,.fa-pray:before{content:"\f683"}.fa-hammer:before{content:"\f6e3"}.fa-hand-peace:before{content:"\f25b"}.fa-rotate:before,.fa-sync-alt:before{content:"\f2f1"}.fa-spinner:before{content:"\f110"}.fa-robot:before{content:"\f544"}.fa-peace:before{content:"\f67c"}.fa-cogs:before,.fa-gears:before{content:"\f085"}.fa-warehouse:before{content:"\f494"}.fa-arrow-up-right-dots:before{content:"\e4b7"}.fa-splotch:before{content:"\f5bc"}.fa-face-grin-hearts:before,.fa-grin-hearts:before{content:"\f584"}.fa-dice-four:before{content:"\f524"}.fa-sim-card:before{content:"\f7c4"}.fa-transgender-alt:before,.fa-transgender:before{content:"\f225"}.fa-mercury:before{content:"\f223"}.fa-arrow-turn-down:before,.fa-level-down:before{content:"\f149"}.fa-person-falling-burst:before{content:"\e547"}.fa-award:before{content:"\f559"}.fa-ticket-alt:before,.fa-ticket-simple:before{content:"\f3ff"}.fa-building:before{content:"\f1ad"}.fa-angle-double-left:before,.fa-angles-left:before{content:"\f100"}.fa-qrcode:before{content:"\f029"}.fa-clock-rotate-left:before,.fa-history:before{content:"\f1da"}.fa-face-grin-beam-sweat:before,.fa-grin-beam-sweat:before{content:"\f583"}.fa-arrow-right-from-file:before,.fa-file-export:before{content:"\f56e"}.fa-shield-blank:before,.fa-shield:before{content:"\f132"}.fa-arrow-up-short-wide:before,.fa-sort-amount-up-alt:before{content:"\f885"}.fa-house-medical:before{content:"\e3b2"}.fa-golf-ball-tee:before,.fa-golf-ball:before{content:"\f450"}.fa-chevron-circle-left:before,.fa-circle-chevron-left:before{content:"\f137"}.fa-house-chimney-window:before{content:"\e00d"}.fa-pen-nib:before{content:"\f5ad"}.fa-tent-arrow-turn-left:before{content:"\e580"}.fa-tents:before{content:"\e582"}.fa-magic:before,.fa-wand-magic:before{content:"\f0d0"}.fa-dog:before{content:"\f6d3"}.fa-carrot:before{content:"\f787"}.fa-moon:before{content:"\f186"}.fa-wine-glass-alt:before,.fa-wine-glass-empty:before{content:"\f5ce"}.fa-cheese:before{content:"\f7ef"}.fa-yin-yang:before{content:"\f6ad"}.fa-music:before{content:"\f001"}.fa-code-commit:before{content:"\f386"}.fa-temperature-low:before{content:"\f76b"}.fa-biking:before,.fa-person-biking:before{content:"\f84a"}.fa-broom:before{content:"\f51a"}.fa-shield-heart:before{content:"\e574"}.fa-gopuram:before{content:"\f664"}.fa-earth-oceania:before,.fa-globe-oceania:before{content:"\e47b"}.fa-square-xmark:before,.fa-times-square:before,.fa-xmark-square:before{content:"\f2d3"}.fa-hashtag:before{content:"\23"}.fa-expand-alt:before,.fa-up-right-and-down-left-from-center:before{content:"\f424"}.fa-oil-can:before{content:"\f613"}.fa-t:before{content:"\54"}.fa-hippo:before{content:"\f6ed"}.fa-chart-column:before{content:"\e0e3"}.fa-infinity:before{content:"\f534"}.fa-vial-circle-check:before{content:"\e596"}.fa-person-arrow-down-to-line:before{content:"\e538"}.fa-voicemail:before{content:"\f897"}.fa-fan:before{content:"\f863"}.fa-person-walking-luggage:before{content:"\e554"}.fa-arrows-alt-v:before,.fa-up-down:before{content:"\f338"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-calendar:before{content:"\f133"}.fa-trailer:before{content:"\e041"}.fa-bahai:before,.fa-haykal:before{content:"\f666"}.fa-sd-card:before{content:"\f7c2"}.fa-dragon:before{content:"\f6d5"}.fa-shoe-prints:before{content:"\f54b"}.fa-circle-plus:before,.fa-plus-circle:before{content:"\f055"}.fa-face-grin-tongue-wink:before,.fa-grin-tongue-wink:before{content:"\f58b"}.fa-hand-holding:before{content:"\f4bd"}.fa-plug-circle-exclamation:before{content:"\e55d"}.fa-chain-broken:before,.fa-chain-slash:before,.fa-link-slash:before,.fa-unlink:before{content:"\f127"}.fa-clone:before{content:"\f24d"}.fa-person-walking-arrow-loop-left:before{content:"\e551"}.fa-arrow-up-z-a:before,.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-fire-alt:before,.fa-fire-flame-curved:before{content:"\f7e4"}.fa-tornado:before{content:"\f76f"}.fa-file-circle-plus:before{content:"\e494"}.fa-book-quran:before,.fa-quran:before{content:"\f687"}.fa-anchor:before{content:"\f13d"}.fa-border-all:before{content:"\f84c"}.fa-angry:before,.fa-face-angry:before{content:"\f556"}.fa-cookie-bite:before{content:"\f564"}.fa-arrow-trend-down:before{content:"\e097"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-draw-polygon:before{content:"\f5ee"}.fa-balance-scale:before,.fa-scale-balanced:before{content:"\f24e"}.fa-gauge-simple-high:before,.fa-tachometer-fast:before,.fa-tachometer:before{content:"\f62a"}.fa-shower:before{content:"\f2cc"}.fa-desktop-alt:before,.fa-desktop:before{content:"\f390"}.fa-m:before{content:"\4d"}.fa-table-list:before,.fa-th-list:before{content:"\f00b"}.fa-comment-sms:before,.fa-sms:before{content:"\f7cd"}.fa-book:before{content:"\f02d"}.fa-user-plus:before{content:"\f234"}.fa-check:before{content:"\f00c"}.fa-battery-4:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-house-circle-check:before{content:"\e509"}.fa-angle-left:before{content:"\f104"}.fa-diagram-successor:before{content:"\e47a"}.fa-truck-arrow-right:before{content:"\e58b"}.fa-arrows-split-up-and-left:before{content:"\e4bc"}.fa-fist-raised:before,.fa-hand-fist:before{content:"\f6de"}.fa-cloud-moon:before{content:"\f6c3"}.fa-briefcase:before{content:"\f0b1"}.fa-person-falling:before{content:"\e546"}.fa-image-portrait:before,.fa-portrait:before{content:"\f3e0"}.fa-user-tag:before{content:"\f507"}.fa-rug:before{content:"\e569"}.fa-earth-europe:before,.fa-globe-europe:before{content:"\f7a2"}.fa-cart-flatbed-suitcase:before,.fa-luggage-cart:before{content:"\f59d"}.fa-rectangle-times:before,.fa-rectangle-xmark:before,.fa-times-rectangle:before,.fa-window-close:before{content:"\f410"}.fa-baht-sign:before{content:"\e0ac"}.fa-book-open:before{content:"\f518"}.fa-book-journal-whills:before,.fa-journal-whills:before{content:"\f66a"}.fa-handcuffs:before{content:"\e4f8"}.fa-exclamation-triangle:before,.fa-triangle-exclamation:before,.fa-warning:before{content:"\f071"}.fa-database:before{content:"\f1c0"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-bottle-droplet:before{content:"\e4c4"}.fa-mask-face:before{content:"\e1d7"}.fa-hill-rockslide:before{content:"\e508"}.fa-exchange-alt:before,.fa-right-left:before{content:"\f362"}.fa-paper-plane:before{content:"\f1d8"}.fa-road-circle-exclamation:before{content:"\e565"}.fa-dungeon:before{content:"\f6d9"}.fa-align-right:before{content:"\f038"}.fa-money-bill-1-wave:before,.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-life-ring:before{content:"\f1cd"}.fa-hands:before,.fa-sign-language:before,.fa-signing:before{content:"\f2a7"}.fa-calendar-day:before{content:"\f783"}.fa-ladder-water:before,.fa-swimming-pool:before,.fa-water-ladder:before{content:"\f5c5"}.fa-arrows-up-down:before,.fa-arrows-v:before{content:"\f07d"}.fa-face-grimace:before,.fa-grimace:before{content:"\f57f"}.fa-wheelchair-alt:before,.fa-wheelchair-move:before{content:"\e2ce"}.fa-level-down-alt:before,.fa-turn-down:before{content:"\f3be"}.fa-person-walking-arrow-right:before{content:"\e552"}.fa-envelope-square:before,.fa-square-envelope:before{content:"\f199"}.fa-dice:before{content:"\f522"}.fa-bowling-ball:before{content:"\f436"}.fa-brain:before{content:"\f5dc"}.fa-band-aid:before,.fa-bandage:before{content:"\f462"}.fa-calendar-minus:before{content:"\f272"}.fa-circle-xmark:before,.fa-times-circle:before,.fa-xmark-circle:before{content:"\f057"}.fa-gifts:before{content:"\f79c"}.fa-hotel:before{content:"\f594"}.fa-earth-asia:before,.fa-globe-asia:before{content:"\f57e"}.fa-id-card-alt:before,.fa-id-card-clip:before{content:"\f47f"}.fa-magnifying-glass-plus:before,.fa-search-plus:before{content:"\f00e"}.fa-thumbs-up:before{content:"\f164"}.fa-user-clock:before{content:"\f4fd"}.fa-allergies:before,.fa-hand-dots:before{content:"\f461"}.fa-file-invoice:before{content:"\f570"}.fa-window-minimize:before{content:"\f2d1"}.fa-coffee:before,.fa-mug-saucer:before{content:"\f0f4"}.fa-brush:before{content:"\f55d"}.fa-mask:before{content:"\f6fa"}.fa-magnifying-glass-minus:before,.fa-search-minus:before{content:"\f010"}.fa-ruler-vertical:before{content:"\f548"}.fa-user-alt:before,.fa-user-large:before{content:"\f406"}.fa-train-tram:before{content:"\e5b4"}.fa-user-nurse:before{content:"\f82f"}.fa-syringe:before{content:"\f48e"}.fa-cloud-sun:before{content:"\f6c4"}.fa-stopwatch-20:before{content:"\e06f"}.fa-square-full:before{content:"\f45c"}.fa-magnet:before{content:"\f076"}.fa-jar:before{content:"\e516"}.fa-note-sticky:before,.fa-sticky-note:before{content:"\f249"}.fa-bug-slash:before{content:"\e490"}.fa-arrow-up-from-water-pump:before{content:"\e4b6"}.fa-bone:before{content:"\f5d7"}.fa-user-injured:before{content:"\f728"}.fa-face-sad-tear:before,.fa-sad-tear:before{content:"\f5b4"}.fa-plane:before{content:"\f072"}.fa-tent-arrows-down:before{content:"\e581"}.fa-exclamation:before{content:"\21"}.fa-arrows-spin:before{content:"\e4bb"}.fa-print:before{content:"\f02f"}.fa-try:before,.fa-turkish-lira-sign:before,.fa-turkish-lira:before{content:"\e2bb"}.fa-dollar-sign:before,.fa-dollar:before,.fa-usd:before{content:"\24"}.fa-x:before{content:"\58"}.fa-magnifying-glass-dollar:before,.fa-search-dollar:before{content:"\f688"}.fa-users-cog:before,.fa-users-gear:before{content:"\f509"}.fa-person-military-pointing:before{content:"\e54a"}.fa-bank:before,.fa-building-columns:before,.fa-institution:before,.fa-museum:before,.fa-university:before{content:"\f19c"}.fa-umbrella:before{content:"\f0e9"}.fa-trowel:before{content:"\e589"}.fa-d:before{content:"\44"}.fa-stapler:before{content:"\e5af"}.fa-masks-theater:before,.fa-theater-masks:before{content:"\f630"}.fa-kip-sign:before{content:"\e1c4"}.fa-hand-point-left:before{content:"\f0a5"}.fa-handshake-alt:before,.fa-handshake-simple:before{content:"\f4c6"}.fa-fighter-jet:before,.fa-jet-fighter:before{content:"\f0fb"}.fa-share-alt-square:before,.fa-square-share-nodes:before{content:"\f1e1"}.fa-barcode:before{content:"\f02a"}.fa-plus-minus:before{content:"\e43c"}.fa-video-camera:before,.fa-video:before{content:"\f03d"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\f19d"}.fa-hand-holding-medical:before{content:"\e05c"}.fa-person-circle-check:before{content:"\e53e"}.fa-level-up-alt:before,.fa-turn-up:before{content:"\f3bf"} +.fa-sr-only,.fa-sr-only-focusable:not(:focus),.sr-only,.sr-only-focusable:not(:focus){position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}:host,:root{--fa-style-family-brands:"Font Awesome 6 Brands";--fa-font-brands:normal 400 1em/1 "Font Awesome 6 Brands"}@font-face{font-family:"Font Awesome 6 Brands";font-style:normal;font-weight:400;font-display:block;src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }.fa-brands,.fab{font-weight:400}.fa-monero:before{content:"\f3d0"}.fa-hooli:before{content:"\f427"}.fa-yelp:before{content:"\f1e9"}.fa-cc-visa:before{content:"\f1f0"}.fa-lastfm:before{content:"\f202"}.fa-shopware:before{content:"\f5b5"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-aws:before{content:"\f375"}.fa-redhat:before{content:"\f7bc"}.fa-yoast:before{content:"\f2b1"}.fa-cloudflare:before{content:"\e07d"}.fa-ups:before{content:"\f7e0"}.fa-pixiv:before{content:"\e640"}.fa-wpexplorer:before{content:"\f2de"}.fa-dyalog:before{content:"\f399"}.fa-bity:before{content:"\f37a"}.fa-stackpath:before{content:"\f842"}.fa-buysellads:before{content:"\f20d"}.fa-first-order:before{content:"\f2b0"}.fa-modx:before{content:"\f285"}.fa-guilded:before{content:"\e07e"}.fa-vnv:before{content:"\f40b"}.fa-js-square:before,.fa-square-js:before{content:"\f3b9"}.fa-microsoft:before{content:"\f3ca"}.fa-qq:before{content:"\f1d6"}.fa-orcid:before{content:"\f8d2"}.fa-java:before{content:"\f4e4"}.fa-invision:before{content:"\f7b0"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-centercode:before{content:"\f380"}.fa-glide-g:before{content:"\f2a6"}.fa-drupal:before{content:"\f1a9"}.fa-jxl:before{content:"\e67b"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-unity:before{content:"\e049"}.fa-whmcs:before{content:"\f40d"}.fa-rocketchat:before{content:"\f3e8"}.fa-vk:before{content:"\f189"}.fa-untappd:before{content:"\f405"}.fa-mailchimp:before{content:"\f59e"}.fa-css3-alt:before{content:"\f38b"}.fa-reddit-square:before,.fa-square-reddit:before{content:"\f1a2"}.fa-vimeo-v:before{content:"\f27d"}.fa-contao:before{content:"\f26d"}.fa-square-font-awesome:before{content:"\e5ad"}.fa-deskpro:before{content:"\f38f"}.fa-brave:before{content:"\e63c"}.fa-sistrix:before{content:"\f3ee"}.fa-instagram-square:before,.fa-square-instagram:before{content:"\e055"}.fa-battle-net:before{content:"\f835"}.fa-the-red-yeti:before{content:"\f69d"}.fa-hacker-news-square:before,.fa-square-hacker-news:before{content:"\f3af"}.fa-edge:before{content:"\f282"}.fa-threads:before{content:"\e618"}.fa-napster:before{content:"\f3d2"}.fa-snapchat-square:before,.fa-square-snapchat:before{content:"\f2ad"}.fa-google-plus-g:before{content:"\f0d5"}.fa-artstation:before{content:"\f77a"}.fa-markdown:before{content:"\f60f"}.fa-sourcetree:before{content:"\f7d3"}.fa-google-plus:before{content:"\f2b3"}.fa-diaspora:before{content:"\f791"}.fa-foursquare:before{content:"\f180"}.fa-stack-overflow:before{content:"\f16c"}.fa-github-alt:before{content:"\f113"}.fa-phoenix-squadron:before{content:"\f511"}.fa-pagelines:before{content:"\f18c"}.fa-algolia:before{content:"\f36c"}.fa-red-river:before{content:"\f3e3"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-safari:before{content:"\f267"}.fa-google:before{content:"\f1a0"}.fa-font-awesome-alt:before,.fa-square-font-awesome-stroke:before{content:"\f35c"}.fa-atlassian:before{content:"\f77b"}.fa-linkedin-in:before{content:"\f0e1"}.fa-digital-ocean:before{content:"\f391"}.fa-nimblr:before{content:"\f5a8"}.fa-chromecast:before{content:"\f838"}.fa-evernote:before{content:"\f839"}.fa-hacker-news:before{content:"\f1d4"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-adversal:before{content:"\f36a"}.fa-creative-commons:before{content:"\f25e"}.fa-watchman-monitoring:before{content:"\e087"}.fa-fonticons:before{content:"\f280"}.fa-weixin:before{content:"\f1d7"}.fa-shirtsinbulk:before{content:"\f214"}.fa-codepen:before{content:"\f1cb"}.fa-git-alt:before{content:"\f841"}.fa-lyft:before{content:"\f3c3"}.fa-rev:before{content:"\f5b2"}.fa-windows:before{content:"\f17a"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-square-viadeo:before,.fa-viadeo-square:before{content:"\f2aa"}.fa-meetup:before{content:"\f2e0"}.fa-centos:before{content:"\f789"}.fa-adn:before{content:"\f170"}.fa-cloudsmith:before{content:"\f384"}.fa-opensuse:before{content:"\e62b"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-dribbble-square:before,.fa-square-dribbble:before{content:"\f397"}.fa-codiepie:before{content:"\f284"}.fa-node:before{content:"\f419"}.fa-mix:before{content:"\f3cb"}.fa-steam:before{content:"\f1b6"}.fa-cc-apple-pay:before{content:"\f416"}.fa-scribd:before{content:"\f28a"}.fa-debian:before{content:"\e60b"}.fa-openid:before{content:"\f19b"}.fa-instalod:before{content:"\e081"}.fa-expeditedssl:before{content:"\f23e"}.fa-sellcast:before{content:"\f2da"}.fa-square-twitter:before,.fa-twitter-square:before{content:"\f081"}.fa-r-project:before{content:"\f4f7"}.fa-delicious:before{content:"\f1a5"}.fa-freebsd:before{content:"\f3a4"}.fa-vuejs:before{content:"\f41f"}.fa-accusoft:before{content:"\f369"}.fa-ioxhost:before{content:"\f208"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-app-store:before{content:"\f36f"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-itunes-note:before{content:"\f3b5"}.fa-golang:before{content:"\e40f"}.fa-kickstarter:before,.fa-square-kickstarter:before{content:"\f3bb"}.fa-grav:before{content:"\f2d6"}.fa-weibo:before{content:"\f18a"}.fa-uncharted:before{content:"\e084"}.fa-firstdraft:before{content:"\f3a1"}.fa-square-youtube:before,.fa-youtube-square:before{content:"\f431"}.fa-wikipedia-w:before{content:"\f266"}.fa-rendact:before,.fa-wpressr:before{content:"\f3e4"}.fa-angellist:before{content:"\f209"}.fa-galactic-republic:before{content:"\f50c"}.fa-nfc-directional:before{content:"\e530"}.fa-skype:before{content:"\f17e"}.fa-joget:before{content:"\f3b7"}.fa-fedora:before{content:"\f798"}.fa-stripe-s:before{content:"\f42a"}.fa-meta:before{content:"\e49b"}.fa-laravel:before{content:"\f3bd"}.fa-hotjar:before{content:"\f3b1"}.fa-bluetooth-b:before{content:"\f294"}.fa-square-letterboxd:before{content:"\e62e"}.fa-sticker-mule:before{content:"\f3f7"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-hips:before{content:"\f452"}.fa-behance:before{content:"\f1b4"}.fa-reddit:before{content:"\f1a1"}.fa-discord:before{content:"\f392"}.fa-chrome:before{content:"\f268"}.fa-app-store-ios:before{content:"\f370"}.fa-cc-discover:before{content:"\f1f2"}.fa-wpbeginner:before{content:"\f297"}.fa-confluence:before{content:"\f78d"}.fa-shoelace:before{content:"\e60c"}.fa-mdb:before{content:"\f8ca"}.fa-dochub:before{content:"\f394"}.fa-accessible-icon:before{content:"\f368"}.fa-ebay:before{content:"\f4f4"}.fa-amazon:before{content:"\f270"}.fa-unsplash:before{content:"\e07c"}.fa-yarn:before{content:"\f7e3"}.fa-square-steam:before,.fa-steam-square:before{content:"\f1b7"}.fa-500px:before{content:"\f26e"}.fa-square-vimeo:before,.fa-vimeo-square:before{content:"\f194"}.fa-asymmetrik:before{content:"\f372"}.fa-font-awesome-flag:before,.fa-font-awesome-logo-full:before,.fa-font-awesome:before{content:"\f2b4"}.fa-gratipay:before{content:"\f184"}.fa-apple:before{content:"\f179"}.fa-hive:before{content:"\e07f"}.fa-gitkraken:before{content:"\f3a6"}.fa-keybase:before{content:"\f4f5"}.fa-apple-pay:before{content:"\f415"}.fa-padlet:before{content:"\e4a0"}.fa-amazon-pay:before{content:"\f42c"}.fa-github-square:before,.fa-square-github:before{content:"\f092"}.fa-stumbleupon:before{content:"\f1a4"}.fa-fedex:before{content:"\f797"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-shopify:before{content:"\e057"}.fa-neos:before{content:"\f612"}.fa-square-threads:before{content:"\e619"}.fa-hackerrank:before{content:"\f5f7"}.fa-researchgate:before{content:"\f4f8"}.fa-swift:before{content:"\f8e1"}.fa-angular:before{content:"\f420"}.fa-speakap:before{content:"\f3f3"}.fa-angrycreative:before{content:"\f36e"}.fa-y-combinator:before{content:"\f23b"}.fa-empire:before{content:"\f1d1"}.fa-envira:before{content:"\f299"}.fa-google-scholar:before{content:"\e63b"}.fa-gitlab-square:before,.fa-square-gitlab:before{content:"\e5ae"}.fa-studiovinari:before{content:"\f3f8"}.fa-pied-piper:before{content:"\f2ae"}.fa-wordpress:before{content:"\f19a"}.fa-product-hunt:before{content:"\f288"}.fa-firefox:before{content:"\f269"}.fa-linode:before{content:"\f2b8"}.fa-goodreads:before{content:"\f3a8"}.fa-odnoklassniki-square:before,.fa-square-odnoklassniki:before{content:"\f264"}.fa-jsfiddle:before{content:"\f1cc"}.fa-sith:before{content:"\f512"}.fa-themeisle:before{content:"\f2b2"}.fa-page4:before{content:"\f3d7"}.fa-hashnode:before{content:"\e499"}.fa-react:before{content:"\f41b"}.fa-cc-paypal:before{content:"\f1f4"}.fa-squarespace:before{content:"\f5be"}.fa-cc-stripe:before{content:"\f1f5"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-bitcoin:before{content:"\f379"}.fa-keycdn:before{content:"\f3ba"}.fa-opera:before{content:"\f26a"}.fa-itch-io:before{content:"\f83a"}.fa-umbraco:before{content:"\f8e8"}.fa-galactic-senate:before{content:"\f50d"}.fa-ubuntu:before{content:"\f7df"}.fa-draft2digital:before{content:"\f396"}.fa-stripe:before{content:"\f429"}.fa-houzz:before{content:"\f27c"}.fa-gg:before{content:"\f260"}.fa-dhl:before{content:"\f790"}.fa-pinterest-square:before,.fa-square-pinterest:before{content:"\f0d3"}.fa-xing:before{content:"\f168"}.fa-blackberry:before{content:"\f37b"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-playstation:before{content:"\f3df"}.fa-quinscape:before{content:"\f459"}.fa-less:before{content:"\f41d"}.fa-blogger-b:before{content:"\f37d"}.fa-opencart:before{content:"\f23d"}.fa-vine:before{content:"\f1ca"}.fa-signal-messenger:before{content:"\e663"}.fa-paypal:before{content:"\f1ed"}.fa-gitlab:before{content:"\f296"}.fa-typo3:before{content:"\f42b"}.fa-reddit-alien:before{content:"\f281"}.fa-yahoo:before{content:"\f19e"}.fa-dailymotion:before{content:"\e052"}.fa-affiliatetheme:before{content:"\f36b"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-bootstrap:before{content:"\f836"}.fa-odnoklassniki:before{content:"\f263"}.fa-nfc-symbol:before{content:"\e531"}.fa-mintbit:before{content:"\e62f"}.fa-ethereum:before{content:"\f42e"}.fa-speaker-deck:before{content:"\f83c"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-patreon:before{content:"\f3d9"}.fa-avianex:before{content:"\f374"}.fa-ello:before{content:"\f5f1"}.fa-gofore:before{content:"\f3a7"}.fa-bimobject:before{content:"\f378"}.fa-brave-reverse:before{content:"\e63d"}.fa-facebook-f:before{content:"\f39e"}.fa-google-plus-square:before,.fa-square-google-plus:before{content:"\f0d4"}.fa-web-awesome:before{content:"\e682"}.fa-mandalorian:before{content:"\f50f"}.fa-first-order-alt:before{content:"\f50a"}.fa-osi:before{content:"\f41a"}.fa-google-wallet:before{content:"\f1ee"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-periscope:before{content:"\f3da"}.fa-fulcrum:before{content:"\f50b"}.fa-cloudscale:before{content:"\f383"}.fa-forumbee:before{content:"\f211"}.fa-mizuni:before{content:"\f3cc"}.fa-schlix:before{content:"\f3ea"}.fa-square-xing:before,.fa-xing-square:before{content:"\f169"}.fa-bandcamp:before{content:"\f2d5"}.fa-wpforms:before{content:"\f298"}.fa-cloudversify:before{content:"\f385"}.fa-usps:before{content:"\f7e1"}.fa-megaport:before{content:"\f5a3"}.fa-magento:before{content:"\f3c4"}.fa-spotify:before{content:"\f1bc"}.fa-optin-monster:before{content:"\f23c"}.fa-fly:before{content:"\f417"}.fa-aviato:before{content:"\f421"}.fa-itunes:before{content:"\f3b4"}.fa-cuttlefish:before{content:"\f38c"}.fa-blogger:before{content:"\f37c"}.fa-flickr:before{content:"\f16e"}.fa-viber:before{content:"\f409"}.fa-soundcloud:before{content:"\f1be"}.fa-digg:before{content:"\f1a6"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-letterboxd:before{content:"\e62d"}.fa-symfony:before{content:"\f83d"}.fa-maxcdn:before{content:"\f136"}.fa-etsy:before{content:"\f2d7"}.fa-facebook-messenger:before{content:"\f39f"}.fa-audible:before{content:"\f373"}.fa-think-peaks:before{content:"\f731"}.fa-bilibili:before{content:"\e3d9"}.fa-erlang:before{content:"\f39d"}.fa-x-twitter:before{content:"\e61b"}.fa-cotton-bureau:before{content:"\f89e"}.fa-dashcube:before{content:"\f210"}.fa-42-group:before,.fa-innosoft:before{content:"\e080"}.fa-stack-exchange:before{content:"\f18d"}.fa-elementor:before{content:"\f430"}.fa-pied-piper-square:before,.fa-square-pied-piper:before{content:"\e01e"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-palfed:before{content:"\f3d8"}.fa-superpowers:before{content:"\f2dd"}.fa-resolving:before{content:"\f3e7"}.fa-xbox:before{content:"\f412"}.fa-square-web-awesome-stroke:before{content:"\e684"}.fa-searchengin:before{content:"\f3eb"}.fa-tiktok:before{content:"\e07b"}.fa-facebook-square:before,.fa-square-facebook:before{content:"\f082"}.fa-renren:before{content:"\f18b"}.fa-linux:before{content:"\f17c"}.fa-glide:before{content:"\f2a5"}.fa-linkedin:before{content:"\f08c"}.fa-hubspot:before{content:"\f3b2"}.fa-deploydog:before{content:"\f38e"}.fa-twitch:before{content:"\f1e8"}.fa-ravelry:before{content:"\f2d9"}.fa-mixer:before{content:"\e056"}.fa-lastfm-square:before,.fa-square-lastfm:before{content:"\f203"}.fa-vimeo:before{content:"\f40a"}.fa-mendeley:before{content:"\f7b3"}.fa-uniregistry:before{content:"\f404"}.fa-figma:before{content:"\f799"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-dropbox:before{content:"\f16b"}.fa-instagram:before{content:"\f16d"}.fa-cmplid:before{content:"\e360"}.fa-upwork:before{content:"\e641"}.fa-facebook:before{content:"\f09a"}.fa-gripfire:before{content:"\f3ac"}.fa-jedi-order:before{content:"\f50e"}.fa-uikit:before{content:"\f403"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-phabricator:before{content:"\f3db"}.fa-ussunnah:before{content:"\f407"}.fa-earlybirds:before{content:"\f39a"}.fa-trade-federation:before{content:"\f513"}.fa-autoprefixer:before{content:"\f41c"}.fa-whatsapp:before{content:"\f232"}.fa-square-upwork:before{content:"\e67c"}.fa-slideshare:before{content:"\f1e7"}.fa-google-play:before{content:"\f3ab"}.fa-viadeo:before{content:"\f2a9"}.fa-line:before{content:"\f3c0"}.fa-google-drive:before{content:"\f3aa"}.fa-servicestack:before{content:"\f3ec"}.fa-simplybuilt:before{content:"\f215"}.fa-bitbucket:before{content:"\f171"}.fa-imdb:before{content:"\f2d8"}.fa-deezer:before{content:"\e077"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-jira:before{content:"\f7b1"}.fa-docker:before{content:"\f395"}.fa-screenpal:before{content:"\e570"}.fa-bluetooth:before{content:"\f293"}.fa-gitter:before{content:"\f426"}.fa-d-and-d:before{content:"\f38d"}.fa-microblog:before{content:"\e01a"}.fa-cc-diners-club:before{content:"\f24c"}.fa-gg-circle:before{content:"\f261"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-yandex:before{content:"\f413"}.fa-readme:before{content:"\f4d5"}.fa-html5:before{content:"\f13b"}.fa-sellsy:before{content:"\f213"}.fa-square-web-awesome:before{content:"\e683"}.fa-sass:before{content:"\f41e"}.fa-wirsindhandwerk:before,.fa-wsh:before{content:"\e2d0"}.fa-buromobelexperte:before{content:"\f37f"}.fa-salesforce:before{content:"\f83b"}.fa-octopus-deploy:before{content:"\e082"}.fa-medapps:before{content:"\f3c6"}.fa-ns8:before{content:"\f3d5"}.fa-pinterest-p:before{content:"\f231"}.fa-apper:before{content:"\f371"}.fa-fort-awesome:before{content:"\f286"}.fa-waze:before{content:"\f83f"}.fa-bluesky:before{content:"\e671"}.fa-cc-jcb:before{content:"\f24b"}.fa-snapchat-ghost:before,.fa-snapchat:before{content:"\f2ab"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-rust:before{content:"\e07a"}.fa-wix:before{content:"\f5cf"}.fa-behance-square:before,.fa-square-behance:before{content:"\f1b5"}.fa-supple:before{content:"\f3f9"}.fa-webflow:before{content:"\e65c"}.fa-rebel:before{content:"\f1d0"}.fa-css3:before{content:"\f13c"}.fa-staylinked:before{content:"\f3f5"}.fa-kaggle:before{content:"\f5fa"}.fa-space-awesome:before{content:"\e5ac"}.fa-deviantart:before{content:"\f1bd"}.fa-cpanel:before{content:"\f388"}.fa-goodreads-g:before{content:"\f3a9"}.fa-git-square:before,.fa-square-git:before{content:"\f1d2"}.fa-square-tumblr:before,.fa-tumblr-square:before{content:"\f174"}.fa-trello:before{content:"\f181"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-get-pocket:before{content:"\f265"}.fa-perbyte:before{content:"\e083"}.fa-grunt:before{content:"\f3ad"}.fa-weebly:before{content:"\f5cc"}.fa-connectdevelop:before{content:"\f20e"}.fa-leanpub:before{content:"\f212"}.fa-black-tie:before{content:"\f27e"}.fa-themeco:before{content:"\f5c6"}.fa-python:before{content:"\f3e2"}.fa-android:before{content:"\f17b"}.fa-bots:before{content:"\e340"}.fa-free-code-camp:before{content:"\f2c5"}.fa-hornbill:before{content:"\f592"}.fa-js:before{content:"\f3b8"}.fa-ideal:before{content:"\e013"}.fa-git:before{content:"\f1d3"}.fa-dev:before{content:"\f6cc"}.fa-sketch:before{content:"\f7c6"}.fa-yandex-international:before{content:"\f414"}.fa-cc-amex:before{content:"\f1f3"}.fa-uber:before{content:"\f402"}.fa-github:before{content:"\f09b"}.fa-php:before{content:"\f457"}.fa-alipay:before{content:"\f642"}.fa-youtube:before{content:"\f167"}.fa-skyatlas:before{content:"\f216"}.fa-firefox-browser:before{content:"\e007"}.fa-replyd:before{content:"\f3e6"}.fa-suse:before{content:"\f7d6"}.fa-jenkins:before{content:"\f3b6"}.fa-twitter:before{content:"\f099"}.fa-rockrms:before{content:"\f3e9"}.fa-pinterest:before{content:"\f0d2"}.fa-buffer:before{content:"\f837"}.fa-npm:before{content:"\f3d4"}.fa-yammer:before{content:"\f840"}.fa-btc:before{content:"\f15a"}.fa-dribbble:before{content:"\f17d"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-internet-explorer:before{content:"\f26b"}.fa-stubber:before{content:"\e5c7"}.fa-telegram-plane:before,.fa-telegram:before{content:"\f2c6"}.fa-old-republic:before{content:"\f510"}.fa-odysee:before{content:"\e5c6"}.fa-square-whatsapp:before,.fa-whatsapp-square:before{content:"\f40c"}.fa-node-js:before{content:"\f3d3"}.fa-edge-legacy:before{content:"\e078"}.fa-slack-hash:before,.fa-slack:before{content:"\f198"}.fa-medrt:before{content:"\f3c8"}.fa-usb:before{content:"\f287"}.fa-tumblr:before{content:"\f173"}.fa-vaadin:before{content:"\f408"}.fa-quora:before{content:"\f2c4"}.fa-square-x-twitter:before{content:"\e61a"}.fa-reacteurope:before{content:"\f75d"}.fa-medium-m:before,.fa-medium:before{content:"\f23a"}.fa-amilia:before{content:"\f36d"}.fa-mixcloud:before{content:"\f289"}.fa-flipboard:before{content:"\f44d"}.fa-viacoin:before{content:"\f237"}.fa-critical-role:before{content:"\f6c9"}.fa-sitrox:before{content:"\e44a"}.fa-discourse:before{content:"\f393"}.fa-joomla:before{content:"\f1aa"}.fa-mastodon:before{content:"\f4f6"}.fa-airbnb:before{content:"\f834"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-buy-n-large:before{content:"\f8a6"}.fa-gulp:before{content:"\f3ae"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-strava:before{content:"\f428"}.fa-ember:before{content:"\f423"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-teamspeak:before{content:"\f4f9"}.fa-pushed:before{content:"\f3e1"}.fa-wordpress-simple:before{content:"\f411"}.fa-nutritionix:before{content:"\f3d6"}.fa-wodu:before{content:"\e088"}.fa-google-pay:before{content:"\e079"}.fa-intercom:before{content:"\f7af"}.fa-zhihu:before{content:"\f63f"}.fa-korvue:before{content:"\f42f"}.fa-pix:before{content:"\e43a"}.fa-steam-symbol:before{content:"\f3f6"}:host,:root{--fa-font-regular:normal 400 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:400;font-display:block;src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }.fa-regular,.far{font-weight:400}:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }.fa-solid,.fas{font-weight:900}@font-face{font-family:"Font Awesome 5 Brands";font-display:block;font-weight:400;src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:900;src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:400;src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }@font-face{font-family:"FontAwesome";font-display:block;src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }@font-face{font-family:"FontAwesome";font-display:block;src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }@font-face{font-family:"FontAwesome";font-display:block;src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }@font-face{font-family:"FontAwesome";font-display:block;src: url("../webfonts/fa-v4compatibility.woff2") format("woff2"), url("../webfonts/fa-v4compatibility.ttf") format("truetype"); } \ No newline at end of file diff --git a/docs/deps/font-awesome-6.5.2/css/v4-shims.css b/docs/deps/font-awesome-6.5.2/css/v4-shims.css new file mode 100644 index 0000000..ea60ea4 --- /dev/null +++ b/docs/deps/font-awesome-6.5.2/css/v4-shims.css @@ -0,0 +1,2194 @@ +/*! + * Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +.fa.fa-glass:before { + content: "\f000"; } + +.fa.fa-envelope-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-envelope-o:before { + content: "\f0e0"; } + +.fa.fa-star-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-star-o:before { + content: "\f005"; } + +.fa.fa-remove:before { + content: "\f00d"; } + +.fa.fa-close:before { + content: "\f00d"; } + +.fa.fa-gear:before { + content: "\f013"; } + +.fa.fa-trash-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-trash-o:before { + content: "\f2ed"; } + +.fa.fa-home:before { + content: "\f015"; } + +.fa.fa-file-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-o:before { + content: "\f15b"; } + +.fa.fa-clock-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-clock-o:before { + content: "\f017"; } + +.fa.fa-arrow-circle-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-down:before { + content: "\f358"; } + +.fa.fa-arrow-circle-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-up:before { + content: "\f35b"; } + +.fa.fa-play-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-play-circle-o:before { + content: "\f144"; } + +.fa.fa-repeat:before { + content: "\f01e"; } + +.fa.fa-rotate-right:before { + content: "\f01e"; } + +.fa.fa-refresh:before { + content: "\f021"; } + +.fa.fa-list-alt { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-list-alt:before { + content: "\f022"; } + +.fa.fa-dedent:before { + content: "\f03b"; } + +.fa.fa-video-camera:before { + content: "\f03d"; } + +.fa.fa-picture-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-picture-o:before { + content: "\f03e"; } + +.fa.fa-photo { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-photo:before { + content: "\f03e"; } + +.fa.fa-image { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-image:before { + content: "\f03e"; } + +.fa.fa-map-marker:before { + content: "\f3c5"; } + +.fa.fa-pencil-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-pencil-square-o:before { + content: "\f044"; } + +.fa.fa-edit { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-edit:before { + content: "\f044"; } + +.fa.fa-share-square-o:before { + content: "\f14d"; } + +.fa.fa-check-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-check-square-o:before { + content: "\f14a"; } + +.fa.fa-arrows:before { + content: "\f0b2"; } + +.fa.fa-times-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-times-circle-o:before { + content: "\f057"; } + +.fa.fa-check-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-check-circle-o:before { + content: "\f058"; } + +.fa.fa-mail-forward:before { + content: "\f064"; } + +.fa.fa-expand:before { + content: "\f424"; } + +.fa.fa-compress:before { + content: "\f422"; } + +.fa.fa-eye { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-eye-slash { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-warning:before { + content: "\f071"; } + +.fa.fa-calendar:before { + content: "\f073"; } + +.fa.fa-arrows-v:before { + content: "\f338"; } + +.fa.fa-arrows-h:before { + content: "\f337"; } + +.fa.fa-bar-chart:before { + content: "\e0e3"; } + +.fa.fa-bar-chart-o:before { + content: "\e0e3"; } + +.fa.fa-twitter-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-twitter-square:before { + content: "\f081"; } + +.fa.fa-facebook-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook-square:before { + content: "\f082"; } + +.fa.fa-gears:before { + content: "\f085"; } + +.fa.fa-thumbs-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-thumbs-o-up:before { + content: "\f164"; } + +.fa.fa-thumbs-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-thumbs-o-down:before { + content: "\f165"; } + +.fa.fa-heart-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-heart-o:before { + content: "\f004"; } + +.fa.fa-sign-out:before { + content: "\f2f5"; } + +.fa.fa-linkedin-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-linkedin-square:before { + content: "\f08c"; } + +.fa.fa-thumb-tack:before { + content: "\f08d"; } + +.fa.fa-external-link:before { + content: "\f35d"; } + +.fa.fa-sign-in:before { + content: "\f2f6"; } + +.fa.fa-github-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-github-square:before { + content: "\f092"; } + +.fa.fa-lemon-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-lemon-o:before { + content: "\f094"; } + +.fa.fa-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-square-o:before { + content: "\f0c8"; } + +.fa.fa-bookmark-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-bookmark-o:before { + content: "\f02e"; } + +.fa.fa-twitter { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook:before { + content: "\f39e"; } + +.fa.fa-facebook-f { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook-f:before { + content: "\f39e"; } + +.fa.fa-github { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-credit-card { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-feed:before { + content: "\f09e"; } + +.fa.fa-hdd-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hdd-o:before { + content: "\f0a0"; } + +.fa.fa-hand-o-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-o-right:before { + content: "\f0a4"; } + +.fa.fa-hand-o-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-o-left:before { + content: "\f0a5"; } + +.fa.fa-hand-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-o-up:before { + content: "\f0a6"; } + +.fa.fa-hand-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-o-down:before { + content: "\f0a7"; } + +.fa.fa-globe:before { + content: "\f57d"; } + +.fa.fa-tasks:before { + content: "\f828"; } + +.fa.fa-arrows-alt:before { + content: "\f31e"; } + +.fa.fa-group:before { + content: "\f0c0"; } + +.fa.fa-chain:before { + content: "\f0c1"; } + +.fa.fa-cut:before { + content: "\f0c4"; } + +.fa.fa-files-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-files-o:before { + content: "\f0c5"; } + +.fa.fa-floppy-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-floppy-o:before { + content: "\f0c7"; } + +.fa.fa-save { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-save:before { + content: "\f0c7"; } + +.fa.fa-navicon:before { + content: "\f0c9"; } + +.fa.fa-reorder:before { + content: "\f0c9"; } + +.fa.fa-magic:before { + content: "\e2ca"; } + +.fa.fa-pinterest { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pinterest-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pinterest-square:before { + content: "\f0d3"; } + +.fa.fa-google-plus-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-square:before { + content: "\f0d4"; } + +.fa.fa-google-plus { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus:before { + content: "\f0d5"; } + +.fa.fa-money:before { + content: "\f3d1"; } + +.fa.fa-unsorted:before { + content: "\f0dc"; } + +.fa.fa-sort-desc:before { + content: "\f0dd"; } + +.fa.fa-sort-asc:before { + content: "\f0de"; } + +.fa.fa-linkedin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-linkedin:before { + content: "\f0e1"; } + +.fa.fa-rotate-left:before { + content: "\f0e2"; } + +.fa.fa-legal:before { + content: "\f0e3"; } + +.fa.fa-tachometer:before { + content: "\f625"; } + +.fa.fa-dashboard:before { + content: "\f625"; } + +.fa.fa-comment-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-comment-o:before { + content: "\f075"; } + +.fa.fa-comments-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-comments-o:before { + content: "\f086"; } + +.fa.fa-flash:before { + content: "\f0e7"; } + +.fa.fa-clipboard:before { + content: "\f0ea"; } + +.fa.fa-lightbulb-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-lightbulb-o:before { + content: "\f0eb"; } + +.fa.fa-exchange:before { + content: "\f362"; } + +.fa.fa-cloud-download:before { + content: "\f0ed"; } + +.fa.fa-cloud-upload:before { + content: "\f0ee"; } + +.fa.fa-bell-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-bell-o:before { + content: "\f0f3"; } + +.fa.fa-cutlery:before { + content: "\f2e7"; } + +.fa.fa-file-text-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-text-o:before { + content: "\f15c"; } + +.fa.fa-building-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-building-o:before { + content: "\f1ad"; } + +.fa.fa-hospital-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hospital-o:before { + content: "\f0f8"; } + +.fa.fa-tablet:before { + content: "\f3fa"; } + +.fa.fa-mobile:before { + content: "\f3cd"; } + +.fa.fa-mobile-phone:before { + content: "\f3cd"; } + +.fa.fa-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-circle-o:before { + content: "\f111"; } + +.fa.fa-mail-reply:before { + content: "\f3e5"; } + +.fa.fa-github-alt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-folder-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-folder-o:before { + content: "\f07b"; } + +.fa.fa-folder-open-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-folder-open-o:before { + content: "\f07c"; } + +.fa.fa-smile-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-smile-o:before { + content: "\f118"; } + +.fa.fa-frown-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-frown-o:before { + content: "\f119"; } + +.fa.fa-meh-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-meh-o:before { + content: "\f11a"; } + +.fa.fa-keyboard-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-keyboard-o:before { + content: "\f11c"; } + +.fa.fa-flag-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-flag-o:before { + content: "\f024"; } + +.fa.fa-mail-reply-all:before { + content: "\f122"; } + +.fa.fa-star-half-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-star-half-o:before { + content: "\f5c0"; } + +.fa.fa-star-half-empty { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-star-half-empty:before { + content: "\f5c0"; } + +.fa.fa-star-half-full { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-star-half-full:before { + content: "\f5c0"; } + +.fa.fa-code-fork:before { + content: "\f126"; } + +.fa.fa-chain-broken:before { + content: "\f127"; } + +.fa.fa-unlink:before { + content: "\f127"; } + +.fa.fa-calendar-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-o:before { + content: "\f133"; } + +.fa.fa-maxcdn { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-html5 { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-css3 { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-unlock-alt:before { + content: "\f09c"; } + +.fa.fa-minus-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-minus-square-o:before { + content: "\f146"; } + +.fa.fa-level-up:before { + content: "\f3bf"; } + +.fa.fa-level-down:before { + content: "\f3be"; } + +.fa.fa-pencil-square:before { + content: "\f14b"; } + +.fa.fa-external-link-square:before { + content: "\f360"; } + +.fa.fa-compass { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-down:before { + content: "\f150"; } + +.fa.fa-toggle-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-toggle-down:before { + content: "\f150"; } + +.fa.fa-caret-square-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-up:before { + content: "\f151"; } + +.fa.fa-toggle-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-toggle-up:before { + content: "\f151"; } + +.fa.fa-caret-square-o-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-right:before { + content: "\f152"; } + +.fa.fa-toggle-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-toggle-right:before { + content: "\f152"; } + +.fa.fa-eur:before { + content: "\f153"; } + +.fa.fa-euro:before { + content: "\f153"; } + +.fa.fa-gbp:before { + content: "\f154"; } + +.fa.fa-usd:before { + content: "\24"; } + +.fa.fa-dollar:before { + content: "\24"; } + +.fa.fa-inr:before { + content: "\e1bc"; } + +.fa.fa-rupee:before { + content: "\e1bc"; } + +.fa.fa-jpy:before { + content: "\f157"; } + +.fa.fa-cny:before { + content: "\f157"; } + +.fa.fa-rmb:before { + content: "\f157"; } + +.fa.fa-yen:before { + content: "\f157"; } + +.fa.fa-rub:before { + content: "\f158"; } + +.fa.fa-ruble:before { + content: "\f158"; } + +.fa.fa-rouble:before { + content: "\f158"; } + +.fa.fa-krw:before { + content: "\f159"; } + +.fa.fa-won:before { + content: "\f159"; } + +.fa.fa-btc { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitcoin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitcoin:before { + content: "\f15a"; } + +.fa.fa-file-text:before { + content: "\f15c"; } + +.fa.fa-sort-alpha-asc:before { + content: "\f15d"; } + +.fa.fa-sort-alpha-desc:before { + content: "\f881"; } + +.fa.fa-sort-amount-asc:before { + content: "\f884"; } + +.fa.fa-sort-amount-desc:before { + content: "\f160"; } + +.fa.fa-sort-numeric-asc:before { + content: "\f162"; } + +.fa.fa-sort-numeric-desc:before { + content: "\f886"; } + +.fa.fa-youtube-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-youtube-square:before { + content: "\f431"; } + +.fa.fa-youtube { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-xing { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-xing-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-xing-square:before { + content: "\f169"; } + +.fa.fa-youtube-play { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-youtube-play:before { + content: "\f167"; } + +.fa.fa-dropbox { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-stack-overflow { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-instagram { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-flickr { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-adn { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitbucket { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitbucket-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitbucket-square:before { + content: "\f171"; } + +.fa.fa-tumblr { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-tumblr-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-tumblr-square:before { + content: "\f174"; } + +.fa.fa-long-arrow-down:before { + content: "\f309"; } + +.fa.fa-long-arrow-up:before { + content: "\f30c"; } + +.fa.fa-long-arrow-left:before { + content: "\f30a"; } + +.fa.fa-long-arrow-right:before { + content: "\f30b"; } + +.fa.fa-apple { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-windows { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-android { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-linux { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-dribbble { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-skype { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-foursquare { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-trello { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gratipay { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gittip { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gittip:before { + content: "\f184"; } + +.fa.fa-sun-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-sun-o:before { + content: "\f185"; } + +.fa.fa-moon-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-moon-o:before { + content: "\f186"; } + +.fa.fa-vk { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-weibo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-renren { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pagelines { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-stack-exchange { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-right:before { + content: "\f35a"; } + +.fa.fa-arrow-circle-o-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-left:before { + content: "\f359"; } + +.fa.fa-caret-square-o-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-left:before { + content: "\f191"; } + +.fa.fa-toggle-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-toggle-left:before { + content: "\f191"; } + +.fa.fa-dot-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-dot-circle-o:before { + content: "\f192"; } + +.fa.fa-vimeo-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-vimeo-square:before { + content: "\f194"; } + +.fa.fa-try:before { + content: "\e2bb"; } + +.fa.fa-turkish-lira:before { + content: "\e2bb"; } + +.fa.fa-plus-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-plus-square-o:before { + content: "\f0fe"; } + +.fa.fa-slack { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wordpress { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-openid { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-institution:before { + content: "\f19c"; } + +.fa.fa-bank:before { + content: "\f19c"; } + +.fa.fa-mortar-board:before { + content: "\f19d"; } + +.fa.fa-yahoo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-reddit { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-reddit-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-reddit-square:before { + content: "\f1a2"; } + +.fa.fa-stumbleupon-circle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-stumbleupon { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-delicious { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-digg { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pied-piper-pp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pied-piper-alt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-drupal { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-joomla { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-behance { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-behance-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-behance-square:before { + content: "\f1b5"; } + +.fa.fa-steam { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-steam-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-steam-square:before { + content: "\f1b7"; } + +.fa.fa-automobile:before { + content: "\f1b9"; } + +.fa.fa-cab:before { + content: "\f1ba"; } + +.fa.fa-spotify { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-deviantart { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-soundcloud { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-file-pdf-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-pdf-o:before { + content: "\f1c1"; } + +.fa.fa-file-word-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-word-o:before { + content: "\f1c2"; } + +.fa.fa-file-excel-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-excel-o:before { + content: "\f1c3"; } + +.fa.fa-file-powerpoint-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-powerpoint-o:before { + content: "\f1c4"; } + +.fa.fa-file-image-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-image-o:before { + content: "\f1c5"; } + +.fa.fa-file-photo-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-photo-o:before { + content: "\f1c5"; } + +.fa.fa-file-picture-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-picture-o:before { + content: "\f1c5"; } + +.fa.fa-file-archive-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-archive-o:before { + content: "\f1c6"; } + +.fa.fa-file-zip-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-zip-o:before { + content: "\f1c6"; } + +.fa.fa-file-audio-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-audio-o:before { + content: "\f1c7"; } + +.fa.fa-file-sound-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-sound-o:before { + content: "\f1c7"; } + +.fa.fa-file-video-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-video-o:before { + content: "\f1c8"; } + +.fa.fa-file-movie-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-movie-o:before { + content: "\f1c8"; } + +.fa.fa-file-code-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-code-o:before { + content: "\f1c9"; } + +.fa.fa-vine { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-codepen { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-jsfiddle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-life-bouy:before { + content: "\f1cd"; } + +.fa.fa-life-buoy:before { + content: "\f1cd"; } + +.fa.fa-life-saver:before { + content: "\f1cd"; } + +.fa.fa-support:before { + content: "\f1cd"; } + +.fa.fa-circle-o-notch:before { + content: "\f1ce"; } + +.fa.fa-rebel { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ra { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ra:before { + content: "\f1d0"; } + +.fa.fa-resistance { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-resistance:before { + content: "\f1d0"; } + +.fa.fa-empire { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ge { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ge:before { + content: "\f1d1"; } + +.fa.fa-git-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-git-square:before { + content: "\f1d2"; } + +.fa.fa-git { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-hacker-news { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-y-combinator-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-y-combinator-square:before { + content: "\f1d4"; } + +.fa.fa-yc-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yc-square:before { + content: "\f1d4"; } + +.fa.fa-tencent-weibo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-qq { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-weixin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wechat { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wechat:before { + content: "\f1d7"; } + +.fa.fa-send:before { + content: "\f1d8"; } + +.fa.fa-paper-plane-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-paper-plane-o:before { + content: "\f1d8"; } + +.fa.fa-send-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-send-o:before { + content: "\f1d8"; } + +.fa.fa-circle-thin { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-circle-thin:before { + content: "\f111"; } + +.fa.fa-header:before { + content: "\f1dc"; } + +.fa.fa-futbol-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-futbol-o:before { + content: "\f1e3"; } + +.fa.fa-soccer-ball-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-soccer-ball-o:before { + content: "\f1e3"; } + +.fa.fa-slideshare { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-twitch { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yelp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-newspaper-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-newspaper-o:before { + content: "\f1ea"; } + +.fa.fa-paypal { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-wallet { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-visa { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-mastercard { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-discover { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-amex { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-paypal { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-stripe { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bell-slash-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-bell-slash-o:before { + content: "\f1f6"; } + +.fa.fa-trash:before { + content: "\f2ed"; } + +.fa.fa-copyright { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-eyedropper:before { + content: "\f1fb"; } + +.fa.fa-area-chart:before { + content: "\f1fe"; } + +.fa.fa-pie-chart:before { + content: "\f200"; } + +.fa.fa-line-chart:before { + content: "\f201"; } + +.fa.fa-lastfm { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-lastfm-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-lastfm-square:before { + content: "\f203"; } + +.fa.fa-ioxhost { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-angellist { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-cc:before { + content: "\f20a"; } + +.fa.fa-ils:before { + content: "\f20b"; } + +.fa.fa-shekel:before { + content: "\f20b"; } + +.fa.fa-sheqel:before { + content: "\f20b"; } + +.fa.fa-buysellads { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-connectdevelop { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-dashcube { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-forumbee { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-leanpub { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-sellsy { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-shirtsinbulk { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-simplybuilt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-skyatlas { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-diamond { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-diamond:before { + content: "\f3a5"; } + +.fa.fa-transgender:before { + content: "\f224"; } + +.fa.fa-intersex:before { + content: "\f224"; } + +.fa.fa-transgender-alt:before { + content: "\f225"; } + +.fa.fa-facebook-official { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook-official:before { + content: "\f09a"; } + +.fa.fa-pinterest-p { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-whatsapp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-hotel:before { + content: "\f236"; } + +.fa.fa-viacoin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-medium { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-y-combinator { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yc { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yc:before { + content: "\f23b"; } + +.fa.fa-optin-monster { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-opencart { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-expeditedssl { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-battery-4:before { + content: "\f240"; } + +.fa.fa-battery:before { + content: "\f240"; } + +.fa.fa-battery-3:before { + content: "\f241"; } + +.fa.fa-battery-2:before { + content: "\f242"; } + +.fa.fa-battery-1:before { + content: "\f243"; } + +.fa.fa-battery-0:before { + content: "\f244"; } + +.fa.fa-object-group { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-object-ungroup { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-sticky-note-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-sticky-note-o:before { + content: "\f249"; } + +.fa.fa-cc-jcb { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-diners-club { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-clone { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hourglass-o:before { + content: "\f254"; } + +.fa.fa-hourglass-1:before { + content: "\f251"; } + +.fa.fa-hourglass-2:before { + content: "\f252"; } + +.fa.fa-hourglass-3:before { + content: "\f253"; } + +.fa.fa-hand-rock-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-rock-o:before { + content: "\f255"; } + +.fa.fa-hand-grab-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-grab-o:before { + content: "\f255"; } + +.fa.fa-hand-paper-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-paper-o:before { + content: "\f256"; } + +.fa.fa-hand-stop-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-stop-o:before { + content: "\f256"; } + +.fa.fa-hand-scissors-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-scissors-o:before { + content: "\f257"; } + +.fa.fa-hand-lizard-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-lizard-o:before { + content: "\f258"; } + +.fa.fa-hand-spock-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-spock-o:before { + content: "\f259"; } + +.fa.fa-hand-pointer-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-pointer-o:before { + content: "\f25a"; } + +.fa.fa-hand-peace-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-peace-o:before { + content: "\f25b"; } + +.fa.fa-registered { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-creative-commons { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gg { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gg-circle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-odnoklassniki { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-odnoklassniki-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-odnoklassniki-square:before { + content: "\f264"; } + +.fa.fa-get-pocket { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wikipedia-w { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-safari { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-chrome { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-firefox { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-opera { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-internet-explorer { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-television:before { + content: "\f26c"; } + +.fa.fa-contao { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-500px { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-amazon { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-calendar-plus-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-plus-o:before { + content: "\f271"; } + +.fa.fa-calendar-minus-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-minus-o:before { + content: "\f272"; } + +.fa.fa-calendar-times-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-times-o:before { + content: "\f273"; } + +.fa.fa-calendar-check-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-check-o:before { + content: "\f274"; } + +.fa.fa-map-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-map-o:before { + content: "\f279"; } + +.fa.fa-commenting:before { + content: "\f4ad"; } + +.fa.fa-commenting-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-commenting-o:before { + content: "\f4ad"; } + +.fa.fa-houzz { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-vimeo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-vimeo:before { + content: "\f27d"; } + +.fa.fa-black-tie { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-fonticons { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-reddit-alien { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-edge { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-credit-card-alt:before { + content: "\f09d"; } + +.fa.fa-codiepie { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-modx { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-fort-awesome { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-usb { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-product-hunt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-mixcloud { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-scribd { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pause-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-pause-circle-o:before { + content: "\f28b"; } + +.fa.fa-stop-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-stop-circle-o:before { + content: "\f28d"; } + +.fa.fa-bluetooth { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bluetooth-b { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gitlab { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wpbeginner { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wpforms { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-envira { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wheelchair-alt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wheelchair-alt:before { + content: "\f368"; } + +.fa.fa-question-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-question-circle-o:before { + content: "\f059"; } + +.fa.fa-volume-control-phone:before { + content: "\f2a0"; } + +.fa.fa-asl-interpreting:before { + content: "\f2a3"; } + +.fa.fa-deafness:before { + content: "\f2a4"; } + +.fa.fa-hard-of-hearing:before { + content: "\f2a4"; } + +.fa.fa-glide { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-glide-g { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-signing:before { + content: "\f2a7"; } + +.fa.fa-viadeo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-viadeo-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-viadeo-square:before { + content: "\f2aa"; } + +.fa.fa-snapchat { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-snapchat-ghost { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-snapchat-ghost:before { + content: "\f2ab"; } + +.fa.fa-snapchat-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-snapchat-square:before { + content: "\f2ad"; } + +.fa.fa-pied-piper { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-first-order { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yoast { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-themeisle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-official { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-official:before { + content: "\f2b3"; } + +.fa.fa-google-plus-circle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-circle:before { + content: "\f2b3"; } + +.fa.fa-font-awesome { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-fa { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-fa:before { + content: "\f2b4"; } + +.fa.fa-handshake-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-handshake-o:before { + content: "\f2b5"; } + +.fa.fa-envelope-open-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-envelope-open-o:before { + content: "\f2b6"; } + +.fa.fa-linode { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-address-book-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-address-book-o:before { + content: "\f2b9"; } + +.fa.fa-vcard:before { + content: "\f2bb"; } + +.fa.fa-address-card-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-address-card-o:before { + content: "\f2bb"; } + +.fa.fa-vcard-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-vcard-o:before { + content: "\f2bb"; } + +.fa.fa-user-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-user-circle-o:before { + content: "\f2bd"; } + +.fa.fa-user-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-user-o:before { + content: "\f007"; } + +.fa.fa-id-badge { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-drivers-license:before { + content: "\f2c2"; } + +.fa.fa-id-card-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-id-card-o:before { + content: "\f2c2"; } + +.fa.fa-drivers-license-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-drivers-license-o:before { + content: "\f2c2"; } + +.fa.fa-quora { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-free-code-camp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-telegram { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-thermometer-4:before { + content: "\f2c7"; } + +.fa.fa-thermometer:before { + content: "\f2c7"; } + +.fa.fa-thermometer-3:before { + content: "\f2c8"; } + +.fa.fa-thermometer-2:before { + content: "\f2c9"; } + +.fa.fa-thermometer-1:before { + content: "\f2ca"; } + +.fa.fa-thermometer-0:before { + content: "\f2cb"; } + +.fa.fa-bathtub:before { + content: "\f2cd"; } + +.fa.fa-s15:before { + content: "\f2cd"; } + +.fa.fa-window-maximize { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-window-restore { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-times-rectangle:before { + content: "\f410"; } + +.fa.fa-window-close-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-window-close-o:before { + content: "\f410"; } + +.fa.fa-times-rectangle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-times-rectangle-o:before { + content: "\f410"; } + +.fa.fa-bandcamp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-grav { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-etsy { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-imdb { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ravelry { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-eercast { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-eercast:before { + content: "\f2da"; } + +.fa.fa-snowflake-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-snowflake-o:before { + content: "\f2dc"; } + +.fa.fa-superpowers { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wpexplorer { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-meetup { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } diff --git a/docs/deps/font-awesome-6.5.2/css/v4-shims.min.css b/docs/deps/font-awesome-6.5.2/css/v4-shims.min.css new file mode 100644 index 0000000..09baf5f --- /dev/null +++ b/docs/deps/font-awesome-6.5.2/css/v4-shims.min.css @@ -0,0 +1,6 @@ +/*! + * Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +.fa.fa-glass:before{content:"\f000"}.fa.fa-envelope-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-envelope-o:before{content:"\f0e0"}.fa.fa-star-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-star-o:before{content:"\f005"}.fa.fa-close:before,.fa.fa-remove:before{content:"\f00d"}.fa.fa-gear:before{content:"\f013"}.fa.fa-trash-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-trash-o:before{content:"\f2ed"}.fa.fa-home:before{content:"\f015"}.fa.fa-file-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-o:before{content:"\f15b"}.fa.fa-clock-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-clock-o:before{content:"\f017"}.fa.fa-arrow-circle-o-down{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-arrow-circle-o-down:before{content:"\f358"}.fa.fa-arrow-circle-o-up{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-arrow-circle-o-up:before{content:"\f35b"}.fa.fa-play-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-play-circle-o:before{content:"\f144"}.fa.fa-repeat:before,.fa.fa-rotate-right:before{content:"\f01e"}.fa.fa-refresh:before{content:"\f021"}.fa.fa-list-alt{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-list-alt:before{content:"\f022"}.fa.fa-dedent:before{content:"\f03b"}.fa.fa-video-camera:before{content:"\f03d"}.fa.fa-picture-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-picture-o:before{content:"\f03e"}.fa.fa-photo{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-photo:before{content:"\f03e"}.fa.fa-image{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-image:before{content:"\f03e"}.fa.fa-map-marker:before{content:"\f3c5"}.fa.fa-pencil-square-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-pencil-square-o:before{content:"\f044"}.fa.fa-edit{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-edit:before{content:"\f044"}.fa.fa-share-square-o:before{content:"\f14d"}.fa.fa-check-square-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-check-square-o:before{content:"\f14a"}.fa.fa-arrows:before{content:"\f0b2"}.fa.fa-times-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-times-circle-o:before{content:"\f057"}.fa.fa-check-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-check-circle-o:before{content:"\f058"}.fa.fa-mail-forward:before{content:"\f064"}.fa.fa-expand:before{content:"\f424"}.fa.fa-compress:before{content:"\f422"}.fa.fa-eye,.fa.fa-eye-slash{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-warning:before{content:"\f071"}.fa.fa-calendar:before{content:"\f073"}.fa.fa-arrows-v:before{content:"\f338"}.fa.fa-arrows-h:before{content:"\f337"}.fa.fa-bar-chart-o:before,.fa.fa-bar-chart:before{content:"\e0e3"}.fa.fa-twitter-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-twitter-square:before{content:"\f081"}.fa.fa-facebook-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-facebook-square:before{content:"\f082"}.fa.fa-gears:before{content:"\f085"}.fa.fa-thumbs-o-up{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-thumbs-o-up:before{content:"\f164"}.fa.fa-thumbs-o-down{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-thumbs-o-down:before{content:"\f165"}.fa.fa-heart-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-heart-o:before{content:"\f004"}.fa.fa-sign-out:before{content:"\f2f5"}.fa.fa-linkedin-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-linkedin-square:before{content:"\f08c"}.fa.fa-thumb-tack:before{content:"\f08d"}.fa.fa-external-link:before{content:"\f35d"}.fa.fa-sign-in:before{content:"\f2f6"}.fa.fa-github-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-github-square:before{content:"\f092"}.fa.fa-lemon-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-lemon-o:before{content:"\f094"}.fa.fa-square-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-square-o:before{content:"\f0c8"}.fa.fa-bookmark-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-bookmark-o:before{content:"\f02e"}.fa.fa-facebook,.fa.fa-twitter{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-facebook:before{content:"\f39e"}.fa.fa-facebook-f{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-facebook-f:before{content:"\f39e"}.fa.fa-github{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-credit-card{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-feed:before{content:"\f09e"}.fa.fa-hdd-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hdd-o:before{content:"\f0a0"}.fa.fa-hand-o-right{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-o-right:before{content:"\f0a4"}.fa.fa-hand-o-left{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-o-left:before{content:"\f0a5"}.fa.fa-hand-o-up{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-o-up:before{content:"\f0a6"}.fa.fa-hand-o-down{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-o-down:before{content:"\f0a7"}.fa.fa-globe:before{content:"\f57d"}.fa.fa-tasks:before{content:"\f828"}.fa.fa-arrows-alt:before{content:"\f31e"}.fa.fa-group:before{content:"\f0c0"}.fa.fa-chain:before{content:"\f0c1"}.fa.fa-cut:before{content:"\f0c4"}.fa.fa-files-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-files-o:before{content:"\f0c5"}.fa.fa-floppy-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-floppy-o:before{content:"\f0c7"}.fa.fa-save{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-save:before{content:"\f0c7"}.fa.fa-navicon:before,.fa.fa-reorder:before{content:"\f0c9"}.fa.fa-magic:before{content:"\e2ca"}.fa.fa-pinterest,.fa.fa-pinterest-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-pinterest-square:before{content:"\f0d3"}.fa.fa-google-plus-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-google-plus-square:before{content:"\f0d4"}.fa.fa-google-plus{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-google-plus:before{content:"\f0d5"}.fa.fa-money:before{content:"\f3d1"}.fa.fa-unsorted:before{content:"\f0dc"}.fa.fa-sort-desc:before{content:"\f0dd"}.fa.fa-sort-asc:before{content:"\f0de"}.fa.fa-linkedin{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-linkedin:before{content:"\f0e1"}.fa.fa-rotate-left:before{content:"\f0e2"}.fa.fa-legal:before{content:"\f0e3"}.fa.fa-dashboard:before,.fa.fa-tachometer:before{content:"\f625"}.fa.fa-comment-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-comment-o:before{content:"\f075"}.fa.fa-comments-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-comments-o:before{content:"\f086"}.fa.fa-flash:before{content:"\f0e7"}.fa.fa-clipboard:before{content:"\f0ea"}.fa.fa-lightbulb-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-lightbulb-o:before{content:"\f0eb"}.fa.fa-exchange:before{content:"\f362"}.fa.fa-cloud-download:before{content:"\f0ed"}.fa.fa-cloud-upload:before{content:"\f0ee"}.fa.fa-bell-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-bell-o:before{content:"\f0f3"}.fa.fa-cutlery:before{content:"\f2e7"}.fa.fa-file-text-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-text-o:before{content:"\f15c"}.fa.fa-building-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-building-o:before{content:"\f1ad"}.fa.fa-hospital-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hospital-o:before{content:"\f0f8"}.fa.fa-tablet:before{content:"\f3fa"}.fa.fa-mobile-phone:before,.fa.fa-mobile:before{content:"\f3cd"}.fa.fa-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-circle-o:before{content:"\f111"}.fa.fa-mail-reply:before{content:"\f3e5"}.fa.fa-github-alt{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-folder-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-folder-o:before{content:"\f07b"}.fa.fa-folder-open-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-folder-open-o:before{content:"\f07c"}.fa.fa-smile-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-smile-o:before{content:"\f118"}.fa.fa-frown-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-frown-o:before{content:"\f119"}.fa.fa-meh-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-meh-o:before{content:"\f11a"}.fa.fa-keyboard-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-keyboard-o:before{content:"\f11c"}.fa.fa-flag-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-flag-o:before{content:"\f024"}.fa.fa-mail-reply-all:before{content:"\f122"}.fa.fa-star-half-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-star-half-o:before{content:"\f5c0"}.fa.fa-star-half-empty{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-star-half-empty:before{content:"\f5c0"}.fa.fa-star-half-full{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-star-half-full:before{content:"\f5c0"}.fa.fa-code-fork:before{content:"\f126"}.fa.fa-chain-broken:before,.fa.fa-unlink:before{content:"\f127"}.fa.fa-calendar-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-calendar-o:before{content:"\f133"}.fa.fa-css3,.fa.fa-html5,.fa.fa-maxcdn{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-unlock-alt:before{content:"\f09c"}.fa.fa-minus-square-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-minus-square-o:before{content:"\f146"}.fa.fa-level-up:before{content:"\f3bf"}.fa.fa-level-down:before{content:"\f3be"}.fa.fa-pencil-square:before{content:"\f14b"}.fa.fa-external-link-square:before{content:"\f360"}.fa.fa-compass{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-caret-square-o-down{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-caret-square-o-down:before{content:"\f150"}.fa.fa-toggle-down{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-toggle-down:before{content:"\f150"}.fa.fa-caret-square-o-up{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-caret-square-o-up:before{content:"\f151"}.fa.fa-toggle-up{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-toggle-up:before{content:"\f151"}.fa.fa-caret-square-o-right{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-caret-square-o-right:before{content:"\f152"}.fa.fa-toggle-right{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-toggle-right:before{content:"\f152"}.fa.fa-eur:before,.fa.fa-euro:before{content:"\f153"}.fa.fa-gbp:before{content:"\f154"}.fa.fa-dollar:before,.fa.fa-usd:before{content:"\24"}.fa.fa-inr:before,.fa.fa-rupee:before{content:"\e1bc"}.fa.fa-cny:before,.fa.fa-jpy:before,.fa.fa-rmb:before,.fa.fa-yen:before{content:"\f157"}.fa.fa-rouble:before,.fa.fa-rub:before,.fa.fa-ruble:before{content:"\f158"}.fa.fa-krw:before,.fa.fa-won:before{content:"\f159"}.fa.fa-bitcoin,.fa.fa-btc{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-bitcoin:before{content:"\f15a"}.fa.fa-file-text:before{content:"\f15c"}.fa.fa-sort-alpha-asc:before{content:"\f15d"}.fa.fa-sort-alpha-desc:before{content:"\f881"}.fa.fa-sort-amount-asc:before{content:"\f884"}.fa.fa-sort-amount-desc:before{content:"\f160"}.fa.fa-sort-numeric-asc:before{content:"\f162"}.fa.fa-sort-numeric-desc:before{content:"\f886"}.fa.fa-youtube-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-youtube-square:before{content:"\f431"}.fa.fa-xing,.fa.fa-xing-square,.fa.fa-youtube{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-xing-square:before{content:"\f169"}.fa.fa-youtube-play{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-youtube-play:before{content:"\f167"}.fa.fa-adn,.fa.fa-bitbucket,.fa.fa-bitbucket-square,.fa.fa-dropbox,.fa.fa-flickr,.fa.fa-instagram,.fa.fa-stack-overflow{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-bitbucket-square:before{content:"\f171"}.fa.fa-tumblr,.fa.fa-tumblr-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-tumblr-square:before{content:"\f174"}.fa.fa-long-arrow-down:before{content:"\f309"}.fa.fa-long-arrow-up:before{content:"\f30c"}.fa.fa-long-arrow-left:before{content:"\f30a"}.fa.fa-long-arrow-right:before{content:"\f30b"}.fa.fa-android,.fa.fa-apple,.fa.fa-dribbble,.fa.fa-foursquare,.fa.fa-gittip,.fa.fa-gratipay,.fa.fa-linux,.fa.fa-skype,.fa.fa-trello,.fa.fa-windows{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-gittip:before{content:"\f184"}.fa.fa-sun-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-sun-o:before{content:"\f185"}.fa.fa-moon-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-moon-o:before{content:"\f186"}.fa.fa-pagelines,.fa.fa-renren,.fa.fa-stack-exchange,.fa.fa-vk,.fa.fa-weibo{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-arrow-circle-o-right{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-arrow-circle-o-right:before{content:"\f35a"}.fa.fa-arrow-circle-o-left{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-arrow-circle-o-left:before{content:"\f359"}.fa.fa-caret-square-o-left{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-caret-square-o-left:before{content:"\f191"}.fa.fa-toggle-left{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-toggle-left:before{content:"\f191"}.fa.fa-dot-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-dot-circle-o:before{content:"\f192"}.fa.fa-vimeo-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-vimeo-square:before{content:"\f194"}.fa.fa-try:before,.fa.fa-turkish-lira:before{content:"\e2bb"}.fa.fa-plus-square-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-plus-square-o:before{content:"\f0fe"}.fa.fa-openid,.fa.fa-slack,.fa.fa-wordpress{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-bank:before,.fa.fa-institution:before{content:"\f19c"}.fa.fa-mortar-board:before{content:"\f19d"}.fa.fa-google,.fa.fa-reddit,.fa.fa-reddit-square,.fa.fa-yahoo{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-reddit-square:before{content:"\f1a2"}.fa.fa-behance,.fa.fa-behance-square,.fa.fa-delicious,.fa.fa-digg,.fa.fa-drupal,.fa.fa-joomla,.fa.fa-pied-piper-alt,.fa.fa-pied-piper-pp,.fa.fa-stumbleupon,.fa.fa-stumbleupon-circle{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-behance-square:before{content:"\f1b5"}.fa.fa-steam,.fa.fa-steam-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-steam-square:before{content:"\f1b7"}.fa.fa-automobile:before{content:"\f1b9"}.fa.fa-cab:before{content:"\f1ba"}.fa.fa-deviantart,.fa.fa-soundcloud,.fa.fa-spotify{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-file-pdf-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-pdf-o:before{content:"\f1c1"}.fa.fa-file-word-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-word-o:before{content:"\f1c2"}.fa.fa-file-excel-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-excel-o:before{content:"\f1c3"}.fa.fa-file-powerpoint-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-powerpoint-o:before{content:"\f1c4"}.fa.fa-file-image-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-image-o:before{content:"\f1c5"}.fa.fa-file-photo-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-photo-o:before{content:"\f1c5"}.fa.fa-file-picture-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-picture-o:before{content:"\f1c5"}.fa.fa-file-archive-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-archive-o:before{content:"\f1c6"}.fa.fa-file-zip-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-zip-o:before{content:"\f1c6"}.fa.fa-file-audio-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-audio-o:before{content:"\f1c7"}.fa.fa-file-sound-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-sound-o:before{content:"\f1c7"}.fa.fa-file-video-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-video-o:before{content:"\f1c8"}.fa.fa-file-movie-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-movie-o:before{content:"\f1c8"}.fa.fa-file-code-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-code-o:before{content:"\f1c9"}.fa.fa-codepen,.fa.fa-jsfiddle,.fa.fa-vine{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-life-bouy:before,.fa.fa-life-buoy:before,.fa.fa-life-saver:before,.fa.fa-support:before{content:"\f1cd"}.fa.fa-circle-o-notch:before{content:"\f1ce"}.fa.fa-ra,.fa.fa-rebel{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-ra:before{content:"\f1d0"}.fa.fa-resistance{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-resistance:before{content:"\f1d0"}.fa.fa-empire,.fa.fa-ge{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-ge:before{content:"\f1d1"}.fa.fa-git-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-git-square:before{content:"\f1d2"}.fa.fa-git,.fa.fa-hacker-news,.fa.fa-y-combinator-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-y-combinator-square:before{content:"\f1d4"}.fa.fa-yc-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-yc-square:before{content:"\f1d4"}.fa.fa-qq,.fa.fa-tencent-weibo,.fa.fa-wechat,.fa.fa-weixin{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-wechat:before{content:"\f1d7"}.fa.fa-send:before{content:"\f1d8"}.fa.fa-paper-plane-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-paper-plane-o:before{content:"\f1d8"}.fa.fa-send-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-send-o:before{content:"\f1d8"}.fa.fa-circle-thin{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-circle-thin:before{content:"\f111"}.fa.fa-header:before{content:"\f1dc"}.fa.fa-futbol-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-futbol-o:before{content:"\f1e3"}.fa.fa-soccer-ball-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-soccer-ball-o:before{content:"\f1e3"}.fa.fa-slideshare,.fa.fa-twitch,.fa.fa-yelp{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-newspaper-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-newspaper-o:before{content:"\f1ea"}.fa.fa-cc-amex,.fa.fa-cc-discover,.fa.fa-cc-mastercard,.fa.fa-cc-paypal,.fa.fa-cc-stripe,.fa.fa-cc-visa,.fa.fa-google-wallet,.fa.fa-paypal{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-bell-slash-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-bell-slash-o:before{content:"\f1f6"}.fa.fa-trash:before{content:"\f2ed"}.fa.fa-copyright{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-eyedropper:before{content:"\f1fb"}.fa.fa-area-chart:before{content:"\f1fe"}.fa.fa-pie-chart:before{content:"\f200"}.fa.fa-line-chart:before{content:"\f201"}.fa.fa-lastfm,.fa.fa-lastfm-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-lastfm-square:before{content:"\f203"}.fa.fa-angellist,.fa.fa-ioxhost{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-cc{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-cc:before{content:"\f20a"}.fa.fa-ils:before,.fa.fa-shekel:before,.fa.fa-sheqel:before{content:"\f20b"}.fa.fa-buysellads,.fa.fa-connectdevelop,.fa.fa-dashcube,.fa.fa-forumbee,.fa.fa-leanpub,.fa.fa-sellsy,.fa.fa-shirtsinbulk,.fa.fa-simplybuilt,.fa.fa-skyatlas{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-diamond{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-diamond:before{content:"\f3a5"}.fa.fa-intersex:before,.fa.fa-transgender:before{content:"\f224"}.fa.fa-transgender-alt:before{content:"\f225"}.fa.fa-facebook-official{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-facebook-official:before{content:"\f09a"}.fa.fa-pinterest-p,.fa.fa-whatsapp{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-hotel:before{content:"\f236"}.fa.fa-medium,.fa.fa-viacoin,.fa.fa-y-combinator,.fa.fa-yc{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-yc:before{content:"\f23b"}.fa.fa-expeditedssl,.fa.fa-opencart,.fa.fa-optin-monster{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-battery-4:before,.fa.fa-battery:before{content:"\f240"}.fa.fa-battery-3:before{content:"\f241"}.fa.fa-battery-2:before{content:"\f242"}.fa.fa-battery-1:before{content:"\f243"}.fa.fa-battery-0:before{content:"\f244"}.fa.fa-object-group,.fa.fa-object-ungroup,.fa.fa-sticky-note-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-sticky-note-o:before{content:"\f249"}.fa.fa-cc-diners-club,.fa.fa-cc-jcb{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-clone{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hourglass-o:before{content:"\f254"}.fa.fa-hourglass-1:before{content:"\f251"}.fa.fa-hourglass-2:before{content:"\f252"}.fa.fa-hourglass-3:before{content:"\f253"}.fa.fa-hand-rock-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-rock-o:before{content:"\f255"}.fa.fa-hand-grab-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-grab-o:before{content:"\f255"}.fa.fa-hand-paper-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-paper-o:before{content:"\f256"}.fa.fa-hand-stop-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-stop-o:before{content:"\f256"}.fa.fa-hand-scissors-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-scissors-o:before{content:"\f257"}.fa.fa-hand-lizard-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-lizard-o:before{content:"\f258"}.fa.fa-hand-spock-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-spock-o:before{content:"\f259"}.fa.fa-hand-pointer-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-pointer-o:before{content:"\f25a"}.fa.fa-hand-peace-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-peace-o:before{content:"\f25b"}.fa.fa-registered{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-creative-commons,.fa.fa-gg,.fa.fa-gg-circle,.fa.fa-odnoklassniki,.fa.fa-odnoklassniki-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-odnoklassniki-square:before{content:"\f264"}.fa.fa-chrome,.fa.fa-firefox,.fa.fa-get-pocket,.fa.fa-internet-explorer,.fa.fa-opera,.fa.fa-safari,.fa.fa-wikipedia-w{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-television:before{content:"\f26c"}.fa.fa-500px,.fa.fa-amazon,.fa.fa-contao{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-calendar-plus-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-calendar-plus-o:before{content:"\f271"}.fa.fa-calendar-minus-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-calendar-minus-o:before{content:"\f272"}.fa.fa-calendar-times-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-calendar-times-o:before{content:"\f273"}.fa.fa-calendar-check-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-calendar-check-o:before{content:"\f274"}.fa.fa-map-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-map-o:before{content:"\f279"}.fa.fa-commenting:before{content:"\f4ad"}.fa.fa-commenting-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-commenting-o:before{content:"\f4ad"}.fa.fa-houzz,.fa.fa-vimeo{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-vimeo:before{content:"\f27d"}.fa.fa-black-tie,.fa.fa-edge,.fa.fa-fonticons,.fa.fa-reddit-alien{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-credit-card-alt:before{content:"\f09d"}.fa.fa-codiepie,.fa.fa-fort-awesome,.fa.fa-mixcloud,.fa.fa-modx,.fa.fa-product-hunt,.fa.fa-scribd,.fa.fa-usb{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-pause-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-pause-circle-o:before{content:"\f28b"}.fa.fa-stop-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-stop-circle-o:before{content:"\f28d"}.fa.fa-bluetooth,.fa.fa-bluetooth-b,.fa.fa-envira,.fa.fa-gitlab,.fa.fa-wheelchair-alt,.fa.fa-wpbeginner,.fa.fa-wpforms{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-wheelchair-alt:before{content:"\f368"}.fa.fa-question-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-question-circle-o:before{content:"\f059"}.fa.fa-volume-control-phone:before{content:"\f2a0"}.fa.fa-asl-interpreting:before{content:"\f2a3"}.fa.fa-deafness:before,.fa.fa-hard-of-hearing:before{content:"\f2a4"}.fa.fa-glide,.fa.fa-glide-g{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-signing:before{content:"\f2a7"}.fa.fa-viadeo,.fa.fa-viadeo-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-viadeo-square:before{content:"\f2aa"}.fa.fa-snapchat,.fa.fa-snapchat-ghost{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-snapchat-ghost:before{content:"\f2ab"}.fa.fa-snapchat-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-snapchat-square:before{content:"\f2ad"}.fa.fa-first-order,.fa.fa-google-plus-official,.fa.fa-pied-piper,.fa.fa-themeisle,.fa.fa-yoast{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-google-plus-official:before{content:"\f2b3"}.fa.fa-google-plus-circle{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-google-plus-circle:before{content:"\f2b3"}.fa.fa-fa,.fa.fa-font-awesome{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-fa:before{content:"\f2b4"}.fa.fa-handshake-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-handshake-o:before{content:"\f2b5"}.fa.fa-envelope-open-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-envelope-open-o:before{content:"\f2b6"}.fa.fa-linode{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-address-book-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-address-book-o:before{content:"\f2b9"}.fa.fa-vcard:before{content:"\f2bb"}.fa.fa-address-card-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-address-card-o:before{content:"\f2bb"}.fa.fa-vcard-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-vcard-o:before{content:"\f2bb"}.fa.fa-user-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-user-circle-o:before{content:"\f2bd"}.fa.fa-user-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-user-o:before{content:"\f007"}.fa.fa-id-badge{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-drivers-license:before{content:"\f2c2"}.fa.fa-id-card-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-id-card-o:before{content:"\f2c2"}.fa.fa-drivers-license-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-drivers-license-o:before{content:"\f2c2"}.fa.fa-free-code-camp,.fa.fa-quora,.fa.fa-telegram{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-thermometer-4:before,.fa.fa-thermometer:before{content:"\f2c7"}.fa.fa-thermometer-3:before{content:"\f2c8"}.fa.fa-thermometer-2:before{content:"\f2c9"}.fa.fa-thermometer-1:before{content:"\f2ca"}.fa.fa-thermometer-0:before{content:"\f2cb"}.fa.fa-bathtub:before,.fa.fa-s15:before{content:"\f2cd"}.fa.fa-window-maximize,.fa.fa-window-restore{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-times-rectangle:before{content:"\f410"}.fa.fa-window-close-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-window-close-o:before{content:"\f410"}.fa.fa-times-rectangle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-times-rectangle-o:before{content:"\f410"}.fa.fa-bandcamp,.fa.fa-eercast,.fa.fa-etsy,.fa.fa-grav,.fa.fa-imdb,.fa.fa-ravelry{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-eercast:before{content:"\f2da"}.fa.fa-snowflake-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-snowflake-o:before{content:"\f2dc"}.fa.fa-meetup,.fa.fa-superpowers,.fa.fa-wpexplorer{font-family:"Font Awesome 6 Brands";font-weight:400} \ No newline at end of file diff --git a/docs/deps/font-awesome-6.5.2/webfonts/fa-brands-400.ttf b/docs/deps/font-awesome-6.5.2/webfonts/fa-brands-400.ttf new file mode 100644 index 0000000..1fbb1f7 Binary files /dev/null and b/docs/deps/font-awesome-6.5.2/webfonts/fa-brands-400.ttf differ diff --git a/docs/deps/font-awesome-6.5.2/webfonts/fa-brands-400.woff2 b/docs/deps/font-awesome-6.5.2/webfonts/fa-brands-400.woff2 new file mode 100644 index 0000000..5d28021 Binary files /dev/null and b/docs/deps/font-awesome-6.5.2/webfonts/fa-brands-400.woff2 differ diff --git a/docs/deps/font-awesome-6.5.2/webfonts/fa-regular-400.ttf b/docs/deps/font-awesome-6.5.2/webfonts/fa-regular-400.ttf new file mode 100644 index 0000000..549d68d Binary files /dev/null and b/docs/deps/font-awesome-6.5.2/webfonts/fa-regular-400.ttf differ diff --git a/docs/deps/font-awesome-6.5.2/webfonts/fa-regular-400.woff2 b/docs/deps/font-awesome-6.5.2/webfonts/fa-regular-400.woff2 new file mode 100644 index 0000000..18400d7 Binary files /dev/null and b/docs/deps/font-awesome-6.5.2/webfonts/fa-regular-400.woff2 differ diff --git a/docs/deps/font-awesome-6.5.2/webfonts/fa-solid-900.ttf b/docs/deps/font-awesome-6.5.2/webfonts/fa-solid-900.ttf new file mode 100644 index 0000000..bb2a869 Binary files /dev/null and b/docs/deps/font-awesome-6.5.2/webfonts/fa-solid-900.ttf differ diff --git a/docs/deps/font-awesome-6.5.2/webfonts/fa-solid-900.woff2 b/docs/deps/font-awesome-6.5.2/webfonts/fa-solid-900.woff2 new file mode 100644 index 0000000..758dd4f Binary files /dev/null and b/docs/deps/font-awesome-6.5.2/webfonts/fa-solid-900.woff2 differ diff --git a/docs/deps/font-awesome-6.5.2/webfonts/fa-v4compatibility.ttf b/docs/deps/font-awesome-6.5.2/webfonts/fa-v4compatibility.ttf new file mode 100644 index 0000000..8c5864c Binary files /dev/null and b/docs/deps/font-awesome-6.5.2/webfonts/fa-v4compatibility.ttf differ diff --git a/docs/deps/font-awesome-6.5.2/webfonts/fa-v4compatibility.woff2 b/docs/deps/font-awesome-6.5.2/webfonts/fa-v4compatibility.woff2 new file mode 100644 index 0000000..f94bec2 Binary files /dev/null and b/docs/deps/font-awesome-6.5.2/webfonts/fa-v4compatibility.woff2 differ diff --git a/docs/deps/headroom-0.11.0/headroom.min.js b/docs/deps/headroom-0.11.0/headroom.min.js new file mode 100644 index 0000000..433069f --- /dev/null +++ b/docs/deps/headroom-0.11.0/headroom.min.js @@ -0,0 +1,7 @@ +/*! + * headroom.js v0.11.0 - Give your page some headroom. Hide your header until you need it + * Copyright (c) 2020 Nick Williams - http://wicky.nillia.ms/headroom.js + * License: MIT + */ + +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(t=t||self).Headroom=n()}(this,function(){"use strict";function t(){return"undefined"!=typeof window}function d(t){return function(t){return t&&t.document&&function(t){return 9===t.nodeType}(t.document)}(t)?function(t){var n=t.document,o=n.body,s=n.documentElement;return{scrollHeight:function(){return Math.max(o.scrollHeight,s.scrollHeight,o.offsetHeight,s.offsetHeight,o.clientHeight,s.clientHeight)},height:function(){return t.innerHeight||s.clientHeight||o.clientHeight},scrollY:function(){return void 0!==t.pageYOffset?t.pageYOffset:(s||o.parentNode||o).scrollTop}}}(t):function(t){return{scrollHeight:function(){return Math.max(t.scrollHeight,t.offsetHeight,t.clientHeight)},height:function(){return Math.max(t.offsetHeight,t.clientHeight)},scrollY:function(){return t.scrollTop}}}(t)}function n(t,s,e){var n,o=function(){var n=!1;try{var t={get passive(){n=!0}};window.addEventListener("test",t,t),window.removeEventListener("test",t,t)}catch(t){n=!1}return n}(),i=!1,r=d(t),l=r.scrollY(),a={};function c(){var t=Math.round(r.scrollY()),n=r.height(),o=r.scrollHeight();a.scrollY=t,a.lastScrollY=l,a.direction=ls.tolerance[a.direction],e(a),l=t,i=!1}function h(){i||(i=!0,n=requestAnimationFrame(c))}var u=!!o&&{passive:!0,capture:!1};return t.addEventListener("scroll",h,u),c(),{destroy:function(){cancelAnimationFrame(n),t.removeEventListener("scroll",h,u)}}}function o(t,n){n=n||{},Object.assign(this,o.options,n),this.classes=Object.assign({},o.options.classes,n.classes),this.elem=t,this.tolerance=function(t){return t===Object(t)?t:{down:t,up:t}}(this.tolerance),this.initialised=!1,this.frozen=!1}return o.prototype={constructor:o,init:function(){return o.cutsTheMustard&&!this.initialised&&(this.addClass("initial"),this.initialised=!0,setTimeout(function(t){t.scrollTracker=n(t.scroller,{offset:t.offset,tolerance:t.tolerance},t.update.bind(t))},100,this)),this},destroy:function(){this.initialised=!1,Object.keys(this.classes).forEach(this.removeClass,this),this.scrollTracker.destroy()},unpin:function(){!this.hasClass("pinned")&&this.hasClass("unpinned")||(this.addClass("unpinned"),this.removeClass("pinned"),this.onUnpin&&this.onUnpin.call(this))},pin:function(){this.hasClass("unpinned")&&(this.addClass("pinned"),this.removeClass("unpinned"),this.onPin&&this.onPin.call(this))},freeze:function(){this.frozen=!0,this.addClass("frozen")},unfreeze:function(){this.frozen=!1,this.removeClass("frozen")},top:function(){this.hasClass("top")||(this.addClass("top"),this.removeClass("notTop"),this.onTop&&this.onTop.call(this))},notTop:function(){this.hasClass("notTop")||(this.addClass("notTop"),this.removeClass("top"),this.onNotTop&&this.onNotTop.call(this))},bottom:function(){this.hasClass("bottom")||(this.addClass("bottom"),this.removeClass("notBottom"),this.onBottom&&this.onBottom.call(this))},notBottom:function(){this.hasClass("notBottom")||(this.addClass("notBottom"),this.removeClass("bottom"),this.onNotBottom&&this.onNotBottom.call(this))},shouldUnpin:function(t){return"down"===t.direction&&!t.top&&t.toleranceExceeded},shouldPin:function(t){return"up"===t.direction&&t.toleranceExceeded||t.top},addClass:function(t){this.elem.classList.add.apply(this.elem.classList,this.classes[t].split(" "))},removeClass:function(t){this.elem.classList.remove.apply(this.elem.classList,this.classes[t].split(" "))},hasClass:function(t){return this.classes[t].split(" ").every(function(t){return this.classList.contains(t)},this.elem)},update:function(t){t.isOutOfBounds||!0!==this.frozen&&(t.top?this.top():this.notTop(),t.bottom?this.bottom():this.notBottom(),this.shouldUnpin(t)?this.unpin():this.shouldPin(t)&&this.pin())}},o.options={tolerance:{up:0,down:0},offset:0,scroller:t()?window:null,classes:{frozen:"headroom--frozen",pinned:"headroom--pinned",unpinned:"headroom--unpinned",top:"headroom--top",notTop:"headroom--not-top",bottom:"headroom--bottom",notBottom:"headroom--not-bottom",initial:"headroom"}},o.cutsTheMustard=!!(t()&&function(){}.bind&&"classList"in document.documentElement&&Object.assign&&Object.keys&&requestAnimationFrame),o}); \ No newline at end of file diff --git a/docs/deps/headroom-0.11.0/jQuery.headroom.min.js b/docs/deps/headroom-0.11.0/jQuery.headroom.min.js new file mode 100644 index 0000000..17f70c9 --- /dev/null +++ b/docs/deps/headroom-0.11.0/jQuery.headroom.min.js @@ -0,0 +1,7 @@ +/*! + * headroom.js v0.9.4 - Give your page some headroom. Hide your header until you need it + * Copyright (c) 2017 Nick Williams - http://wicky.nillia.ms/headroom.js + * License: MIT + */ + +!function(a){a&&(a.fn.headroom=function(b){return this.each(function(){var c=a(this),d=c.data("headroom"),e="object"==typeof b&&b;e=a.extend(!0,{},Headroom.options,e),d||(d=new Headroom(this,e),d.init(),c.data("headroom",d)),"string"==typeof b&&(d[b](),"destroy"===b&&c.removeData("headroom"))})},a("[data-headroom]").each(function(){var b=a(this);b.headroom(b.data())}))}(window.Zepto||window.jQuery); \ No newline at end of file diff --git a/docs/deps/jquery-3.6.0/jquery-3.6.0.js b/docs/deps/jquery-3.6.0/jquery-3.6.0.js new file mode 100644 index 0000000..fc6c299 --- /dev/null +++ b/docs/deps/jquery-3.6.0/jquery-3.6.0.js @@ -0,0 +1,10881 @@ +/*! + * jQuery JavaScript Library v3.6.0 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2021-03-02T17:08Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.6.0", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.6 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2021-02-16 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +} +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the primary Deferred + primary = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + primary.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( primary.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return primary.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); + } + + return primary.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
    " ], + col: [ 2, "", "
    " ], + tr: [ 2, "", "
    " ], + td: [ 3, "", "
    " ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + + // Support: Chrome 86+ + // In Chrome, if an element having a focusout handler is blurred by + // clicking outside of it, it invokes the handler synchronously. If + // that handler calls `.remove()` on the element, the data is cleared, + // leaving `result` undefined. We need to guard against this. + return result && result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + which: true +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + // Suppress native focus or blur as it's already being fired + // in leverageNative. + _default: function() { + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + // + // Support: Firefox 70+ + // Only Firefox includes border widths + // in computed dimensions. (gh-4529) + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; + tr.style.cssText = "border:1px solid"; + + // Support: Chrome 86+ + // Height set through cssText does not get applied. + // Computed height then comes back as 0. + tr.style.height = "1px"; + trChild.style.height = "9px"; + + // Support: Android 8 Chrome 86+ + // In our bodyBackground.html iframe, + // display for all div elements is set to "inline", + // which causes a problem only in Android 8 Chrome 86. + // Ensuring the div is display: block + // gets around this issue. + trChild.style.display = "block"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + + parseInt( trStyle.borderTopWidth, 10 ) + + parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml, parserErrorElem; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) {} + + parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; + if ( !xml || parserErrorElem ) { + jQuery.error( "Invalid XML: " + ( + parserErrorElem ? + jQuery.map( parserErrorElem.childNodes, function( el ) { + return el.textContent; + } ).join( "\n" ) : + data + ) ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ).filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ).map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + +originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script but not if jsonp + if ( !isSuccess && + jQuery.inArray( "script", s.dataTypes ) > -1 && + jQuery.inArray( "json", s.dataTypes ) < 0 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " - - - - - - - + +PathwayEmbed • PathwayEmbed + + + + + + + - - - -
    -
    -
    - -
    +
    +
    +
    +
    -

    We are focusing on 1-D embeddings of pathway state. +

    We are focusing on estimating intracellular signal transduction states vis distance embedding

    @@ -105,29 +85,41 @@

    InstallationUsage

    -library(PathwayEmbed)
    +library(PathwayEmbed)
     
     # Load example data included with the package
    -data(fake_test_object)
    +data("synthetic_test_object_100")
    +data("synthetic_test_metadata")
    +
    +# Check what pathways are availabel in the pre-constructed table
    +ListPathway() # summary page
    +ListPathway("Pathway") # what pathways are available
    +ListPathway("WNT") # what coefficient tables are available
    +
    +# Load pre-constructed pathway coefficient tables
    +Wnt_12h   <- LoadPathway("WNT3A_12H_ACTIVATION",  "mouse")
    +
    +# Input data preprocess 
    +matrix_12h   <- DataPreProcess(synthetic_test_object_100, Wnt_12h,   Seurat.object = TRUE)
    +
    +# Determine the global reference (ON and OFF)
    +pathwaystat_12h   <- PathwayMaxMin(matrix_12h,   Wnt_12h)
     
     # Compute pathway data
    -mds_results <- ComputeCellData(fake_test_object, pathway = "Wnt", distance.method = "manhattan", batch.size = 100) 
    +score_12h   <- ComputeCellData(matrix_12h,   pathwaystat_12h)
     
     # Prepare data for plotting
    -plot_data <- PreparePlotData(fake_test_object, mds_results, group = "genotype")
    +plot_data_12h   <- PreparePlotData(synthetic_test_metadata, score_12h,   group = "genotype")
     
     # Plot pathway activation
    -PlotPathway(to.plot = plot_data, pathway = "Wnt", group = "genotype", color = c("#ae282c", "#2066a8"))
    +PlotPathway(plot_data_12h,   "12hr Wnt",    "genotype", c("#ae282c", "#2066a8"))
     
     # Calculate percentage and do comparison between two groups (optional)
    -CalculatePercentage(to.plot = plot_data, group_var = "genotype")
    + CalculatePercentage(to.plot = plot_data_12h, group_var = "genotype")
    -
    - - - diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..f621cce --- /dev/null +++ b/docs/index.md @@ -0,0 +1,67 @@ +# PathwayEmbed + +## We are focusing on estimating intracellular signal transduction states vis distance embedding + +# PathwayEmbed + +[![Build +Status](https://github.com/RaredonLab/PathwayEmbed/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/RaredonLab/PathwayEmbed/actions) +[![License: +MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) + +PathwayEmbed is an R package for quantifying and visualizing +intracellular signaling pathway activation from transcriptomic data, +integrating pathway topology and gene expression data. + +------------------------------------------------------------------------ + +## Installation + +You can install the released version of PathwayEmbed from GitHub using: + +``` r +# Install remotes if you haven't already +if (!requireNamespace("remotes", quietly = TRUE)) { + install.packages("remotes") +} + +remotes::install_github("RaredonLab/PathwayEmbed") +``` + +------------------------------------------------------------------------ + +## Usage + +``` r +library(PathwayEmbed) + +# Load example data included with the package +data("synthetic_test_object_100") +data("synthetic_test_metadata") + +# Check what pathways are availabel in the pre-constructed table +ListPathway() # summary page +ListPathway("Pathway") # what pathways are available +ListPathway("WNT") # what coefficient tables are available + +# Load pre-constructed pathway coefficient tables +Wnt_12h <- LoadPathway("WNT3A_12H_ACTIVATION", "mouse") + +# Input data preprocess +matrix_12h <- DataPreProcess(synthetic_test_object_100, Wnt_12h, Seurat.object = TRUE) + +# Determine the global reference (ON and OFF) +pathwaystat_12h <- PathwayMaxMin(matrix_12h, Wnt_12h) + +# Compute pathway data +score_12h <- ComputeCellData(matrix_12h, pathwaystat_12h) + +# Prepare data for plotting +plot_data_12h <- PreparePlotData(synthetic_test_metadata, score_12h, group = "genotype") + +# Plot pathway activation +PlotPathway(plot_data_12h, "12hr Wnt", "genotype", c("#ae282c", "#2066a8")) + +# Calculate percentage and do comparison between two groups (optional) + CalculatePercentage(to.plot = plot_data_12h, group_var = "genotype") +``` diff --git a/docs/katex-auto.js b/docs/katex-auto.js new file mode 100644 index 0000000..2adab3a --- /dev/null +++ b/docs/katex-auto.js @@ -0,0 +1,16 @@ +// https://github.com/jgm/pandoc/blob/29fa97ab96b8e2d62d48326e1b949a71dc41f47a/src/Text/Pandoc/Writers/HTML.hs#L332-L345 +document.addEventListener("DOMContentLoaded", function () { + var mathElements = document.getElementsByClassName("math"); + var macros = []; + for (var i = 0; i < mathElements.length; i++) { + var texText = mathElements[i].firstChild; + if (mathElements[i].tagName == "SPAN") { + katex.render(texText.data, mathElements[i], { + displayMode: mathElements[i].classList.contains("display"), + throwOnError: false, + macros: macros, + fleqn: false + }); + } + } +}); diff --git a/docs/lightswitch.js b/docs/lightswitch.js new file mode 100644 index 0000000..3808ca1 --- /dev/null +++ b/docs/lightswitch.js @@ -0,0 +1,85 @@ + +/*! + * Color mode toggler for Bootstrap's docs (https://getbootstrap.com/) + * Copyright 2011-2023 The Bootstrap Authors + * Licensed under the Creative Commons Attribution 3.0 Unported License. + * Updates for {pkgdown} by the {bslib} authors, also licensed under CC-BY-3.0. + */ + +const getStoredTheme = () => localStorage.getItem('theme') +const setStoredTheme = theme => localStorage.setItem('theme', theme) + +const getPreferredTheme = () => { + const storedTheme = getStoredTheme() + if (storedTheme) { + return storedTheme + } + + return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' +} + +const setTheme = theme => { + if (theme === 'auto') { + document.documentElement.setAttribute('data-bs-theme', (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')) + } else { + document.documentElement.setAttribute('data-bs-theme', theme) + } +} + +function bsSetupThemeToggle() { + 'use strict' + + const showActiveTheme = (theme, focus = false) => { + var activeLabel, activeIcon; + + document.querySelectorAll('[data-bs-theme-value]').forEach(element => { + const buttonTheme = element.getAttribute('data-bs-theme-value') + const isActive = buttonTheme == theme + + element.classList.toggle('active', isActive) + element.setAttribute('aria-pressed', isActive) + + if (isActive) { + activeLabel = element.textContent; + activeIcon = element.querySelector('span').classList.value; + } + }) + + const themeSwitcher = document.querySelector('#dropdown-lightswitch') + if (!themeSwitcher) { + return + } + + themeSwitcher.setAttribute('aria-label', activeLabel) + themeSwitcher.querySelector('span').classList.value = activeIcon; + + if (focus) { + themeSwitcher.focus() + } + } + + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { + const storedTheme = getStoredTheme() + if (storedTheme !== 'light' && storedTheme !== 'dark') { + setTheme(getPreferredTheme()) + } + }) + + window.addEventListener('DOMContentLoaded', () => { + showActiveTheme(getPreferredTheme()) + + document + .querySelectorAll('[data-bs-theme-value]') + .forEach(toggle => { + toggle.addEventListener('click', () => { + const theme = toggle.getAttribute('data-bs-theme-value') + setTheme(theme) + setStoredTheme(theme) + showActiveTheme(theme, true) + }) + }) + }) +} + +setTheme(getPreferredTheme()); +bsSetupThemeToggle(); diff --git a/docs/llms.txt b/docs/llms.txt new file mode 100644 index 0000000..c6a3c94 --- /dev/null +++ b/docs/llms.txt @@ -0,0 +1,112 @@ +# PathwayEmbed + +## We are focusing on estimating intracellular signal transduction states vis distance embedding + +# PathwayEmbed + +[![Build +Status](https://github.com/RaredonLab/PathwayEmbed/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/RaredonLab/PathwayEmbed/actions) +[![License: +MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) + +PathwayEmbed is an R package for quantifying and visualizing +intracellular signaling pathway activation from transcriptomic data, +integrating pathway topology and gene expression data. + +------------------------------------------------------------------------ + +## Installation + +You can install the released version of PathwayEmbed from GitHub using: + +``` r +# Install remotes if you haven't already +if (!requireNamespace("remotes", quietly = TRUE)) { + install.packages("remotes") +} + +remotes::install_github("RaredonLab/PathwayEmbed") +``` + +------------------------------------------------------------------------ + +## Usage + +``` r +library(PathwayEmbed) + +# Load example data included with the package +data("synthetic_test_object_100") +data("synthetic_test_metadata") + +# Check what pathways are availabel in the pre-constructed table +ListPathway() # summary page +ListPathway("Pathway") # what pathways are available +ListPathway("WNT") # what coefficient tables are available + +# Load pre-constructed pathway coefficient tables +Wnt_12h <- LoadPathway("WNT3A_12H_ACTIVATION", "mouse") + +# Input data preprocess +matrix_12h <- DataPreProcess(synthetic_test_object_100, Wnt_12h, Seurat.object = TRUE) + +# Determine the global reference (ON and OFF) +pathwaystat_12h <- PathwayMaxMin(matrix_12h, Wnt_12h) + +# Compute pathway data +score_12h <- ComputeCellData(matrix_12h, pathwaystat_12h) + +# Prepare data for plotting +plot_data_12h <- PreparePlotData(synthetic_test_metadata, score_12h, group = "genotype") + +# Plot pathway activation +PlotPathway(plot_data_12h, "12hr Wnt", "genotype", c("#ae282c", "#2066a8")) + +# Calculate percentage and do comparison between two groups (optional) + CalculatePercentage(to.plot = plot_data_12h, group_var = "genotype") +``` + +# Package index + +## All functions + +- [`CalculatePercentage()`](https://raredonlab.github.io/PathwayEmbed/reference/CalculatePercentage.md) + : CalculatePercentage +- [`ComputeCellData()`](https://raredonlab.github.io/PathwayEmbed/reference/ComputeCellData.md) + : ComputeCellData +- [`DataPreProcess()`](https://raredonlab.github.io/PathwayEmbed/reference/DataPreProcess.md) + : DataPreProcess +- [`ListPathway()`](https://raredonlab.github.io/PathwayEmbed/reference/ListPathway.md) + : ListPathway List available pathways or pathway metadata +- [`LoadPathway()`](https://raredonlab.github.io/PathwayEmbed/reference/LoadPathway.md) + : LoadPathway +- [`PathwayMaxMin()`](https://raredonlab.github.io/PathwayEmbed/reference/PathwayMaxMin.md) + : PathwayMaxMin +- [`PlotPathway()`](https://raredonlab.github.io/PathwayEmbed/reference/PlotPathway.md) + : PlotPathway +- [`PreparePlotData()`](https://raredonlab.github.io/PathwayEmbed/reference/PreparePlotData.md) + : PreparePlotData +- [`synthetic_test_matrix`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_matrix.md) + : Example Matrix for Testing +- [`synthetic_test_matrix_100`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_matrix_100.md) + : Expanded Example Matrix for Testing (100 genes) +- [`synthetic_test_metadata`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_metadata.md) + : synthetic metadata for test cells +- [`synthetic_test_object`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object.md) + : Example Seurat Object for Testing +- [`synthetic_test_object_100`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object_100.md) + : Expanded Example Seurat Object for Testing (100 genes) + +# Articles + +### All vignettes + +- [Beta-Catenin Knockout Analysis with + PathwayEmbed](https://raredonlab.github.io/PathwayEmbed/articles/beta_catenin_ko_updated.md): +- [Toy + Set](https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.md): +- [Notch_Analysis](https://raredonlab.github.io/PathwayEmbed/articles/Notch_Analysis_updated.md): +- [Spatial Pathway + Visualization](https://raredonlab.github.io/PathwayEmbed/articles/spatial_pathway_updated.md): +- [TGF-β Pathway Database + Construction](https://raredonlab.github.io/PathwayEmbed/articles/TGFB_database_construction.md): diff --git a/docs/pkgdown.css b/docs/pkgdown.css deleted file mode 100644 index 80ea5b8..0000000 --- a/docs/pkgdown.css +++ /dev/null @@ -1,384 +0,0 @@ -/* Sticky footer */ - -/** - * Basic idea: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/ - * Details: https://github.com/philipwalton/solved-by-flexbox/blob/master/assets/css/components/site.css - * - * .Site -> body > .container - * .Site-content -> body > .container .row - * .footer -> footer - * - * Key idea seems to be to ensure that .container and __all its parents__ - * have height set to 100% - * - */ - -html, body { - height: 100%; -} - -body { - position: relative; -} - -body > .container { - display: flex; - height: 100%; - flex-direction: column; -} - -body > .container .row { - flex: 1 0 auto; -} - -footer { - margin-top: 45px; - padding: 35px 0 36px; - border-top: 1px solid #e5e5e5; - color: #666; - display: flex; - flex-shrink: 0; -} -footer p { - margin-bottom: 0; -} -footer div { - flex: 1; -} -footer .pkgdown { - text-align: right; -} -footer p { - margin-bottom: 0; -} - -img.icon { - float: right; -} - -/* Ensure in-page images don't run outside their container */ -.contents img { - max-width: 100%; - height: auto; -} - -/* Fix bug in bootstrap (only seen in firefox) */ -summary { - display: list-item; -} - -/* Typographic tweaking ---------------------------------*/ - -.contents .page-header { - margin-top: calc(-60px + 1em); -} - -dd { - margin-left: 3em; -} - -/* Section anchors ---------------------------------*/ - -a.anchor { - display: none; - margin-left: 5px; - width: 20px; - height: 20px; - - background-image: url(./link.svg); - background-repeat: no-repeat; - background-size: 20px 20px; - background-position: center center; -} - -h1:hover .anchor, -h2:hover .anchor, -h3:hover .anchor, -h4:hover .anchor, -h5:hover .anchor, -h6:hover .anchor { - display: inline-block; -} - -/* Fixes for fixed navbar --------------------------*/ - -.contents h1, .contents h2, .contents h3, .contents h4 { - padding-top: 60px; - margin-top: -40px; -} - -/* Navbar submenu --------------------------*/ - -.dropdown-submenu { - position: relative; -} - -.dropdown-submenu>.dropdown-menu { - top: 0; - left: 100%; - margin-top: -6px; - margin-left: -1px; - border-radius: 0 6px 6px 6px; -} - -.dropdown-submenu:hover>.dropdown-menu { - display: block; -} - -.dropdown-submenu>a:after { - display: block; - content: " "; - float: right; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; - border-width: 5px 0 5px 5px; - border-left-color: #cccccc; - margin-top: 5px; - margin-right: -10px; -} - -.dropdown-submenu:hover>a:after { - border-left-color: #ffffff; -} - -.dropdown-submenu.pull-left { - float: none; -} - -.dropdown-submenu.pull-left>.dropdown-menu { - left: -100%; - margin-left: 10px; - border-radius: 6px 0 6px 6px; -} - -/* Sidebar --------------------------*/ - -#pkgdown-sidebar { - margin-top: 30px; - position: -webkit-sticky; - position: sticky; - top: 70px; -} - -#pkgdown-sidebar h2 { - font-size: 1.5em; - margin-top: 1em; -} - -#pkgdown-sidebar h2:first-child { - margin-top: 0; -} - -#pkgdown-sidebar .list-unstyled li { - margin-bottom: 0.5em; -} - -/* bootstrap-toc tweaks ------------------------------------------------------*/ - -/* All levels of nav */ - -nav[data-toggle='toc'] .nav > li > a { - padding: 4px 20px 4px 6px; - font-size: 1.5rem; - font-weight: 400; - color: inherit; -} - -nav[data-toggle='toc'] .nav > li > a:hover, -nav[data-toggle='toc'] .nav > li > a:focus { - padding-left: 5px; - color: inherit; - border-left: 1px solid #878787; -} - -nav[data-toggle='toc'] .nav > .active > a, -nav[data-toggle='toc'] .nav > .active:hover > a, -nav[data-toggle='toc'] .nav > .active:focus > a { - padding-left: 5px; - font-size: 1.5rem; - font-weight: 400; - color: inherit; - border-left: 2px solid #878787; -} - -/* Nav: second level (shown on .active) */ - -nav[data-toggle='toc'] .nav .nav { - display: none; /* Hide by default, but at >768px, show it */ - padding-bottom: 10px; -} - -nav[data-toggle='toc'] .nav .nav > li > a { - padding-left: 16px; - font-size: 1.35rem; -} - -nav[data-toggle='toc'] .nav .nav > li > a:hover, -nav[data-toggle='toc'] .nav .nav > li > a:focus { - padding-left: 15px; -} - -nav[data-toggle='toc'] .nav .nav > .active > a, -nav[data-toggle='toc'] .nav .nav > .active:hover > a, -nav[data-toggle='toc'] .nav .nav > .active:focus > a { - padding-left: 15px; - font-weight: 500; - font-size: 1.35rem; -} - -/* orcid ------------------------------------------------------------------- */ - -.orcid { - font-size: 16px; - color: #A6CE39; - /* margins are required by official ORCID trademark and display guidelines */ - margin-left:4px; - margin-right:4px; - vertical-align: middle; -} - -/* Reference index & topics ----------------------------------------------- */ - -.ref-index th {font-weight: normal;} - -.ref-index td {vertical-align: top; min-width: 100px} -.ref-index .icon {width: 40px;} -.ref-index .alias {width: 40%;} -.ref-index-icons .alias {width: calc(40% - 40px);} -.ref-index .title {width: 60%;} - -.ref-arguments th {text-align: right; padding-right: 10px;} -.ref-arguments th, .ref-arguments td {vertical-align: top; min-width: 100px} -.ref-arguments .name {width: 20%;} -.ref-arguments .desc {width: 80%;} - -/* Nice scrolling for wide elements --------------------------------------- */ - -table { - display: block; - overflow: auto; -} - -/* Syntax highlighting ---------------------------------------------------- */ - -pre, code, pre code { - background-color: #f8f8f8; - color: #333; -} -pre, pre code { - white-space: pre-wrap; - word-break: break-all; - overflow-wrap: break-word; -} - -pre { - border: 1px solid #eee; -} - -pre .img, pre .r-plt { - margin: 5px 0; -} - -pre .img img, pre .r-plt img { - background-color: #fff; -} - -code a, pre a { - color: #375f84; -} - -a.sourceLine:hover { - text-decoration: none; -} - -.fl {color: #1514b5;} -.fu {color: #000000;} /* function */ -.ch,.st {color: #036a07;} /* string */ -.kw {color: #264D66;} /* keyword */ -.co {color: #888888;} /* comment */ - -.error {font-weight: bolder;} -.warning {font-weight: bolder;} - -/* Clipboard --------------------------*/ - -.hasCopyButton { - position: relative; -} - -.btn-copy-ex { - position: absolute; - right: 0; - top: 0; - visibility: hidden; -} - -.hasCopyButton:hover button.btn-copy-ex { - visibility: visible; -} - -/* headroom.js ------------------------ */ - -.headroom { - will-change: transform; - transition: transform 200ms linear; -} -.headroom--pinned { - transform: translateY(0%); -} -.headroom--unpinned { - transform: translateY(-100%); -} - -/* mark.js ----------------------------*/ - -mark { - background-color: rgba(255, 255, 51, 0.5); - border-bottom: 2px solid rgba(255, 153, 51, 0.3); - padding: 1px; -} - -/* vertical spacing after htmlwidgets */ -.html-widget { - margin-bottom: 10px; -} - -/* fontawesome ------------------------ */ - -.fab { - font-family: "Font Awesome 5 Brands" !important; -} - -/* don't display links in code chunks when printing */ -/* source: https://stackoverflow.com/a/10781533 */ -@media print { - code a:link:after, code a:visited:after { - content: ""; - } -} - -/* Section anchors --------------------------------- - Added in pandoc 2.11: https://github.com/jgm/pandoc-templates/commit/9904bf71 -*/ - -div.csl-bib-body { } -div.csl-entry { - clear: both; -} -.hanging-indent div.csl-entry { - margin-left:2em; - text-indent:-2em; -} -div.csl-left-margin { - min-width:2em; - float:left; -} -div.csl-right-inline { - margin-left:2em; - padding-left:1em; -} -div.csl-indent { - margin-left: 2em; -} diff --git a/docs/pkgdown.js b/docs/pkgdown.js index 6f0eee4..0a5573a 100644 --- a/docs/pkgdown.js +++ b/docs/pkgdown.js @@ -1,108 +1,162 @@ /* http://gregfranko.com/blog/jquery-best-practices/ */ -(function($) { - $(function() { +(function ($) { + $(function () { - $('.navbar-fixed-top').headroom(); + $('nav.navbar').headroom(); - $('body').css('padding-top', $('.navbar').height() + 10); - $(window).resize(function(){ - $('body').css('padding-top', $('.navbar').height() + 10); + Toc.init({ + $nav: $("#toc"), + $scope: $("main h2, main h3, main h4, main h5, main h6") }); - $('[data-toggle="tooltip"]').tooltip(); - - var cur_path = paths(location.pathname); - var links = $("#navbar ul li a"); - var max_length = -1; - var pos = -1; - for (var i = 0; i < links.length; i++) { - if (links[i].getAttribute("href") === "#") - continue; - // Ignore external links - if (links[i].host !== location.host) - continue; - - var nav_path = paths(links[i].pathname); - - var length = prefix_length(nav_path, cur_path); - if (length > max_length) { - max_length = length; - pos = i; - } + if ($('#toc').length) { + $('body').scrollspy({ + target: '#toc', + offset: $("nav.navbar").outerHeight() + 1 + }); } - // Add class to parent
  • , and enclosing
  • if in dropdown - if (pos >= 0) { - var menu_anchor = $(links[pos]); - menu_anchor.parent().addClass("active"); - menu_anchor.closest("li.dropdown").addClass("active"); - } - }); - - function paths(pathname) { - var pieces = pathname.split("/"); - pieces.shift(); // always starts with / + // Activate popovers + $('[data-bs-toggle="popover"]').popover({ + container: 'body', + html: true, + trigger: 'focus', + placement: "top", + sanitize: false, + }); - var end = pieces[pieces.length - 1]; - if (end === "index.html" || end === "") - pieces.pop(); - return(pieces); - } + $('[data-bs-toggle="tooltip"]').tooltip(); - // Returns -1 if not found - function prefix_length(needle, haystack) { - if (needle.length > haystack.length) - return(-1); + /* Clipboard --------------------------*/ - // Special case for length-0 haystack, since for loop won't run - if (haystack.length === 0) { - return(needle.length === 0 ? 0 : -1); + function changeTooltipMessage(element, msg) { + var tooltipOriginalTitle = element.getAttribute('data-bs-original-title'); + element.setAttribute('data-bs-original-title', msg); + $(element).tooltip('show'); + element.setAttribute('data-bs-original-title', tooltipOriginalTitle); } - for (var i = 0; i < haystack.length; i++) { - if (needle[i] != haystack[i]) - return(i); - } + if (ClipboardJS.isSupported()) { + $(document).ready(function () { + var copyButton = ""; - return(haystack.length); - } + $("div.sourceCode").addClass("hasCopyButton"); - /* Clipboard --------------------------*/ + // Insert copy buttons: + $(copyButton).prependTo(".hasCopyButton"); - function changeTooltipMessage(element, msg) { - var tooltipOriginalTitle=element.getAttribute('data-original-title'); - element.setAttribute('data-original-title', msg); - $(element).tooltip('show'); - element.setAttribute('data-original-title', tooltipOriginalTitle); - } + // Initialize tooltips: + $('.btn-copy-ex').tooltip({ container: 'body' }); - if(ClipboardJS.isSupported()) { - $(document).ready(function() { - var copyButton = ""; + // Initialize clipboard: + var clipboard = new ClipboardJS('[data-clipboard-copy]', { + text: function (trigger) { + return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, ""); + } + }); - $("div.sourceCode").addClass("hasCopyButton"); + clipboard.on('success', function (e) { + changeTooltipMessage(e.trigger, 'Copied!'); + e.clearSelection(); + }); - // Insert copy buttons: - $(copyButton).prependTo(".hasCopyButton"); + clipboard.on('error', function (e) { + changeTooltipMessage(e.trigger, 'Press Ctrl+C or Command+C to copy'); + }); - // Initialize tooltips: - $('.btn-copy-ex').tooltip({container: 'body'}); + }); + } - // Initialize clipboard: - var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', { - text: function(trigger) { - return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, ""); + /* Search marking --------------------------*/ + var url = new URL(window.location.href); + var toMark = url.searchParams.get("q"); + var mark = new Mark("main#main"); + if (toMark) { + mark.mark(toMark, { + accuracy: { + value: "complementary", + limiters: [",", ".", ":", "/"], } }); + } - clipboardBtnCopies.on('success', function(e) { - changeTooltipMessage(e.trigger, 'Copied!'); - e.clearSelection(); - }); + /* Search --------------------------*/ + /* Adapted from https://github.com/rstudio/bookdown/blob/2d692ba4b61f1e466c92e78fd712b0ab08c11d31/inst/resources/bs4_book/bs4_book.js#L25 */ + // Initialise search index on focus + var fuse; + $("#search-input").focus(async function (e) { + if (fuse) { + return; + } - clipboardBtnCopies.on('error', function() { - changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); - }); + $(e.target).addClass("loading"); + var response = await fetch($("#search-input").data("search-index")); + var data = await response.json(); + + var options = { + keys: ["what", "text", "code"], + ignoreLocation: true, + threshold: 0.1, + includeMatches: true, + includeScore: true, + }; + fuse = new Fuse(data, options); + + $(e.target).removeClass("loading"); }); - } + + // Use algolia autocomplete + var options = { + autoselect: true, + debug: true, + hint: false, + minLength: 2, + }; + var q; + async function searchFuse(query, callback) { + await fuse; + + var items; + if (!fuse) { + items = []; + } else { + q = query; + var results = fuse.search(query, { limit: 20 }); + items = results + .filter((x) => x.score <= 0.75) + .map((x) => x.item); + if (items.length === 0) { + items = [{ dir: "Sorry 😿", previous_headings: "", title: "No results found.", what: "No results found.", path: window.location.href }]; + } + } + callback(items); + } + $("#search-input").autocomplete(options, [ + { + name: "content", + source: searchFuse, + templates: { + suggestion: (s) => { + if (s.title == s.what) { + return `${s.dir} >
    ${s.title}
    `; + } else if (s.previous_headings == "") { + return `${s.dir} >
    ${s.title}
    > ${s.what}`; + } else { + return `${s.dir} >
    ${s.title}
    > ${s.previous_headings} > ${s.what}`; + } + }, + }, + }, + ]).on('autocomplete:selected', function (event, s) { + window.location.href = s.path + "?q=" + q + "#" + s.id; + }); + }); })(window.jQuery || window.$) + +document.addEventListener('keydown', function (event) { + // Check if the pressed key is '/' + if (event.key === '/') { + event.preventDefault(); // Prevent any default action associated with the '/' key + document.getElementById('search-input').focus(); // Set focus to the search input + } +}); diff --git a/docs/pkgdown.yml b/docs/pkgdown.yml index 33d1f46..fe00aa5 100644 --- a/docs/pkgdown.yml +++ b/docs/pkgdown.yml @@ -1,8 +1,13 @@ pandoc: '3.2' -pkgdown: 2.1.3 +pkgdown: 2.2.0 pkgdown_sha: ~ articles: - beta_catenin_ko: beta_catenin_ko.html - examples: examples.html - spatial_pathway: spatial_pathway.html -last_built: 2025-08-08T18:32Z + beta_catenin_ko_updated: beta_catenin_ko_updated.html + examples_updated: examples_updated.html + Notch_Analysis_updated: Notch_Analysis_updated.html + spatial_pathway_updated: spatial_pathway_updated.html + TGFB_database_construction: TGFB_database_construction.html +last_built: 2026-04-03T02:53Z +urls: + reference: https://raredonlab.github.io/PathwayEmbed/reference + article: https://raredonlab.github.io/PathwayEmbed/articles diff --git a/docs/reference/CalculatePercentage.html b/docs/reference/CalculatePercentage.html index 5e32035..2ac85e6 100644 --- a/docs/reference/CalculatePercentage.html +++ b/docs/reference/CalculatePercentage.html @@ -1,117 +1,130 @@ -CalculatePercentage — CalculatePercentage • PathwayEmbed - - -
    -
    +
    +
    +
    -
    - -
    -

    This function calculates the percentage of cells in ON (scale > 0) and OFF (scale < 0) -activation states within each group defined by group_var. If exactly two groups -are provided, it also computes Cohen's d effect size between their activation values.

    +
    +

    Calculates the percentage of cells in ON (scale > 0) and OFF +(scale < 0) activation states within each group defined by +group_var.

    -
    +
    +

    Usage

    CalculatePercentage(to.plot, group_var)
    -
    -

    Arguments

    +
    +

    Arguments

    to.plot
    -

    A data frame containing at least a scale column and a grouping column.

    +

    A data frame from PreparePlotData(), containing at +least a scale column and the grouping column specified by +group_var.

    group_var
    -

    A string specifying the grouping variable (e.g., "genotype", "treatment").

    +

    A character string specifying the grouping column in +to.plot (e.g. "genotype", "treatment").

    -
    -

    Value

    -

    A data frame with the percentage of ON/OFF cells and Cohen's d (if applicable).

    +
    +

    Value

    +

    A data frame with columns:

    group
    +

    Group label.

    + +
    percentage_on
    +

    Percentage of cells with scale > 0.

    + +
    percentage_off
    +

    Percentage of cells with scale < 0.

    + +
    cohens_d
    +

    (2-group only) Cohen's d effect size. Repeated for +both group rows as it is a single pairwise estimate.

    + +
    p_value
    +

    (2-group only) Wilcoxon rank-sum p-value.

    + +
    kruskal_p
    +

    (3+ groups only) Kruskal-Wallis p-value.

    + + +

    For 3+ groups, Bonferroni-corrected pairwise Wilcoxon p-values are +attached via attr(result, "pairwise_wilcox").

    +
    +
    +

    Details

    +

    If exactly two groups are provided, Cohen's d effect size and a Wilcoxon +rank-sum p-value are computed between the two groups.

    +

    If more than two groups are provided, a Kruskal-Wallis p-value is computed +across all groups, and pairwise Wilcoxon p-values (Bonferroni-corrected) are +attached as an attribute.

    -
    -

    Examples

    -
    data(fake_to_plot)
    +    
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +data(fake_to_plot)
     CalculatePercentage(fake_to_plot, "genotype")
    -#> # A tibble: 2 × 4
    -#>   group  percentage_on percentage_off cohens_d
    -#>   <chr>          <dbl>          <dbl>    <dbl>
    -#> 1 WT               9.6           90.4    -2.81
    -#> 2 Mutant          98.4            1.6    -2.81
    +} # }
    +
     
    -
    - -
    +
    -
    - +
    diff --git a/docs/reference/CalculatePercentage.md b/docs/reference/CalculatePercentage.md new file mode 100644 index 0000000..2818776 --- /dev/null +++ b/docs/reference/CalculatePercentage.md @@ -0,0 +1,75 @@ +# CalculatePercentage + +Calculates the percentage of cells in ON (`scale > 0`) and OFF +(`scale < 0`) activation states within each group defined by +`group_var`. + +## Usage + +``` r +CalculatePercentage(to.plot, group_var) +``` + +## Arguments + +- to.plot: + + A data frame from + [`PreparePlotData()`](https://raredonlab.github.io/PathwayEmbed/reference/PreparePlotData.md), + containing at least a `scale` column and the grouping column specified + by `group_var`. + +- group_var: + + A character string specifying the grouping column in `to.plot` (e.g. + `"genotype"`, `"treatment"`). + +## Value + +A data frame with columns: + +- group: + + Group label. + +- percentage_on: + + Percentage of cells with `scale > 0`. + +- percentage_off: + + Percentage of cells with `scale < 0`. + +- cohens_d: + + (2-group only) Cohen's d effect size. Repeated for both group rows as + it is a single pairwise estimate. + +- p_value: + + (2-group only) Wilcoxon rank-sum p-value. + +- kruskal_p: + + (3+ groups only) Kruskal-Wallis p-value. + +For 3+ groups, Bonferroni-corrected pairwise Wilcoxon p-values are +attached via `attr(result, "pairwise_wilcox")`. + +## Details + +If exactly two groups are provided, Cohen's d effect size and a Wilcoxon +rank-sum p-value are computed between the two groups. + +If more than two groups are provided, a Kruskal-Wallis p-value is +computed across all groups, and pairwise Wilcoxon p-values +(Bonferroni-corrected) are attached as an attribute. + +## Examples + +``` r +if (FALSE) { # \dontrun{ +data(fake_to_plot) +CalculatePercentage(fake_to_plot, "genotype") +} # } +``` diff --git a/docs/reference/ComputeCellData.html b/docs/reference/ComputeCellData.html index b5c2a3f..1336e42 100644 --- a/docs/reference/ComputeCellData.html +++ b/docs/reference/ComputeCellData.html @@ -1,2148 +1,113 @@ -ComputeCellData — ComputeCellData • PathwayEmbed +ComputeCellData — ComputeCellData • PathwayEmbed + Skip to contents -
    -
    +
    +
    +
    -
    - -
    -

    A function computes cell status for a given pathway in single-cell RNA-seq data, -based on the distance between genes in a specified pathway. The distance is computed -for each batch of cells, and classical multidimensional scaling (MDS) is used to -visualize the pathway expression across cells.

    +
    +

    Computes a per-cell pathway activation score by measuring each cell's +distance to the pathway ON and OFF reference states from +PathwayMaxMin(). Scores are normalized to [0, 1]\, where 1 indicates +proximity to the ON state and 0 indicates proximity to the OFF state.

    -
    -
    ComputeCellData(
    -  x,
    -  pathway,
    -  distance.method,
    -  batch.size = batch.size,
    -  scale.data = TRUE
    -)
    +
    +

    Usage

    +
    ComputeCellData(expr_data, pathway.stat, distance.method = "manhattan")
    -
    -

    Arguments

    +
    +

    Arguments

    -
    x
    -

    A Seurat object containing single-cell RNA sequencing data.

    +
    expr_data
    +

    A z-scored gene-by-cell numeric matrix, e.g. from +DataPreProcess().

    -
    pathway
    -

    A character string specifying the pathway name. This should match a pathway used by LoadPathway().

    +
    pathway.stat
    +

    A data frame from PathwayMaxMin() with columns +pathway.on and pathway.off. Rownames must be gene symbols.

    distance.method
    -

    A character string specifying the distance metric to use.Default is "manhattan". -Options include: "manhattan", "euclidean", "canberra", "binary", "minkowski"

    - - -
    batch.size
    -

    An integer specifying the number of cells to process per batch. Default is 1000.

    - - -
    scale.data
    -

    A logical indicating whether to use scaled data (scale.data = TRUE) or normalized data. Default is TRUE.

    +

    Character string specifying the distance metric. +One of "manhattan" (default) or "euclidean".

    -
    -

    Value

    -

    A data frame of MDS results with normalized values per cell, suitable for thresholding or visualization.

    +
    +

    Value

    +

    A named numeric vector of length equal to the number of cells, +with scores in [0, 1]. A score near 1 indicates the cell is close to +the ON state; a score near 0 indicates proximity to the OFF state. +Cells where both distances are 0 return NaN with a warning.

    -
    -

    Examples

    -
    data(fake_test_object)
    -ComputeCellData(fake_test_object, pathway = "Wnt", distance.method = "manhattan", batch.size = 2000)
    -#> Centering and scaling data matrix
    -#> Warning: The `slot` argument of `GetAssayData()` is deprecated as of SeuratObject 5.0.0.
    -#>  Please use the `layer` argument instead.
    -#>  The deprecated feature was likely used in the PathwayEmbed package.
    -#>   Please report the issue to the authors.
    -#> Centering and scaling data matrix
    -#> Processing batch 1
    -#> Computing distance...
    -#> Running MDS ...
    -#> MDS finished
    -#> Batch 1 processed with 2000 cells
    -#>                        V1 normalized
    -#> pathway.on   2.553664e+01  1.0000000
    -#> pathway.off -1.385006e+02  0.0000000
    -#> Cell1197     2.187651e+00  0.8576605
    -#> Cell1431     2.977148e+00  0.8624734
    -#> Cell460     -2.546460e+00  0.8288005
    -#> Cell63      -3.237843e+00  0.8245857
    -#> Cell485     -5.101010e+00  0.8132275
    -#> Cell1894     3.336181e+00  0.8646621
    -#> Cell1903     5.533059e+00  0.8780547
    -#> Cell559     -4.417421e+00  0.8173948
    -#> Cell927     -1.347230e-01  0.8435029
    -#> Cell1476     4.472467e+00  0.8715891
    -#> Cell1225     3.467462e+00  0.8654624
    -#> Cell197     -5.139934e+00  0.8129902
    -#> Cell517     -2.511700e+00  0.8290124
    -#> Cell1791     1.478848e+00  0.8533395
    -#> Cell536     -2.115078e+00  0.8314303
    -#> Cell1871     4.390905e+00  0.8710919
    -#> Cell77      -2.387543e-01  0.8428687
    -#> Cell898     -2.657024e+00  0.8281265
    -#> Cell446     -8.450933e-01  0.8391723
    -#> Cell567     -2.598861e+00  0.8284811
    -#> Cell1451     5.470021e+00  0.8776704
    -#> Cell1086     2.239440e+00  0.8579762
    -#> Cell555     -3.771045e+00  0.8213352
    -#> Cell773      2.349337e+00  0.8586462
    -#> Cell1493     1.409664e+01  0.9302598
    -#> Cell1324     3.896961e+00  0.8680807
    -#> Cell546     -4.931889e+00  0.8142585
    -#> Cell70      -7.522571e+00  0.7984653
    -#> Cell447     -1.107174e+00  0.8375747
    -#> Cell1284     3.973831e+00  0.8685494
    -#> Cell752     -1.746462e+00  0.8336774
    -#> Cell674     -2.488876e+00  0.8291516
    -#> Cell1699     6.279597e+00  0.8826057
    -#> Cell1241     2.638256e+00  0.8604075
    -#> Cell726     -6.072288e+00  0.8073065
    -#> Cell1579     3.487952e+00  0.8655873
    -#> Cell1927     2.706802e+00  0.8608253
    -#> Cell1568     3.973536e+00  0.8685476
    -#> Cell1094     4.435874e+00  0.8713660
    -#> Cell265     -1.408844e+01  0.7584386
    -#> Cell150     -6.804775e+00  0.8028411
    -#> Cell1023     3.233407e+00  0.8640356
    -#> Cell1290     7.713514e+00  0.8913471
    -#> Cell1440     3.031405e+00  0.8628042
    -#> Cell117     -1.495638e+00  0.8352065
    -#> Cell930     -4.950148e+00  0.8141472
    -#> Cell1553     6.111334e+00  0.8815799
    -#> Cell180     -3.723328e+00  0.8216261
    -#> Cell1208     8.361884e-01  0.8494217
    -#> Cell22      -2.336217e+00  0.8300822
    -#> Cell1631     1.757163e+00  0.8550362
    -#> Cell1921     5.258278e+00  0.8763796
    -#> Cell1962     1.972807e+00  0.8563508
    -#> Cell1698     1.939627e+00  0.8561485
    -#> Cell179      9.596402e-01  0.8501743
    -#> Cell686     -3.143237e+00  0.8251625
    -#> Cell833     -1.010920e+00  0.8381614
    -#> Cell1561     3.923816e+00  0.8682445
    -#> Cell495     -3.997717e+00  0.8199534
    -#> Cell1522     4.194711e-02  0.8445799
    -#> Cell165      3.482031e-02  0.8445365
    -#> Cell264     -6.752699e+00  0.8031585
    -#> Cell673     -5.718999e+00  0.8094602
    -#> Cell736     -3.452739e+00  0.8232757
    -#> Cell876     -4.843860e-02  0.8440289
    -#> Cell1875     5.073292e+00  0.8752519
    -#> Cell604     -1.655241e+00  0.8342335
    -#> Cell1820     3.898603e+00  0.8680907
    -#> Cell1840     1.570116e+00  0.8538959
    -#> Cell1867     3.080942e+00  0.8631061
    -#> Cell986     -1.910366e+00  0.8326783
    -#> Cell1315     2.078346e+00  0.8569941
    -#> Cell130     -8.159773e+00  0.7945808
    -#> Cell1879     8.050219e+00  0.8933997
    -#> Cell874     -5.906678e+00  0.8083160
    -#> Cell643     -1.480603e+00  0.8352982
    -#> Cell1830    -2.443915e+00  0.8294256
    -#> Cell452      6.369148e-01  0.8482069
    -#> Cell746     -5.608155e-01  0.8409054
    -#> Cell577     -4.648033e+00  0.8159890
    -#> Cell743     -4.132135e+00  0.8191340
    -#> Cell902     -2.836086e+00  0.8270349
    -#> Cell1686     4.337423e+00  0.8707659
    -#> Cell1683     2.768362e+00  0.8612006
    -#> Cell1017     3.014114e+00  0.8626988
    -#> Cell1794     1.395343e+00  0.8528304
    -#> Cell1856     4.937359e+00  0.8744232
    -#> Cell1576     5.132836e+00  0.8756148
    -#> Cell1217     4.591427e-01  0.8471232
    -#> Cell156     -5.835136e+00  0.8087522
    -#> Cell1479     3.519981e+00  0.8657826
    -#> Cell1036     4.344174e+00  0.8708070
    -#> Cell1462     3.681621e+00  0.8667680
    -#> Cell1833     2.826915e+00  0.8615576
    -#> Cell42      -7.133920e+00  0.8008346
    -#> Cell1602     7.101675e+00  0.8876172
    -#> Cell102     -2.228033e+00  0.8307417
    -#> Cell1895     6.660881e+00  0.8849301
    -#> Cell794     -4.007671e+00  0.8198927
    -#> Cell828     -2.404265e+00  0.8296674
    -#> Cell502      2.357721e+00  0.8586973
    -#> Cell270     -6.929098e+00  0.8020832
    -#> Cell1977     2.884556e+00  0.8619089
    -#> Cell1511     3.600603e+00  0.8662741
    -#> Cell1395     3.115589e+00  0.8633174
    -#> Cell753     -1.058064e+01  0.7798228
    -#> Cell869     -5.734909e+00  0.8093632
    -#> Cell1809     4.959104e+00  0.8745557
    -#> Cell13      -1.336615e+00  0.8361759
    -#> Cell998     -3.556227e+00  0.8226448
    -#> Cell1633     2.869601e+00  0.8618178
    -#> Cell1441     4.315747e+00  0.8706337
    -#> Cell589     -5.908401e+00  0.8083055
    -#> Cell978     -8.250425e-01  0.8392946
    -#> Cell288     -3.839366e+00  0.8209187
    -#> Cell1989     1.791550e+00  0.8552458
    -#> Cell823     -4.865908e+00  0.8146608
    -#> Cell1547     3.497787e+00  0.8656473
    -#> Cell1828     3.585430e+00  0.8661816
    -#> Cell1287     3.720361e+00  0.8670042
    -#> Cell1687     2.846559e+00  0.8616773
    -#> Cell472     -2.709361e+00  0.8278074
    -#> Cell1974     2.421795e+00  0.8590879
    -#> Cell456      2.959891e+00  0.8623682
    -#> Cell841     -4.193895e+00  0.8187575
    -#> Cell1331     4.031491e+00  0.8689009
    -#> Cell1385     4.675322e+00  0.8728258
    -#> Cell955     -3.931901e+00  0.8203546
    -#> Cell1702     2.685914e+00  0.8606980
    -#> Cell877     -2.711916e+00  0.8277919
    -#> Cell237     -3.690337e+00  0.8218272
    -#> Cell537     -7.486860e+00  0.7986830
    -#> Cell1845     1.927294e+00  0.8560733
    -#> Cell1187     2.211473e+00  0.8578057
    -#> Cell1069     2.830607e+00  0.8615801
    -#> Cell210     -2.274699e+00  0.8304572
    -#> Cell407     -3.318487e+00  0.8240941
    -#> Cell1195     9.364764e+00  0.9014134
    -#> Cell4       -3.185461e+00  0.8249051
    -#> Cell418     -4.854738e+00  0.8147289
    -#> Cell809     -5.900812e+00  0.8083518
    -#> Cell82      -5.658418e+00  0.8098295
    -#> Cell606     -5.761866e+00  0.8091988
    -#> Cell1228     2.017230e+00  0.8566216
    -#> Cell1935     3.575984e+00  0.8661240
    -#> Cell384     -1.135996e-01  0.8436317
    -#> Cell145     -3.842299e+00  0.8209009
    -#> Cell1738     5.516290e+00  0.8779525
    -#> Cell748     -4.278771e+00  0.8182400
    -#> Cell269     -3.404980e+00  0.8235668
    -#> Cell432     -2.566191e+00  0.8286802
    -#> Cell1831     4.375985e+00  0.8710010
    -#> Cell1237     3.100348e+00  0.8632244
    -#> Cell1508     5.196014e+00  0.8760000
    -#> Cell1729     1.053436e+00  0.8507461
    -#> Cell1539     5.923649e+00  0.8804358
    -#> Cell1799     3.653703e+00  0.8665978
    -#> Cell689     -1.154593e+00  0.8372856
    -#> Cell198     -1.845843e+00  0.8330716
    -#> Cell1499     4.025919e+00  0.8688669
    -#> Cell1292     4.396208e+00  0.8711242
    -#> Cell295     -1.396820e+00  0.8358089
    -#> Cell395     -4.903640e+00  0.8144307
    -#> Cell1906     5.587828e+00  0.8783886
    -#> Cell40      -4.673462e+00  0.8158339
    -#> Cell758     -4.774790e+00  0.8152162
    -#> Cell113     -4.088663e+00  0.8193990
    -#> Cell492     -1.099543e+00  0.8376212
    -#> Cell1268     1.981964e+00  0.8564066
    -#> Cell527     -6.433225e+00  0.8051061
    -#> Cell1490     2.941128e+00  0.8622538
    -#> Cell812     -4.116034e+00  0.8192321
    -#> Cell950     -3.879478e+00  0.8206742
    -#> Cell597      2.877903e-01  0.8460786
    -#> Cell826     -4.623204e+00  0.8161403
    -#> Cell1053     4.239387e+00  0.8701682
    -#> Cell484     -2.890247e+00  0.8267047
    -#> Cell1005     5.166262e+00  0.8758186
    -#> Cell614     -1.422096e-01  0.8434572
    -#> Cell1166     2.632685e+00  0.8603735
    -#> Cell834     -3.667927e+00  0.8219639
    -#> Cell1916     2.767592e+00  0.8611959
    -#> Cell453      5.858527e-02  0.8446813
    -#> Cell1924     6.397852e+00  0.8833266
    -#> Cell549      1.917411e-01  0.8454931
    -#> Cell364     -3.557349e+00  0.8226380
    -#> Cell644     -2.377471e+00  0.8298307
    -#> Cell56      -4.258388e+00  0.8183643
    -#> Cell1332     3.549074e+00  0.8659600
    -#> Cell697     -5.651913e+00  0.8098691
    -#> Cell1681     5.007297e+00  0.8748495
    -#> Cell1495     3.037721e+00  0.8628427
    -#> Cell543     -3.521890e+00  0.8228541
    -#> Cell477     -8.262690e-01  0.8392871
    -#> Cell1716     3.509726e+00  0.8657201
    -#> Cell458     -3.216938e+00  0.8247132
    -#> Cell24      -4.355618e+00  0.8177716
    -#> Cell951     -4.708977e+00  0.8156174
    -#> Cell969     -4.185427e+00  0.8188091
    -#> Cell1792     3.923161e+00  0.8682405
    -#> Cell601     -3.824720e+00  0.8210080
    -#> Cell1546     6.873521e-01  0.8485144
    -#> Cell1876     2.297689e+00  0.8583313
    -#> Cell723     -3.242268e+00  0.8245588
    -#> Cell857     -3.880601e+00  0.8206674
    -#> Cell1203     3.828079e+00  0.8676608
    -#> Cell541     -1.570782e+00  0.8347484
    -#> Cell49      -2.564633e+00  0.8286897
    -#> Cell1103     2.058576e+00  0.8568736
    -#> Cell703     -3.201709e+00  0.8248060
    -#> Cell953     -4.987646e+00  0.8139186
    -#> Cell1808     2.902630e+00  0.8620191
    -#> Cell1873     6.854803e+00  0.8861123
    -#> Cell971      3.630673e-01  0.8465375
    -#> Cell1519     4.697006e+00  0.8729580
    -#> Cell310     -1.391486e+00  0.8358414
    -#> Cell1836     6.476657e+00  0.8838070
    -#> Cell956     -6.024846e+00  0.8075957
    -#> Cell1159     1.935235e+00  0.8561217
    -#> Cell691     -5.382385e+00  0.8115122
    -#> Cell1116     2.366846e+00  0.8587529
    -#> Cell1128     5.978390e+00  0.8807695
    -#> Cell771     -1.004896e+00  0.8381982
    -#> Cell1424     3.092833e+00  0.8631786
    -#> Cell584     -6.808329e+00  0.8028194
    -#> Cell396     -3.655225e+00  0.8220413
    -#> Cell760     -1.197136e+00  0.8370262
    -#> Cell1346     2.423370e-01  0.8458015
    -#> Cell583     -4.992521e+00  0.8138889
    -#> Cell722     -6.643534e+00  0.8038240
    -#> Cell538     -4.484421e+00  0.8169864
    -#> Cell832     -1.092899e+01  0.7776992
    -#> Cell1404     3.778424e+00  0.8673581
    -#> Cell1889     1.968310e+00  0.8563233
    -#> Cell1141     4.331806e+00  0.8707316
    -#> Cell1242     5.920307e+00  0.8804154
    -#> Cell1983     6.504761e+00  0.8839783
    -#> Cell57      -2.356628e+00  0.8299578
    -#> Cell43      -1.665190e+00  0.8341729
    -#> Cell1313    -1.398594e+00  0.8357981
    -#> Cell528      5.504613e-01  0.8476799
    -#> Cell87       1.443877e-01  0.8452044
    -#> Cell1020     2.450118e+00  0.8592605
    -#> Cell143     -3.802415e+00  0.8211440
    -#> Cell875     -5.022787e+00  0.8137044
    -#> Cell1056     4.792765e+00  0.8735417
    -#> Cell212     -3.941065e+00  0.8202988
    -#> Cell1243     2.913179e+00  0.8620834
    -#> Cell1949     5.004021e+00  0.8748296
    -#> Cell572     -2.332036e+00  0.8301077
    -#> Cell793     -5.820650e+00  0.8088405
    -#> Cell1661     2.551152e+00  0.8598765
    -#> Cell138     -8.311082e-01  0.8392576
    -#> Cell1978     6.962061e+00  0.8867661
    -#> Cell884     -1.040785e+00  0.8379794
    -#> Cell1391     2.796244e+00  0.8613706
    -#> Cell1084     3.509317e+00  0.8657176
    -#> Cell1997     3.814125e+00  0.8675758
    -#> Cell1466     1.497821e+00  0.8534552
    -#> Cell702     -3.037891e+00  0.8258047
    -#> Cell1570     4.885413e+00  0.8741065
    -#> Cell762     -8.678231e+00  0.7914202
    -#> Cell1837     4.501838e+00  0.8717682
    -#> Cell306     -1.653314e+00  0.8342453
    -#> Cell421     -5.784453e+00  0.8090611
    -#> Cell19      -1.838534e+00  0.8331162
    -#> Cell596     -4.342032e-01  0.8416772
    -#> Cell206     -7.439508e+00  0.7989716
    -#> Cell98       1.471492e-02  0.8444139
    -#> Cell646     -5.856347e+00  0.8086229
    -#> Cell1075     5.444444e+00  0.8775145
    -#> Cell1137     3.098294e+00  0.8632119
    -#> Cell984     -3.434539e+00  0.8233866
    -#> Cell168     -7.060415e+00  0.8012827
    -#> Cell734     -4.230782e+00  0.8185326
    -#> Cell470     -1.666421e+00  0.8341654
    -#> Cell968     -2.321066e+00  0.8301746
    -#> Cell654      2.377754e-01  0.8457737
    -#> Cell512     -8.234125e+00  0.7941275
    -#> Cell67      -6.091040e+00  0.8071921
    -#> Cell18      -4.235923e+00  0.8185013
    -#> Cell1007     3.175780e+00  0.8636843
    -#> Cell399     -5.438964e+00  0.8111673
    -#> Cell1780     2.640760e+00  0.8604227
    -#> Cell928     -2.648884e+00  0.8281761
    -#> Cell124     -4.866034e+00  0.8146600
    -#> Cell1986     2.029917e+00  0.8566989
    -#> Cell679     -6.261440e+00  0.8061533
    -#> Cell309     -1.806025e+00  0.8333143
    -#> Cell840     -4.835286e+00  0.8148474
    -#> Cell239     -1.063424e+01  0.7794960
    -#> Cell1189     5.023362e+00  0.8749475
    -#> Cell656     -2.560149e-01  0.8427635
    -#> Cell1587     9.429585e-01  0.8500726
    -#> Cell356     -6.475996e-01  0.8403763
    -#> Cell929     -9.602209e-02  0.8437388
    -#> Cell1049     2.646391e+00  0.8604570
    -#> Cell1870     3.617627e+00  0.8663779
    -#> Cell1111     4.923236e+00  0.8743371
    -#> Cell973     -3.095113e+00  0.8254558
    -#> Cell819     -1.361698e+00  0.8360230
    -#> Cell1311     3.189516e+00  0.8637680
    -#> Cell666     -7.208716e+00  0.8003786
    -#> Cell1272     5.116513e+00  0.8755153
    -#> Cell1411     6.102751e+00  0.8815276
    -#> Cell1854     5.331844e+00  0.8768280
    -#> Cell575     -1.013407e+00  0.8381463
    -#> Cell289     -3.440123e+00  0.8233526
    -#> Cell1513     2.163586e+00  0.8575138
    -#> Cell48      -2.005106e+00  0.8321007
    -#> Cell1258     2.951004e+00  0.8623140
    -#> Cell1976     4.420621e+00  0.8712731
    -#> Cell402     -8.028658e+00  0.7953801
    -#> Cell1514     5.461089e+00  0.8776159
    -#> Cell347     -4.785454e+00  0.8151512
    -#> Cell1176     4.157537e+00  0.8696693
    -#> Cell482     -1.688151e+00  0.8340329
    -#> Cell1236     5.147822e-02  0.8446380
    -#> Cell325     -1.676620e+00  0.8341032
    -#> Cell1406     5.643447e+00  0.8787276
    -#> Cell1164     2.663221e+00  0.8605596
    -#> Cell684     -4.317017e+00  0.8180069
    -#> Cell1559     3.963602e+00  0.8684870
    -#> Cell493     -2.003234e+00  0.8321121
    -#> Cell52      -1.284233e+00  0.8364953
    -#> Cell1028     5.046281e+00  0.8750872
    -#> Cell339     -4.157261e+00  0.8189808
    -#> Cell127      1.009588e+00  0.8504788
    -#> Cell1689     8.364138e+00  0.8953134
    -#> Cell662     -6.814474e+00  0.8027820
    -#> Cell533     -8.081572e+00  0.7950575
    -#> Cell240     -4.852682e+00  0.8147414
    -#> Cell83      -4.606531e+00  0.8162420
    -#> Cell1276     2.864829e+00  0.8617887
    -#> Cell142     -2.087740e+00  0.8315970
    -#> Cell796     -6.795746e+00  0.8028961
    -#> Cell1734     2.247683e+00  0.8580264
    -#> Cell1022     4.698736e+00  0.8729685
    -#> Cell838     -1.201654e+01  0.7710693
    -#> Cell1673     1.439939e+00  0.8531023
    -#> Cell7       -4.512267e+00  0.8168166
    -#> Cell1782     7.481669e+00  0.8899337
    -#> Cell506      1.828282e+00  0.8554697
    -#> Cell6       -3.214697e+00  0.8247268
    -#> Cell389     -6.606362e+00  0.8040506
    -#> Cell1548     2.498213e+00  0.8595537
    -#> Cell1939     2.997972e+00  0.8626003
    -#> Cell1419     4.320444e+00  0.8706624
    -#> Cell32      -2.615157e+00  0.8283817
    -#> Cell1777     2.777922e+00  0.8612589
    -#> Cell587     -4.069732e+00  0.8195144
    -#> Cell1805     4.640862e+00  0.8726157
    -#> Cell1163     4.807844e+00  0.8736336
    -#> Cell8       -3.045980e-01  0.8424673
    -#> Cell1771     1.686082e+00  0.8546028
    -#> Cell1725     4.684973e+00  0.8728846
    -#> Cell1398     2.880267e+00  0.8618828
    -#> Cell1818     4.941171e+00  0.8744464
    -#> Cell1801     1.995808e+00  0.8564910
    -#> Cell1885     3.339474e+00  0.8646822
    -#> Cell668      4.519370e-01  0.8470793
    -#> Cell1680     3.586560e+00  0.8661885
    -#> Cell473     -1.812677e+00  0.8332738
    -#> Cell1309     1.008637e+00  0.8504730
    -#> Cell28      -1.225058e+00  0.8368560
    -#> Cell721     -1.009088e+00  0.8381726
    -#> Cell97       7.193237e+00  0.8881754
    -#> Cell873     -1.445274e+00  0.8355135
    -#> Cell1280     5.396265e+00  0.8772208
    -#> Cell1618     4.846298e+00  0.8738681
    -#> Cell304      3.755606e-01  0.8466137
    -#> Cell1810     3.412701e+00  0.8651286
    -#> Cell1504     4.774666e+00  0.8734314
    -#> Cell151     -5.723791e-01  0.8408349
    -#> Cell192     -6.907142e+00  0.8022170
    -#> Cell1653     2.983145e+00  0.8625100
    -#> Cell1770     3.472923e+00  0.8654957
    -#> Cell391     -2.187685e+00  0.8309877
    -#> Cell1222     1.350106e+00  0.8525547
    -#> Cell149     -5.999439e+00  0.8077506
    -#> Cell553     -3.467409e+00  0.8231863
    -#> Cell1590     6.228099e+00  0.8822918
    -#> Cell317     -7.354865e+00  0.7994876
    -#> Cell1728     6.403440e+00  0.8833607
    -#> Cell1741     3.331638e+00  0.8646344
    -#> Cell639     -4.620982e+00  0.8161539
    -#> Cell931     -2.394116e+00  0.8297292
    -#> Cell1998     2.131249e+00  0.8573166
    -#> Cell1844     4.018112e+00  0.8688193
    -#> Cell1536     2.599281e+00  0.8601699
    -#> Cell74      -2.644634e+00  0.8282020
    -#> Cell316     -3.112156e+00  0.8253519
    -#> Cell1051     3.635022e+00  0.8664839
    -#> Cell802     -1.272071e+00  0.8365694
    -#> Cell1194     4.550709e+00  0.8720661
    -#> Cell183      1.387707e+00  0.8527839
    -#> Cell820     -6.764886e+00  0.8030843
    -#> Cell1068     4.821785e+00  0.8737186
    -#> Cell540     -3.718339e+00  0.8216565
    -#> Cell624     -8.942328e+00  0.7898102
    -#> Cell375     -3.199804e+00  0.8248176
    -#> Cell706     -2.085771e+00  0.8316090
    -#> Cell713      8.168414e-01  0.8493038
    -#> Cell1853     3.784067e+00  0.8673925
    -#> Cell908     -7.641382e+00  0.7977410
    -#> Cell1657     2.334848e+00  0.8585578
    -#> Cell1866     2.761910e+00  0.8611613
    -#> Cell58      -1.972285e+00  0.8323008
    -#> Cell738     -3.995293e+00  0.8199682
    -#> Cell1474     5.709286e+00  0.8791290
    -#> Cell17      -2.350681e+00  0.8299940
    -#> Cell737     -3.845859e-01  0.8419797
    -#> Cell825      7.712981e-01  0.8490262
    -#> Cell754     -3.049089e+00  0.8257364
    -#> Cell1929    -4.290028e-02  0.8440627
    -#> Cell16      -5.797645e+00  0.8089807
    -#> Cell1375     3.475647e+00  0.8655123
    -#> Cell41      -5.962514e+00  0.8079757
    -#> Cell524     -1.781798e+00  0.8334620
    -#> Cell957     -4.127493e+00  0.8191623
    -#> Cell397     -2.791428e+00  0.8273071
    -#> Cell1758     1.074573e+00  0.8508750
    -#> Cell357     -4.872778e-01  0.8413537
    -#> Cell1352     2.551763e+00  0.8598802
    -#> Cell870     -1.415433e+00  0.8356955
    -#> Cell699     -6.860772e+00  0.8024997
    -#> Cell1085     5.519276e+00  0.8779707
    -#> Cell897     -7.292057e+00  0.7998705
    -#> Cell1428     4.569223e+00  0.8721790
    -#> Cell682     -1.561916e+01  0.7491070
    -#> Cell1443     3.178557e+00  0.8637012
    -#> Cell1859     5.283790e+00  0.8765351
    -#> Cell551      2.604872e-02  0.8444830
    -#> Cell14      -4.966252e-01  0.8412967
    -#> Cell1922     2.890512e+00  0.8619453
    -#> Cell938     -3.253830e+00  0.8244883
    -#> Cell1231     3.786001e+00  0.8674043
    -#> Cell1314     3.080107e+00  0.8631011
    -#> Cell1557     3.964399e+00  0.8684919
    -#> Cell1030     7.450965e+00  0.8897466
    -#> Cell383     -1.768409e-01  0.8432461
    -#> Cell1910     6.028404e+00  0.8810744
    -#> Cell483     -4.774797e+00  0.8152162
    -#> Cell548     -2.900027e+00  0.8266451
    -#> Cell1379     2.306977e+00  0.8583879
    -#> Cell1254     1.907233e+00  0.8559510
    -#> Cell1060     4.870654e+00  0.8740165
    -#> Cell1649     3.548654e+00  0.8659574
    -#> Cell1328     6.043101e+00  0.8811640
    -#> Cell263     -4.529245e+00  0.8167131
    -#> Cell203      2.743575e-01  0.8459967
    -#> Cell496     -7.002914e+00  0.8016332
    -#> Cell1485     6.179335e+00  0.8819945
    -#> Cell1417     5.472083e-01  0.8476601
    -#> Cell1679     9.559373e+00  0.9025998
    -#> Cell878     -1.618421e+00  0.8344580
    -#> Cell1202     1.969329e+00  0.8563296
    -#> Cell778     -2.628158e+00  0.8283025
    -#> Cell637     -1.180423e+00  0.8371281
    -#> Cell109     -2.055887e+00  0.8317911
    -#> Cell1038     3.944102e+00  0.8683681
    -#> Cell1165     1.030655e+00  0.8506072
    -#> Cell619     -1.084056e+00  0.8377156
    -#> Cell1748     4.196021e+00  0.8699039
    -#> Cell261     -4.153012e+00  0.8190067
    -#> Cell672     -5.776461e+00  0.8091099
    -#> Cell1625     4.033235e+00  0.8689115
    -#> Cell71      -1.661454e+00  0.8341957
    -#> Cell965     -4.822146e-02  0.8440302
    -#> Cell1339     3.911760e+00  0.8681710
    -#> Cell1663     5.278787e+00  0.8765046
    -#> Cell1662     1.879105e+00  0.8557795
    -#> Cell882     -1.881731e+00  0.8328528
    -#> Cell1603     5.001504e+00  0.8748142
    -#> Cell207     -3.414599e+00  0.8235082
    -#> Cell1665     3.382918e+00  0.8649470
    -#> Cell69      -1.078374e+01  0.7785846
    -#> Cell1037     1.628652e+00  0.8542527
    -#> Cell321     -5.952138e+00  0.8080389
    -#> Cell725     -2.634715e+00  0.8282625
    -#> Cell1715     1.125425e+00  0.8511850
    -#> Cell922     -5.324164e+00  0.8118671
    -#> Cell260     -2.855633e+00  0.8269157
    -#> Cell1035     3.441518e+00  0.8653043
    -#> Cell1652     4.532720e+00  0.8719564
    -#> Cell1262     5.147296e+00  0.8757030
    -#> Cell1494     3.751850e+00  0.8671961
    -#> Cell96      -5.454876e+00  0.8110703
    -#> Cell1011     6.063291e+00  0.8812871
    -#> Cell1185     3.646979e+00  0.8665568
    -#> Cell1376     3.932055e+00  0.8682947
    -#> Cell37      -8.800870e-01  0.8389590
    -#> Cell1113     6.667043e+00  0.8849676
    -#> Cell1044     3.470057e+00  0.8654783
    -#> Cell457     -4.922316e+00  0.8143169
    -#> Cell1002     4.523969e+00  0.8719031
    -#> Cell1273     1.586153e+00  0.8539936
    -#> Cell449     -7.574314e-01  0.8397067
    -#> Cell568     -4.627982e+00  0.8161112
    -#> Cell406     -5.014503e+00  0.8137549
    -#> Cell394     -1.037620e-01  0.8436916
    -#> Cell1286     6.978705e+00  0.8868676
    -#> Cell1647     4.868471e+00  0.8740032
    -#> Cell1778     2.070510e+00  0.8569464
    -#> Cell944      8.343017e-01  0.8494102
    -#> Cell1869     3.000674e+00  0.8626168
    -#> Cell157     -3.143330e+00  0.8251619
    -#> Cell1902     3.403933e+00  0.8650752
    -#> Cell1041     5.848269e+00  0.8799763
    -#> Cell558     -3.158195e+00  0.8250713
    -#> Cell982     -2.161525e+00  0.8311471
    -#> Cell390     -5.048260e+00  0.8135491
    -#> Cell913     -4.612035e+00  0.8162084
    -#> Cell171     -2.998081e+00  0.8260474
    -#> Cell1123     6.083251e+00  0.8814087
    -#> Cell1912     5.827573e+00  0.8798501
    -#> Cell1019     3.476952e+00  0.8655203
    -#> Cell414     -8.182012e+00  0.7944452
    -#> Cell1765     5.540452e+00  0.8780997
    -#> Cell1058     1.602222e+00  0.8540916
    -#> Cell45      -5.352631e+00  0.8116936
    -#> Cell712     -1.050753e+01  0.7802685
    -#> Cell810     -5.558811e+00  0.8104367
    -#> Cell570     -3.217922e+00  0.8247072
    -#> Cell464     -5.695609e+00  0.8096028
    -#> Cell1265     3.423275e+00  0.8651931
    -#> Cell100     -2.825999e+00  0.8270964
    -#> Cell1886     3.725250e+00  0.8670340
    -#> Cell1985     4.174432e+00  0.8697723
    -#> Cell1574     5.900179e+00  0.8802927
    -#> Cell290     -6.467836e+00  0.8048951
    -#> Cell1544     3.996915e+00  0.8686901
    -#> Cell209     -5.794884e+00  0.8089976
    -#> Cell632     -3.043693e+00  0.8257693
    -#> Cell941     -8.557644e+00  0.7921553
    -#> Cell1102     4.412787e+00  0.8712253
    -#> Cell1335     2.238093e+00  0.8579680
    -#> Cell1656     2.655235e+00  0.8605110
    -#> Cell818     -4.657222e+00  0.8159329
    -#> Cell1338     7.100034e+00  0.8876072
    -#> Cell893      2.010079e-01  0.8455496
    -#> Cell1527     1.242014e+00  0.8518957
    -#> Cell519     -5.789332e-01  0.8407949
    -#> Cell1178     2.457754e+00  0.8593071
    -#> Cell626     -3.901159e+00  0.8205420
    -#> Cell763     -4.302723e+00  0.8180940
    -#> Cell1861     3.946411e+00  0.8683822
    -#> Cell952     -1.434508e+00  0.8355792
    -#> Cell1003     3.231105e+00  0.8640216
    -#> Cell488     -1.920005e+00  0.8326195
    -#> Cell136     -3.074668e+00  0.8255805
    -#> Cell1934     2.884439e+00  0.8619082
    -#> Cell1750     5.260675e+00  0.8763942
    -#> Cell1675     5.536263e+00  0.8780742
    -#> Cell901     -6.761272e+00  0.8031063
    -#> Cell255     -6.715197e+00  0.8033872
    -#> Cell648     -4.410303e+00  0.8174382
    -#> Cell926     -5.424037e+00  0.8112583
    -#> Cell757     -9.442342e+00  0.7867620
    -#> Cell413     -3.506912e+00  0.8229454
    -#> Cell920     -3.197806e+00  0.8248298
    -#> Cell1247     5.830726e+00  0.8798693
    -#> Cell205     -7.265008e+00  0.8000354
    -#> Cell1824     3.844376e+00  0.8677602
    -#> Cell1654     4.096881e+00  0.8692995
    -#> Cell719     -6.068007e+00  0.8073325
    -#> Cell822     -2.336410e+00  0.8300810
    -#> Cell683     -8.943098e+00  0.7898055
    -#> Cell73      -1.517182e+00  0.8350752
    -#> Cell967     -3.683881e+00  0.8218666
    -#> Cell839     -7.451148e+00  0.7989007
    -#> Cell1612     3.825035e+00  0.8676423
    -#> Cell1469     5.711182e+00  0.8791405
    -#> Cell84      -3.900975e+00  0.8205432
    -#> Cell1832     5.534668e+00  0.8780645
    -#> Cell110     -3.841740e-01  0.8419822
    -#> Cell1874     3.101146e+00  0.8632293
    -#> Cell1204     2.628265e+00  0.8603465
    -#> Cell815     -5.942406e+00  0.8080982
    -#> Cell455     -1.473736e+00  0.8353400
    -#> Cell1210     1.988901e+00  0.8564489
    -#> Cell242     -5.079950e+00  0.8133559
    -#> Cell987     -4.694071e+00  0.8157083
    -#> Cell853     -8.193048e+00  0.7943779
    -#> Cell194      3.925843e-01  0.8467174
    -#> Cell856     -5.914379e+00  0.8082691
    -#> Cell5       -9.328239e+00  0.7874576
    -#> Cell1275     2.687362e+00  0.8607068
    -#> Cell308      5.872523e-01  0.8479042
    -#> Cell1629     6.003907e+00  0.8809251
    -#> Cell867     -4.026943e+00  0.8197752
    -#> Cell388     -2.395782e+00  0.8297191
    -#> Cell1377     3.954077e+00  0.8684289
    -#> Cell1761     2.378838e+00  0.8588260
    -#> Cell181     -1.023301e+01  0.7819420
    -#> Cell86      -2.358342e-01  0.8428865
    -#> Cell442      8.118318e-01  0.8492733
    -#> Cell509     -5.880644e+00  0.8084747
    -#> Cell1043     2.196907e+00  0.8577169
    -#> Cell616     -1.966782e+00  0.8323343
    -#> Cell1047     7.471541e-01  0.8488790
    -#> Cell381      8.123613e-01  0.8492765
    -#> Cell177     -5.459928e+00  0.8110395
    -#> Cell1860     4.646909e+00  0.8726526
    -#> Cell330     -6.317148e+00  0.8058137
    -#> Cell1575     5.870997e+00  0.8801148
    -#> Cell797      6.539766e-01  0.8483109
    -#> Cell1355     4.091853e+00  0.8692688
    -#> Cell148     -5.132085e+00  0.8130381
    -#> Cell792      3.512972e-01  0.8464658
    -#> Cell1678     1.040851e+00  0.8506694
    -#> Cell997     -5.141204e-01  0.8411900
    -#> Cell1767     6.300441e+00  0.8827328
    -#> Cell1357     3.756377e+00  0.8672237
    -#> Cell1581     3.557354e+00  0.8660104
    -#> Cell320     -9.302799e-01  0.8386530
    -#> Cell1747     4.217434e+00  0.8700344
    -#> Cell1693     4.442914e+00  0.8714090
    -#> Cell1666     6.511467e+00  0.8840192
    -#> Cell798     -5.282589e+00  0.8121206
    -#> Cell478      5.231596e+00  0.8762169
    -#> Cell1620     2.677388e-01  0.8459564
    -#> Cell594     -2.657657e+00  0.8281226
    -#> Cell27      -4.733011e+00  0.8154709
    -#> Cell660     -5.533604e+00  0.8105904
    -#> Cell1524     7.513489e+00  0.8901277
    -#> Cell417     -3.302960e+00  0.8241888
    -#> Cell623     -4.829405e+00  0.8148833
    -#> Cell1363     3.284126e+00  0.8643448
    -#> Cell985      1.443609e+00  0.8531247
    -#> Cell692     -3.653688e+00  0.8220507
    -#> Cell355     -6.682579e+00  0.8035860
    -#> Cell1345     2.035759e+00  0.8567345
    -#> Cell1645     6.078817e+00  0.8813817
    -#> Cell909     -1.281301e+00  0.8365131
    -#> Cell1198    -2.433871e-02  0.8441758
    -#> Cell545     -7.284642e+00  0.7999157
    -#> Cell199     -1.413354e+00  0.8357081
    -#> Cell480     -5.120715e+00  0.8131074
    -#> Cell756     -6.979196e+00  0.8017778
    -#> Cell311     -2.019316e+00  0.8320141
    -#> Cell465     -1.420365e+00  0.8356654
    -#> Cell727     -5.776192e+00  0.8091115
    -#> Cell1911     4.691621e+00  0.8729251
    -#> Cell814     -7.718218e+00  0.7972726
    -#> Cell1319    -1.620753e-01  0.8433361
    -#> Cell910     -4.453910e+00  0.8171724
    -#> Cell223     -9.335405e-01  0.8386332
    -#> Cell35      -5.605460e+00  0.8101523
    -#> Cell1969     2.163836e+00  0.8575153
    -#> Cell1951     2.112293e+00  0.8572011
    -#> Cell1815     3.054876e+00  0.8629472
    -#> Cell116     -6.671553e+00  0.8036532
    -#> Cell868     -4.173768e+00  0.8188802
    -#> Cell1650     6.068290e+00  0.8813175
    -#> Cell1063     7.740373e-02  0.8447960
    -#> Cell1994     5.836096e-01  0.8478820
    -#> Cell494     -1.026005e+00  0.8380695
    -#> Cell779     -5.609981e+00  0.8101248
    -#> Cell507     -2.010882e+00  0.8320655
    -#> Cell118     -4.142007e+00  0.8190738
    -#> Cell1537     3.854534e+00  0.8678221
    -#> Cell1609     4.262184e+00  0.8703072
    -#> Cell1764     1.165758e+00  0.8514308
    -#> Cell1847     6.175221e+00  0.8819694
    -#> Cell1161     3.460194e+00  0.8654181
    -#> Cell881     -4.081652e+00  0.8194417
    -#> Cell1291     3.124824e+00  0.8633737
    -#> Cell1281     1.556338e+00  0.8538119
    -#> Cell1299     5.007457e+00  0.8748505
    -#> Cell163      9.846166e-01  0.8503266
    -#> Cell377     -2.669592e+00  0.8280499
    -#> Cell104     -5.555989e+00  0.8104539
    -#> Cell227     -2.399824e+00  0.8296944
    -#> Cell1703     1.786450e+00  0.8552147
    -#> Cell1365     1.299195e+00  0.8522443
    -#> Cell1585     5.450907e+00  0.8775539
    -#> Cell1249     2.122743e+00  0.8572648
    -#> Cell475     -5.108411e+00  0.8131824
    -#> Cell590     -1.310648e+00  0.8363342
    -#> Cell1913     1.509220e-01  0.8452442
    -#> Cell1477     1.993907e+00  0.8564794
    -#> Cell114     -4.406950e+00  0.8174586
    -#> Cell268     -1.152648e+01  0.7740567
    -#> Cell348     -5.346972e+00  0.8117281
    -#> Cell38      -4.802610e+00  0.8150466
    -#> Cell324      1.086231e+00  0.8509460
    -#> Cell1372     4.379912e+00  0.8710249
    -#> Cell108     -8.473637e+00  0.7926674
    -#> Cell768      9.972445e-01  0.8504036
    -#> Cell914     -1.350892e+00  0.8360889
    -#> Cell1410     2.791400e+00  0.8613410
    -#> Cell602     -2.460270e+00  0.8293259
    -#> Cell1070     2.428663e+00  0.8591297
    -#> Cell1564     2.278426e+00  0.8582139
    -#> Cell15       7.904911e-01  0.8491432
    -#> Cell653     -3.546062e+00  0.8227068
    -#> Cell1982     9.046943e-01  0.8498394
    -#> Cell448     -3.801550e+00  0.8211493
    -#> Cell26      -1.347845e+00  0.8361075
    -#> Cell1397     3.394335e+00  0.8650166
    -#> Cell1838     5.675577e+00  0.8789235
    -#> Cell224     -2.657126e+00  0.8281259
    -#> Cell954     -5.597396e+00  0.8102015
    -#> Cell1940     5.301888e+00  0.8766454
    -#> Cell1754     2.295328e+00  0.8583169
    -#> Cell1534     3.129269e+00  0.8634008
    -#> Cell962     -1.098184e+00  0.8376295
    -#> Cell1814     5.328388e+00  0.8768070
    -#> Cell1807     9.605482e-02  0.8449097
    -#> Cell1122     2.808429e+00  0.8614449
    -#> Cell714     -3.794824e+00  0.8211903
    -#> Cell1604     4.217865e+00  0.8700370
    -#> Cell891     -9.507693e+00  0.7863636
    -#> Cell688     -2.407078e+00  0.8296502
    -#> Cell824     -6.831062e-01  0.8401598
    -#> Cell1378     3.167292e+00  0.8636325
    -#> Cell211     -6.258159e+00  0.8061734
    -#> Cell278     -4.518571e+00  0.8167782
    -#> Cell345     -5.556628e+00  0.8104500
    -#> Cell700     -7.229416e+00  0.8002524
    -#> Cell1183     3.660341e+00  0.8666383
    -#> Cell1724     4.570305e+00  0.8721856
    -#> Cell851     -3.752316e+00  0.8214494
    -#> Cell991     -5.035866e+00  0.8136247
    -#> Cell1215     1.445845e+00  0.8531383
    -#> Cell474     -7.600605e+00  0.7979896
    -#> Cell94      -2.922875e+00  0.8265058
    -#> Cell650     -6.759905e+00  0.8031146
    -#> Cell1131     3.575456e+00  0.8661208
    -#> Cell627     -1.502394e+00  0.8351653
    -#> Cell408     -5.784622e+00  0.8090601
    -#> Cell196     -5.580251e+00  0.8103060
    -#> Cell129     -1.184406e+01  0.7721207
    -#> Cell615     -4.386851e+00  0.8175812
    -#> Cell1923     3.849343e+00  0.8677905
    -#> Cell911     -4.425448e+00  0.8173459
    -#> Cell1330     4.440676e+00  0.8713953
    -#> Cell46      -2.265883e-01  0.8429429
    -#> Cell1952     1.344951e+00  0.8525232
    -#> Cell1230     3.976275e+00  0.8685642
    -#> Cell1079     2.395342e+00  0.8589266
    -#> Cell942      4.361286e-01  0.8469829
    -#> Cell907     -3.957330e+00  0.8201996
    -#> Cell1087     2.476128e+00  0.8594191
    -#> Cell1623     4.864560e+00  0.8739794
    -#> Cell170     -7.342755e+00  0.7995615
    -#> Cell51      -8.688829e+00  0.7913556
    -#> Cell1882     2.492005e+00  0.8595159
    -#> Cell1154     2.090085e+00  0.8570657
    -#> Cell191     -4.651418e+00  0.8159683
    -#> Cell476     -4.177008e+00  0.8188604
    -#> Cell60       2.145432e+00  0.8574031
    -#> Cell1930     2.855350e+00  0.8617309
    -#> Cell184     -5.738340e+00  0.8093423
    -#> Cell1327     3.327687e-01  0.8463528
    -#> Cell593     -7.251074e+00  0.8001204
    -#> Cell1904     2.783402e+00  0.8612923
    -#> Cell1802     5.245143e+00  0.8762995
    -#> Cell166     -5.634599e+00  0.8099747
    -#> Cell1308     1.752834e+00  0.8550098
    -#> Cell1461     2.964834e+00  0.8623983
    -#> Cell580     -2.048649e+00  0.8318353
    -#> Cell1112     3.980903e+00  0.8685925
    -#> Cell1907     6.688858e+00  0.8851006
    -#> Cell1909     3.797072e+00  0.8674718
    -#> Cell1627     5.130337e+00  0.8755996
    -#> Cell1407     5.980624e+00  0.8807831
    -#> Cell1221     6.697669e+00  0.8851543
    -#> Cell1601     2.797246e+00  0.8613767
    -#> Cell1232     2.557335e+00  0.8599141
    -#> Cell1787     3.088024e+00  0.8631493
    -#> Cell1093     3.998314e+00  0.8686986
    -#> Cell993     -4.008546e+00  0.8198874
    -#> Cell1224     2.684645e+00  0.8606902
    -#> Cell1488     2.123955e+00  0.8572722
    -#> Cell154     -8.072250e-01  0.8394032
    -#> Cell1074     2.347111e+00  0.8586326
    -#> Cell1980     4.728022e+00  0.8731470
    -#> Cell208     -4.474562e+00  0.8170465
    -#> Cell1706     3.245238e+00  0.8641077
    -#> Cell1712     1.904389e+00  0.8559337
    -#> Cell343     -2.900192e+00  0.8266441
    -#> Cell1400     4.581764e+00  0.8722554
    -#> Cell1121     3.451297e+00  0.8653639
    -#> Cell1008     4.445477e+00  0.8714246
    -#> Cell322     -3.356956e+00  0.8238596
    -#> Cell1518     3.334957e+00  0.8646547
    -#> Cell1705     5.468638e+00  0.8776620
    -#> Cell635     -3.675396e+00  0.8219183
    -#> Cell30      -3.949773e+00  0.8202457
    -#> Cell1367     5.942579e+00  0.8805512
    -#> Cell1310     4.007849e+00  0.8687567
    -#> Cell790      2.133720e+00  0.8573317
    -#> Cell1303     8.129756e+00  0.8938846
    -#> Cell11      -7.769006e-01  0.8395881
    -#> Cell1990     4.541059e+00  0.8720073
    -#> Cell1667     4.530620e+00  0.8719436
    -#> Cell1525     4.976567e+00  0.8746622
    -#> Cell1264     2.241702e+00  0.8579900
    -#> Cell300     -5.669292e+00  0.8097632
    -#> Cell33      -1.984246e+00  0.8322279
    -#> Cell675     -2.847706e+00  0.8269641
    -#> Cell245     -2.076642e+00  0.8316646
    -#> Cell899     -4.974173e+00  0.8140008
    -#> Cell655     -1.051595e-01  0.8436831
    -#> Cell1578     5.409611e+00  0.8773021
    -#> Cell921     -3.007083e+00  0.8259925
    -#> Cell1146     1.165036e+00  0.8514264
    -#> Cell10      -2.457011e+00  0.8293458
    -#> Cell313     -4.136987e+00  0.8191044
    -#> Cell164     -4.979041e+00  0.8139711
    -#> Cell769     -2.294246e+00  0.8303381
    -#> Cell89       3.843922e-01  0.8466675
    -#> Cell1238     2.861060e+00  0.8617657
    -#> Cell218     -4.935780e+00  0.8142348
    -#> Cell1029     4.628309e+00  0.8725392
    -#> Cell329     -3.813460e+00  0.8210767
    -#> Cell1535     2.602377e+00  0.8601887
    -#> Cell1711     3.876811e+00  0.8679579
    -#> Cell1914    -4.891481e-02  0.8440260
    -#> Cell1685     2.508357e+00  0.8596156
    -#> Cell1014     3.840938e+00  0.8677392
    -#> Cell1267     4.974226e-01  0.8473566
    -#> Cell1774     4.899100e+00  0.8741900
    -#> Cell1144     1.532099e+00  0.8536641
    -#> Cell918     -6.040228e+00  0.8075019
    -#> Cell1760     5.904522e+00  0.8803192
    -#> Cell996     -5.695054e-02  0.8439770
    -#> Cell525     -2.090867e+00  0.8315779
    -#> Cell1389     2.483952e+00  0.8594668
    -#> Cell1034     6.959922e+00  0.8867531
    -#> Cell932     -3.111385e+00  0.8253566
    -#> Cell600     -6.578845e-01  0.8403136
    -#> Cell949     -6.211386e+00  0.8064585
    -#> Cell983     -3.723058e+00  0.8216278
    -#> Cell1834     5.053115e+00  0.8751289
    -#> Cell919     -3.896413e+00  0.8205710
    -#> Cell844     -1.959530e+01  0.7248678
    -#> Cell751     -3.933877e+00  0.8203426
    -#> Cell1107     1.434083e+00  0.8530666
    -#> Cell556     -5.257318e+00  0.8122747
    -#> Cell710     -3.247728e+00  0.8245255
    -#> Cell979     -2.019439e+00  0.8320133
    -#> Cell799     -5.265791e+00  0.8122230
    -#> Cell805      5.533784e+00  0.8780591
    -#> Cell1932     7.419869e+00  0.8895570
    -#> Cell175     -2.311414e+00  0.8302334
    -#> Cell1004     4.473263e+00  0.8715940
    -#> Cell1946     2.947396e+00  0.8622920
    -#> Cell1551     3.317192e+00  0.8645464
    -#> Cell807     -6.101310e+00  0.8071295
    -#> Cell1064     2.865409e+00  0.8617922
    -#> Cell780     -7.327077e+00  0.7996570
    -#> Cell1317     6.142486e+00  0.8817699
    -#> Cell1784     4.624069e+00  0.8725133
    -#> Cell765     -4.497115e+00  0.8169090
    -#> Cell349     -2.462344e+00  0.8293133
    -#> Cell1971    -1.028719e-01  0.8436971
    -#> Cell1126     1.558196e+00  0.8538232
    -#> Cell190     -2.002755e+00  0.8321150
    -#> Cell1593     4.981784e+00  0.8746940
    -#> Cell1487     4.147450e+00  0.8696078
    -#> Cell1415     5.669699e+00  0.8788877
    -#> Cell735     -8.851880e+00  0.7903616
    -#> Cell847      1.229968e+00  0.8518223
    -#> Cell514     -1.222314e+00  0.8368727
    -#> Cell1344     2.517354e+00  0.8596704
    -#> Cell409     -2.757316e+00  0.8275151
    -#> Cell1489     3.370765e+00  0.8648730
    -#> Cell835     -6.185538e+00  0.8066161
    -#> Cell411     -9.522105e-01  0.8385193
    -#> Cell112     -4.408377e+00  0.8174499
    -#> Cell1388     6.256343e-01  0.8481382
    -#> Cell373     -5.618769e+00  0.8100712
    -#> Cell248     -2.039951e+00  0.8318883
    -#> Cell788     -4.225321e+00  0.8185659
    -#> Cell462     -6.449409e+00  0.8050075
    -#> Cell1918     2.543404e+00  0.8598292
    -#> Cell230     -1.752529e+01  0.7374869
    -#> Cell236     -2.320017e+00  0.8301810
    -#> Cell1849     5.286355e+00  0.8765507
    -#> Cell1364     5.600514e+00  0.8784659
    -#> Cell1529     5.561813e+00  0.8782300
    -#> Cell1010     2.789918e+00  0.8613320
    -#> Cell1630     3.222510e+00  0.8639692
    -#> Cell1731     3.162726e+00  0.8636047
    -#> Cell344     -5.460696e+00  0.8110348
    -#> Cell1958     4.919009e+00  0.8743113
    -#> Cell630     -4.594423e+00  0.8163158
    -#> Cell1542     1.892750e+00  0.8558627
    -#> Cell1864     5.315059e+00  0.8767257
    -#> Cell791     -1.696228e+00  0.8339837
    -#> Cell1979     2.498944e+00  0.8595582
    -#> Cell1329     3.096531e+00  0.8632012
    -#> Cell1743     4.683413e+00  0.8728751
    -#> Cell1638     3.724671e+00  0.8670304
    -#> Cell93      -1.680101e+00  0.8340820
    -#> Cell1181     8.377766e+00  0.8953965
    -#> Cell1491     1.250303e+00  0.8519462
    -#> Cell1718     3.321093e+00  0.8645701
    -#> Cell992     -7.071854e+00  0.8012129
    -#> Cell612     -5.328573e+00  0.8118403
    -#> Cell1599     3.265567e-01  0.8463149
    -#> Cell821     -4.883403e+00  0.8145541
    -#> Cell532     -4.282955e+00  0.8182145
    -#> Cell1991     3.531548e+00  0.8658531
    -#> Cell221     -5.022717e+00  0.8137048
    -#> Cell1600     5.104067e+00  0.8754395
    -#> Cell782     -2.202498e+00  0.8308974
    -#> Cell160     -1.700813e+01  0.7406396
    -#> Cell1212     3.329497e+00  0.8646214
    -#> Cell1383     5.131598e+00  0.8756073
    -#> Cell200     -3.487177e+00  0.8230657
    -#> Cell479     -8.092531e-01  0.8393908
    -#> Cell989      6.306347e-01  0.8481686
    -#> Cell387     -7.790524e+00  0.7968318
    -#> Cell1150     1.380178e+01  0.9284623
    -#> Cell871     -4.625526e+00  0.8161262
    -#> Cell486     -3.492258e+00  0.8230348
    -#> Cell1109     8.857411e+00  0.8983205
    -#> Cell1425     7.100450e+00  0.8876098
    -#> Cell1434     2.771523e+00  0.8612199
    -#> Cell266     -2.255521e+00  0.8305741
    -#> Cell1732     7.582570e+00  0.8905489
    -#> Cell642     -1.078781e+01  0.7785598
    -#> Cell1516     2.401470e+00  0.8589640
    -#> Cell1642     4.107392e+00  0.8693636
    -#> Cell1045    -1.481385e+00  0.8352934
    -#> Cell698     -2.272651e+00  0.8304697
    -#> Cell611     -3.862316e-01  0.8419696
    -#> Cell1540     4.171762e+00  0.8697560
    -#> Cell1733     2.251957e+00  0.8580525
    -#> Cell20      -3.688963e+00  0.8218356
    -#> Cell201     -1.587512e+00  0.8346464
    -#> Cell174     -3.911275e+00  0.8204804
    -#> Cell1138    -4.133390e-01  0.8418044
    -#> Cell1798     3.854174e+00  0.8678199
    -#> Cell276     -1.879459e+00  0.8328667
    -#> Cell1032     3.445563e+00  0.8653289
    -#> Cell291     -1.152224e+01  0.7740826
    -#> Cell85      -3.751385e+00  0.8214551
    -#> Cell789     -1.475443e+00  0.8353296
    -#> Cell1937     2.620327e+00  0.8602982
    -#> Cell1753     4.307346e+00  0.8705825
    -#> Cell1713     2.800927e+00  0.8613991
    -#> Cell1408     4.944347e+00  0.8744658
    -#> Cell1478     4.942109e+00  0.8744521
    -#> Cell346     -9.100278e+00  0.7888473
    -#> Cell1880     5.570869e+00  0.8782852
    -#> Cell916     -7.622405e+00  0.7978567
    -#> Cell1259     2.834473e+00  0.8616036
    -#> Cell497     -4.234679e+00  0.8185088
    -#> Cell671     -2.980141e+00  0.8261567
    -#> Cell1119     5.987505e+00  0.8808251
    -#> Cell1588     3.693785e+00  0.8668421
    -#> Cell1790     1.074226e+01  0.9098109
    -#> Cell739     -1.945995e+00  0.8324611
    -#> Cell1429     3.684289e+00  0.8667843
    -#> Cell937     -8.115943e+00  0.7948480
    -#> Cell777     -1.352596e+00  0.8360785
    -#> Cell1800     6.694702e+00  0.8851363
    -#> Cell1813     8.061320e+00  0.8934674
    -#> Cell1151     3.697736e+00  0.8668662
    -#> Cell1981     1.140097e+00  0.8512744
    -#> Cell271     -2.534469e+00  0.8288736
    -#> Cell1624     3.008374e+00  0.8626638
    -#> Cell1632     1.683145e+00  0.8545849
    -#> Cell327     -4.066607e+00  0.8195334
    -#> Cell704     -8.376011e+00  0.7932626
    -#> Cell1366     2.958402e+00  0.8623591
    -#> Cell186     -3.682899e+00  0.8218726
    -#> Cell1083     3.119371e+00  0.8633404
    -#> Cell158     -2.011055e+00  0.8320644
    -#> Cell1709     7.858540e+00  0.8922312
    -#> Cell959     -1.348652e+00  0.8361026
    -#> Cell135     -5.059855e+00  0.8134784
    -#> Cell1302     1.834924e+00  0.8555102
    -#> Cell696     -2.936196e+00  0.8264246
    -#> Cell64      -1.743308e+00  0.8336967
    -#> Cell123     -1.928199e+00  0.8325695
    -#> Cell581     -1.386549e+00  0.8358715
    -#> Cell489     -5.886958e+00  0.8084363
    -#> Cell1592     2.091354e+00  0.8570734
    -#> Cell1180     3.228465e+00  0.8640055
    -#> Cell354     -1.777761e+00  0.8334866
    -#> Cell1611     3.941651e+00  0.8683532
    -#> Cell885     -3.069707e+00  0.8256107
    -#> Cell1714     7.859776e+00  0.8922388
    -#> Cell1152     3.953152e+00  0.8684233
    -#> Cell44      -9.462637e+00  0.7866383
    -#> Cell2000     4.809645e+00  0.8736446
    -#> Cell217     -3.335877e+00  0.8239881
    -#> Cell1999     4.324124e+00  0.8706848
    -#> Cell254     -1.182114e+01  0.7722604
    -#> Cell1651     3.300399e+00  0.8644440
    -#> Cell297     -4.806658e+00  0.8150220
    -#> Cell879     -8.904718e+00  0.7900395
    -#> Cell454     -5.030831e+00  0.8136554
    -#> Cell1942     3.309939e+00  0.8645021
    -#> Cell1167     3.331132e+00  0.8646313
    -#> Cell178     -3.881347e+00  0.8206628
    -#> Cell958     -5.000886e+00  0.8138379
    -#> Cell55      -2.497973e-01  0.8428014
    -#> Cell34      -2.016121e+00  0.8320336
    -#> Cell1157     4.395226e+00  0.8711182
    -#> Cell362      1.725328e+00  0.8548421
    -#> Cell369     -2.715544e+00  0.8277698
    -#> Cell862     -3.828964e+00  0.8209821
    -#> Cell1274     7.028437e+00  0.8871708
    -#> Cell252     -2.419737e+00  0.8295730
    -#> Cell1296     3.300301e+00  0.8644434
    -#> Cell88       7.329084e-01  0.8487921
    -#> Cell1955     4.538133e+00  0.8719894
    -#> Cell855     -2.597148e+00  0.8284915
    -#> Cell1868     5.307151e+00  0.8766775
    -#> Cell1538     4.116599e+00  0.8694197
    -#> Cell1226     2.511031e+00  0.8596319
    -#> Cell1926     5.464900e+00  0.8776392
    -#> Cell188     -3.004406e-01  0.8424926
    -#> Cell1855     1.081399e-01  0.8449834
    -#> Cell1416     2.954025e+00  0.8623324
    -#> Cell529      1.985034e-01  0.8455343
    -#> Cell923     -4.207263e+00  0.8186760
    -#> Cell1643     5.427486e+00  0.8774111
    -#> Cell1409     3.526214e+00  0.8658206
    -#> Cell1184     5.873788e+00  0.8801318
    -#> Cell31      -4.871164e+00  0.8146287
    -#> Cell518     -5.928803e+00  0.8081812
    -#> Cell1092     3.474113e+00  0.8655030
    -#> Cell1531     5.842394e+00  0.8799404
    -#> Cell742     -2.084118e+00  0.8316190
    -#> Cell1334     2.635728e+00  0.8603920
    -#> Cell106     -4.433566e+00  0.8172964
    -#> Cell863     -4.569219e+00  0.8164694
    -#> Cell1373     1.515291e+00  0.8535617
    -#> Cell187     -2.116926e+00  0.8314190
    -#> Cell1773     5.400550e+00  0.8772469
    -#> Cell1726     1.127872e+01  0.9130812
    -#> Cell1573     2.917304e+00  0.8621086
    -#> Cell1442     5.682652e+00  0.8789666
    -#> Cell1473     4.643146e+00  0.8726296
    -#> Cell1639     3.292805e+00  0.8643977
    -#> Cell1852     1.458071e+00  0.8532128
    -#> Cell1261     3.140157e+00  0.8634671
    -#> Cell1422     1.957907e+00  0.8562599
    -#> Cell1293     2.612562e+00  0.8602508
    -#> Cell1842     4.937515e+00  0.8744241
    -#> Cell353     -1.083505e+01  0.7782718
    -#> Cell1881     2.162978e+00  0.8575101
    -#> Cell1170     5.846668e+00  0.8799665
    -#> Cell1995     4.082654e-01  0.8468130
    -#> Cell1899     1.443446e+00  0.8531237
    -#> Cell68      -7.757721e+00  0.7970318
    -#> Cell1322     2.270152e+00  0.8581634
    -#> Cell471      8.834481e-02  0.8448627
    -#> Cell1399    -1.224704e+00  0.8368582
    -#> Cell586     -6.309902e+00  0.8058579
    -#> Cell1586     2.698655e+00  0.8607757
    -#> Cell578      2.813923e+00  0.8614784
    -#> Cell1158     1.812324e+00  0.8553724
    -#> Cell912     -5.487815e-01  0.8409787
    -#> Cell1498     4.065122e+00  0.8691059
    -#> Cell499     -1.612529e+00  0.8344939
    -#> Cell1260     2.323416e+00  0.8584881
    -#> Cell1182     2.487085e+00  0.8594859
    -#> Cell1492     1.367947e+00  0.8526634
    -#> Cell1512     4.714016e+00  0.8730616
    -#> Cell552     -2.475870e+00  0.8292308
    -#> Cell256     -5.303474e+00  0.8119933
    -#> Cell1691     2.841201e+00  0.8616446
    -#> Cell995     -6.917045e+00  0.8021567
    -#> Cell431     -4.766562e+00  0.8152664
    -#> Cell1723     3.806164e+00  0.8675272
    -#> Cell1975     1.654987e+00  0.8544133
    -#> Cell1160     3.424894e+00  0.8652029
    -#> Cell1816     3.808554e+00  0.8675418
    -#> Cell162     -2.949866e+00  0.8263413
    -#> Cell934     -4.184356e+00  0.8188156
    -#> Cell1483     3.296511e+00  0.8644203
    -#> Cell1353     3.306926e+00  0.8644838
    -#> Cell1420     1.160349e+00  0.8513979
    -#> Cell1530     1.902499e+00  0.8559221
    -#> Cell1708     2.704543e+00  0.8608116
    -#> Cell848     -6.573896e+00  0.8042486
    -#> Cell1453     6.930855e+00  0.8865759
    -#> Cell1669     9.520692e-01  0.8501282
    -#> Cell591     -6.593842e-01  0.8403045
    -#> Cell1763     3.105260e+00  0.8632544
    -#> Cell1517     5.372094e+00  0.8770734
    -#> Cell1947     2.093310e+00  0.8570854
    -#> Cell341     -6.436180e+00  0.8050881
    -#> Cell1306     1.498045e+00  0.8534565
    -#> Cell234     -3.633526e+00  0.8221736
    -#> Cell443     -3.248022e-01  0.8423441
    -#> Cell603      6.620379e-01  0.8483601
    -#> Cell1964     5.282284e+00  0.8765259
    -#> Cell1384     5.632130e+00  0.8786586
    -#> Cell293     -3.756013e+00  0.8214269
    -#> Cell1954     5.827709e+00  0.8798509
    -#> Cell1719     3.982895e+00  0.8686046
    -#> Cell622     -3.458374e+00  0.8232413
    -#> Cell1591     8.518784e+00  0.8962562
    -#> Cell153     -3.890934e+00  0.8206044
    -#> Cell469     -7.046617e+00  0.8013668
    -#> Cell92      -2.264823e+00  0.8305174
    -#> Cell1343     6.124401e+00  0.8816596
    -#> Cell1405     3.858295e+00  0.8678450
    -#> Cell415     -3.688228e+00  0.8218401
    -#> Cell1746     8.618894e-01  0.8495784
    -#> Cell81      -4.347717e+00  0.8178197
    -#> Cell887     -2.846891e+00  0.8269690
    -#> Cell981      1.105003e+00  0.8510605
    -#> Cell1252     3.909414e+00  0.8681567
    -#> Cell75      -2.210378e+00  0.8308493
    -#> Cell917     -4.719723e+00  0.8155519
    -#> Cell1147     2.686012e+00  0.8606986
    -#> Cell1577     1.565862e+00  0.8538699
    -#> Cell1444     1.768307e+00  0.8551041
    -#> Cell836     -9.744687e+00  0.7849189
    -#> Cell1046     5.927376e+00  0.8804585
    -#> Cell286      5.631364e+00  0.8786540
    -#> Cell337     -6.138043e+00  0.8069056
    -#> Cell1374     9.645347e-01  0.8502042
    -#> Cell647     -3.360193e+00  0.8238399
    -#> Cell1270     3.120615e+00  0.8633480
    -#> Cell1359     1.143667e+00  0.8512962
    -#> Cell970     -1.220228e+01  0.7699370
    -#> Cell249     -8.572195e-01  0.8390984
    -#> Cell1817     2.473187e+00  0.8594012
    -#> Cell1401     2.894140e+00  0.8619674
    -#> Cell66      -7.957104e+00  0.7958163
    -#> Cell1172     2.695875e+00  0.8607587
    -#> Cell284      2.358416e+00  0.8587015
    -#> Cell302     -1.948362e+00  0.8324466
    -#> Cell9       -8.838599e-01  0.8389360
    -#> Cell1892     4.172628e+00  0.8697612
    -#> Cell1024     3.575678e+00  0.8661221
    -#> Cell1033     1.079385e+01  0.9101254
    -#> Cell141     -2.163524e+00  0.8311350
    -#> Cell257     -6.367491e+00  0.8055068
    -#> Cell39      -3.285300e+00  0.8242964
    -#> Cell1956     8.552491e+00  0.8964617
    -#> Cell842     -5.304538e+00  0.8119868
    -#> Cell894     -3.946586e+00  0.8202651
    -#> Cell1412     4.684050e+00  0.8728790
    -#> Cell1965     2.819975e+00  0.8615152
    -#> Cell1040     4.634880e+00  0.8725792
    -#> Cell1071     4.395256e+00  0.8711184
    -#> Cell285     -4.128973e+00  0.8191532
    -#> Cell1776     1.729879e+00  0.8548698
    -#> Cell1920     2.417015e+00  0.8590587
    -#> Cell1766     5.619921e+00  0.8785842
    -#> Cell1521     3.146339e+00  0.8635048
    -#> Cell681     -1.126704e+00  0.8374556
    -#> Cell1244     7.732166e-01  0.8490378
    -#> Cell1438     6.218522e+00  0.8822334
    -#> Cell125     -3.022339e+00  0.8258995
    -#> Cell99      -3.397827e+00  0.8236104
    -#> Cell1463     5.337364e+00  0.8768617
    -#> Cell1370     4.733620e+00  0.8731812
    -#> Cell1449     2.973987e+00  0.8624541
    -#> Cell1297    -8.172260e-01  0.8393422
    -#> Cell1139     7.321686e+00  0.8889585
    -#> Cell1617     1.782221e+00  0.8551889
    -#> Cell62      -2.814114e-01  0.8426086
    -#> Cell795     -9.785981e+00  0.7846671
    -#> Cell1368     4.464679e+00  0.8715416
    -#> Cell784      1.270151e+00  0.8520672
    -#> Cell1361     3.992385e+00  0.8686625
    -#> Cell1505     3.408884e+00  0.8651053
    -#> Cell1135     2.600027e+00  0.8601744
    -#> Cell1133     3.403061e+00  0.8650698
    -#> Cell693     -5.025854e+00  0.8136857
    -#> Cell1386     1.636957e+00  0.8543034
    -#> Cell1762     2.058807e+00  0.8568750
    -#> Cell434     -9.784709e+00  0.7846749
    -#> Cell1890     4.997894e+00  0.8747922
    -#> Cell335     -1.024198e+00  0.8380805
    -#> Cell213     -4.133438e+00  0.8191260
    -#> Cell1993     3.835135e+00  0.8677038
    -#> Cell775     -1.172671e+00  0.8371754
    -#> Cell1948     3.381771e+00  0.8649400
    -#> Cell1507     3.327981e+00  0.8646121
    -#> Cell1635     5.823155e+00  0.8798232
    -#> Cell966     -3.553126e-01  0.8421581
    -#> Cell439     -9.814852e-01  0.8383409
    -#> Cell1596     5.547734e+00  0.8781441
    -#> Cell159     -9.072961e-01  0.8387931
    -#> Cell772     -3.498057e+00  0.8229994
    -#> Cell535     -3.689246e-01  0.8420752
    -#> Cell131      1.775726e+00  0.8551493
    -#> Cell1245     2.669524e+00  0.8605981
    -#> Cell1541     4.470637e+00  0.8715780
    -#> Cell315     -6.550499e+00  0.8043912
    -#> Cell412     -1.876144e+00  0.8328869
    -#> Cell1626     3.863855e+00  0.8678789
    -#> Cell939     -2.964059e+00  0.8262548
    -#> Cell1145     1.761428e+00  0.8550622
    -#> Cell554     -5.919187e+00  0.8082398
    -#> Cell521     -1.040847e+00  0.8379790
    -#> Cell1320     4.232163e+00  0.8701242
    -#> Cell625     -8.282925e+00  0.7938300
    -#> Cell1789     6.472559e+00  0.8837820
    -#> Cell1660     2.148320e+00  0.8574207
    -#> Cell372     -3.199535e+00  0.8248193
    -#> Cell1843     4.714859e+00  0.8730668
    -#> Cell1077     3.144718e+00  0.8634949
    -#> Cell1919     3.676086e+00  0.8667342
    -#> Cell305     -3.229468e+00  0.8246368
    -#> Cell1227     2.922140e+00  0.8621381
    -#> Cell720     -3.251843e+00  0.8245004
    -#> Cell1500     5.235602e+00  0.8762413
    -#> Cell1234     5.571832e+00  0.8782910
    -#> Cell1350     5.012268e+00  0.8748798
    -#> Cell425     -1.153365e+00  0.8372931
    -#> Cell904     -8.792506e+00  0.7907235
    -#> Cell392      3.146944e+00  0.8635085
    -#> Cell1966     1.313419e+00  0.8523310
    -#> Cell241     -2.079388e+00  0.8316479
    -#> Cell1001     3.775665e+00  0.8673413
    -#> Cell1235     4.870658e+00  0.8740166
    -#> Cell1127     3.357789e+00  0.8647938
    -#> Cell115     -6.727406e+00  0.8033127
    -#> Cell1607    -2.116326e+00  0.8314227
    -#> Cell1598     1.061385e+01  0.9090280
    -#> Cell90       2.838962e-01  0.8460549
    -#> Cell963     -3.722377e+00  0.8216319
    -#> Cell250     -4.339542e+00  0.8178696
    -#> Cell1307     1.940139e+00  0.8561516
    -#> Cell976     -4.902253e+00  0.8144392
    -#> Cell640      2.876903e-01  0.8460780
    -#> Cell599     -3.898275e+00  0.8205596
    -#> Cell936     -3.497310e+00  0.8230040
    -#> Cell562     -2.520909e-01  0.8427874
    -#> Cell1827     1.750728e+00  0.8549969
    -#> Cell294     -4.536029e+00  0.8166718
    -#> Cell1503     4.310370e+00  0.8706010
    -#> Cell1061     1.054413e+00  0.8507521
    -#> Cell1563     3.111450e+00  0.8632921
    -#> Cell613     -6.936688e+00  0.8020369
    -#> Cell1822     2.617660e+00  0.8602819
    -#> Cell999     -2.091833e+00  0.8315720
    -#> Cell420     -1.141746e+00  0.8373639
    -#> Cell977     -1.739452e+00  0.8337202
    -#> Cell1446     6.314464e+00  0.8828183
    -#> Cell23      -4.026703e+00  0.8197767
    -#> Cell1269    -1.802157e-01  0.8432256
    -#> Cell1664     4.272084e+00  0.8703676
    -#> Cell374     -1.988833e+00  0.8321999
    -#> Cell1348     7.664510e-01  0.8489966
    -#> Cell1012     2.441326e+00  0.8592069
    -#> Cell404     -4.687260e+00  0.8157498
    -#> Cell1720     6.228644e+00  0.8822951
    -#> Cell522     -8.842502e-01  0.8389336
    -#> Cell385     -5.286339e+00  0.8120977
    -#> Cell1497     3.874218e+00  0.8679421
    -#> Cell244     -4.554701e+00  0.8165579
    -#> Cell806     -2.508081e+00  0.8290345
    -#> Cell259     -7.553028e+00  0.7982796
    -#> Cell504     -4.652897e+00  0.8159593
    -#> Cell707     -3.654021e+00  0.8220486
    -#> Cell1779     1.120540e+01  0.9126343
    -#> Cell585      6.055401e-01  0.8480157
    -#> Cell534     -2.841561e+00  0.8270015
    -#> Cell498     -3.702193e-01  0.8420673
    -#> Cell530     -5.663249e+00  0.8098000
    -#> Cell228     -5.412731e+00  0.8113272
    -#> Cell1054     2.176785e+00  0.8575942
    -#> Cell1336     1.946799e+00  0.8561922
    -#> Cell1155     4.998723e+00  0.8747973
    -#> Cell729     -2.750616e+00  0.8275559
    -#> Cell1199     4.850943e-01  0.8472814
    -#> Cell1101     2.726820e+00  0.8609474
    -#> Cell701      1.541115e+00  0.8537191
    -#> Cell1031     5.056765e+00  0.8751511
    -#> Cell314     -5.036892e+00  0.8136184
    -#> Cell1250     1.929087e+00  0.8560842
    -#> Cell1454     8.028274e-01  0.8492184
    -#> Cell1279     4.008096e+00  0.8687582
    -#> Cell1640     4.442638e+00  0.8714073
    -#> Cell1108     2.985326e+00  0.8625232
    -#> Cell1216     3.260352e+00  0.8641999
    -#> Cell1106     5.098449e+00  0.8754052
    -#> Cell1316     4.212489e+00  0.8700042
    -#> Cell634     -6.896020e+00  0.8022848
    -#> Cell741     -3.659584e+00  0.8220147
    -#> Cell724     -6.680321e+00  0.8035998
    -#> Cell1622     6.550178e+00  0.8842552
    -#> Cell513     -1.625010e+00  0.8344178
    -#> Cell378     -4.344728e-01  0.8416756
    -#> Cell1872     7.147272e+00  0.8878952
    -#> Cell1120     3.633497e+00  0.8664746
    -#> Cell1295     4.433529e+00  0.8713517
    -#> Cell1186     4.642131e+00  0.8726234
    -#> Cell1960     2.263397e+00  0.8581222
    -#> Cell1567     4.235475e+00  0.8701444
    -#> Cell1671     4.161648e+00  0.8696943
    -#> Cell1756     4.106706e+00  0.8693594
    -#> Cell134     -2.864676e+00  0.8268606
    -#> Cell523     -7.890380e+00  0.7962230
    -#> Cell1755     1.372906e+00  0.8526937
    -#> Cell1048     1.228168e+00  0.8518113
    -#> Cell1707     7.463656e-02  0.8447792
    -#> Cell1884     2.920809e+00  0.8621299
    -#> Cell781     -5.581494e+00  0.8102984
    -#> Cell1421     4.339233e+00  0.8707769
    -#> Cell1646     3.497326e+00  0.8656445
    -#> Cell888     -2.136140e+00  0.8313019
    -#> Cell1608     4.161315e+00  0.8696923
    -#> Cell467     -5.588368e+00  0.8102565
    -#> Cell401     -1.597301e+01  0.7469499
    -#> Cell817     -1.818904e+00  0.8332358
    -#> Cell422     -1.683599e+00  0.8340607
    -#> Cell279     -5.463197e+00  0.8110196
    -#> Cell573     -2.998001e+00  0.8260478
    -#> Cell1240     3.497488e+00  0.8656455
    -#> Cell1736     3.700279e+00  0.8668817
    -#> Cell360     -7.501587e+00  0.7985932
    -#> Cell1104     4.255658e+00  0.8702674
    -#> Cell299     -1.121189e+01  0.7759745
    -#> Cell565     -1.012065e+00  0.8381545
    -#> Cell1727     4.097341e+00  0.8693023
    -#> Cell1941     8.133612e+00  0.8939081
    -#> Cell1528     3.219728e+00  0.8639522
    -#> Cell367     -5.155110e+00  0.8128977
    -#> Cell1803     4.827867e+00  0.8737557
    -#> Cell621     -4.709343e+00  0.8156152
    -#> Cell849     -6.875967e+00  0.8024071
    -#> Cell1251     2.525552e+00  0.8597204
    -#> Cell386     -7.252081e+00  0.8001142
    -#> Cell336     -1.709403e+00  0.8339034
    -#> Cell1099     1.345223e+00  0.8525249
    -#> Cell808      3.138943e+00  0.8634597
    -#> Cell1835     1.384617e+01  0.9287328
    -#> Cell854     -5.590518e-01  0.8409161
    -#> Cell866     -4.471698e+00  0.8170639
    -#> Cell1996     1.513606e+00  0.8535514
    -#> Cell1124     5.454201e-01  0.8476492
    -#> Cell740     -3.228914e+00  0.8246402
    -#> Cell426     -2.136323e+00  0.8313008
    -#> Cell436     -1.509923e+00  0.8351194
    -#> Cell1589     5.551011e+00  0.8781641
    -#> Cell1610     4.734751e+00  0.8731881
    -#> Cell915     -1.184811e+00  0.8371014
    -#> Cell172     -7.005306e-01  0.8400536
    -#> Cell1897     2.161411e+00  0.8575005
    -#> Cell1169     4.488091e+00  0.8716844
    -#> Cell1549     3.694011e+00  0.8668435
    -#> Cell1788     5.821074e+00  0.8798105
    -#> Cell1722     2.830832e+00  0.8615814
    -#> Cell450     -6.828779e+00  0.8026947
    -#> Cell579     -3.504593e+00  0.8229596
    -#> Cell1177     3.311328e+00  0.8645106
    -#> Cell1992     2.356146e+00  0.8586877
    -#> Cell233     -5.731860e+00  0.8093818
    -#> Cell761     -6.027181e+00  0.8075814
    -#> Cell925      6.077224e-01  0.8480290
    -#> Cell732     -6.250359e+00  0.8062209
    -#> Cell1214     2.423492e+00  0.8590982
    -#> Cell1533     2.335500e+00  0.8585618
    -#> Cell1179     5.424837e-01  0.8476313
    -#> Cell1206     3.879335e+00  0.8679733
    -#> Cell1944     3.031898e+00  0.8628072
    -#> Cell667     -5.035387e+00  0.8136276
    -#> Cell677     -1.701958e+00  0.8339487
    -#> Cell366     -5.784739e+00  0.8090594
    -#> Cell1263     3.763026e+00  0.8672642
    -#> Cell1082     2.156869e+00  0.8574728
    -#> Cell1677     2.107119e+00  0.8571695
    -#> Cell298     -3.485523e+00  0.8230758
    -#> Cell785     -2.007245e+00  0.8320877
    -#> Cell1970     5.304286e+00  0.8766600
    -#> Cell1684     3.338175e+00  0.8646743
    -#> Cell1545     1.888877e+00  0.8558391
    -#> Cell1006     4.861111e+00  0.8739584
    -#> Cell1806     2.120350e+00  0.8572502
    -#> Cell1246     2.448497e+00  0.8592506
    -#> Cell1641     3.354311e+00  0.8647727
    -#> Cell1558     5.255201e+00  0.8763608
    -#> Cell251     -2.154466e+00  0.8311902
    -#> Cell755     -4.475972e+00  0.8170379
    -#> Cell628     -3.189371e+00  0.8248812
    -#> Cell1739     2.102815e+00  0.8571433
    -#> Cell76      -6.437924e+00  0.8050775
    -#> Cell437     -1.963356e+00  0.8323552
    -#> Cell1266     1.707764e+00  0.8547350
    -#> Cell1735     8.016568e-01  0.8492112
    -#> Cell1506     4.107172e+00  0.8693622
    -#> Cell445     -1.237742e+00  0.8367787
    -#> Cell1613     6.837193e+00  0.8860049
    -#> Cell1694     6.047569e+00  0.8811912
    -#> Cell393     -4.865025e+00  0.8146661
    -#> Cell1390     5.618155e+00  0.8785734
    -#> Cell379     -3.685803e+00  0.8218549
    -#> Cell520     -3.978582e+00  0.8200701
    -#> Cell1       -1.070547e-01  0.8436716
    -#> Cell126     -1.729903e+00  0.8337784
    -#> Cell1360     4.236161e+00  0.8701486
    -#> Cell1076     2.289754e+00  0.8582829
    -#> Cell267     -1.569615e+00  0.8347555
    -#> Cell561     -5.958784e+00  0.8079984
    -#> Cell994     -9.416685e+00  0.7869184
    -#> Cell860     -3.278277e+00  0.8243392
    -#> Cell1439     8.881405e-01  0.8497384
    -#> Cell1342     3.893844e+00  0.8680617
    -#> Cell1943     6.527310e+00  0.8841158
    -#> Cell1752     1.768543e+00  0.8551055
    -#> Cell730     -6.648068e+00  0.8037964
    -#> Cell1829     4.823960e+00  0.8737319
    -#> Cell1067     2.038783e+00  0.8567530
    -#> Cell238     -7.829027e+00  0.7965971
    -#> Cell1768     5.093900e+00  0.8753775
    -#> Cell1337     2.883116e+00  0.8619002
    -#> Cell859     -3.457021e+00  0.8232496
    -#> Cell500     -7.090577e+00  0.8010988
    -#> Cell609     -5.921293e+00  0.8082269
    -#> Cell800     -3.810778e+00  0.8210930
    -#> Cell273     -2.541050e+00  0.8288335
    -#> Cell1480     2.820251e+00  0.8615169
    -#> Cell1369     4.761970e+00  0.8733540
    -#> Cell47      -2.677477e-01  0.8426919
    -#> Cell1192     2.834217e+00  0.8616021
    -#> Cell1510     6.310530e+00  0.8827943
    -#> Cell1957     5.910272e+00  0.8803542
    -#> Cell1282     3.383314e+00  0.8649495
    -#> Cell1502     2.014902e+00  0.8566074
    -#> Cell1115     9.267987e+00  0.9008235
    -#> Cell1597     3.834620e+00  0.8677007
    -#> Cell1471     3.415747e+00  0.8651472
    -#> Cell1605     3.501326e+00  0.8656689
    -#> Cell1211     3.809431e+00  0.8675471
    -#> Cell334     -5.946781e+00  0.8080716
    -#> Cell1582     3.733590e+00  0.8670848
    -#> Cell1088     7.047853e+00  0.8872891
    -#> Cell1900     2.649728e+00  0.8604774
    -#> Cell633     -1.760604e+00  0.8335912
    -#> Cell1140     4.764271e+00  0.8733680
    -#> Cell459      3.486886e-01  0.8464498
    -#> Cell945     -1.874992e+00  0.8328939
    -#> Cell883     -7.844705e+00  0.7965015
    -#> Cell1142     2.224181e+00  0.8578832
    -#> Cell1171     5.107751e+00  0.8754619
    -#> Cell1987     2.053340e+00  0.8568417
    -#> Cell132     -2.533510e+00  0.8288795
    -#> Cell1136     2.629879e+00  0.8603564
    -#> Cell1445     4.173118e+00  0.8697642
    -#> Cell1200     1.760294e+00  0.8550552
    -#> Cell193     -6.290203e+00  0.8059780
    -#> Cell1175     3.283677e+00  0.8643420
    -#> Cell1658     4.537313e+00  0.8719844
    -#> Cell1583     5.480168e+00  0.8777322
    -#> Cell319     -2.812208e+00  0.8271805
    -#> Cell1749     1.378398e+00  0.8527271
    -#> Cell1393     5.596570e+00  0.8784419
    -#> Cell1621     1.333477e+00  0.8524533
    -#> Cell830     -5.134259e+00  0.8130248
    -#> Cell1863     1.380146e+00  0.8527378
    -#> Cell641      2.290562e+00  0.8582878
    -#> Cell1936     3.466920e+00  0.8654591
    -#> Cell728     -9.467140e-01  0.8385528
    -#> Cell980     -1.941271e+00  0.8324899
    -#> Cell1704     7.553572e-01  0.8489290
    -#> Cell342     -5.726945e+00  0.8094117
    -#> Cell1321     5.487962e+00  0.8777798
    -#> Cell491     -2.693672e+00  0.8279031
    -#> Cell1223     3.585600e+00  0.8661826
    -#> Cell1659     4.608718e+00  0.8724197
    -#> Cell890      1.133067e+00  0.8512316
    -#> Cell1333     4.421323e+00  0.8712773
    -#> Cell1468     3.555121e+00  0.8659968
    -#> Cell1945     1.111527e+00  0.8511002
    -#> Cell1781     7.889315e-01  0.8491336
    -#> Cell424     -3.293795e+00  0.8242446
    -#> Cell382     -1.015574e+01  0.7824130
    -#> Cell709     -5.325916e+00  0.8118565
    -#> Cell1233     7.272342e-02  0.8447675
    -#> Cell629      1.547001e+00  0.8537550
    -#> Cell1501     6.298582e-01  0.8481639
    -#> Cell1740     3.259529e+00  0.8641948
    -#> Cell557     -4.548873e+00  0.8165935
    -#> Cell1826     3.305104e+00  0.8644727
    -#> Cell3       -1.776182e+00  0.8334963
    -#> Cell101     -6.135859e-01  0.8405837
    -#> Cell1349     4.322582e+00  0.8706754
    -#> Cell1858     5.744264e+00  0.8793422
    -#> Cell1961     4.397947e+00  0.8711348
    -#> Cell990     -1.891222e-01  0.8431713
    -#> Cell547      7.731322e-02  0.8447955
    -#> Cell451     -1.675322e+00  0.8341111
    -#> Cell1021     4.769793e+00  0.8734017
    -#> Cell301     -7.280541e+00  0.7999407
    -#> Cell886     -2.352136e+00  0.8299852
    -#> Cell65      -5.238278e+00  0.8123907
    -#> Cell1414     2.015881e+00  0.8566133
    -#> Cell1968     3.514429e+00  0.8657488
    -#> Cell1347     4.130869e+00  0.8695067
    -#> Cell1426     4.946296e+00  0.8744777
    -#> Cell1125     2.783757e+00  0.8612944
    -#> Cell749     -2.601269e+00  0.8284664
    -#> Cell441     -1.330214e+00  0.8362150
    -#> Cell487     -8.270616e+00  0.7939051
    -#> Cell1219     1.951349e+00  0.8562199
    -#> Cell1619     2.476559e+00  0.8594217
    -#> Cell617     -1.178983e+00  0.8371369
    -#> Cell636     -4.479972e+00  0.8170135
    -#> Cell1118     4.381234e+00  0.8710330
    -#> Cell895     -6.013831e+00  0.8076628
    -#> Cell189     -2.193528e+00  0.8309521
    -#> Cell1132     5.564067e+00  0.8782437
    -#> Cell1644     4.927563e+00  0.8743635
    -#> Cell905     -1.965606e+00  0.8323415
    -#> Cell733     -2.432107e+00  0.8294976
    -#> Cell811     -4.506181e+00  0.8168537
    -#> Cell569     -2.367583e+00  0.8298910
    -#> Cell670     -4.909241e+00  0.8143966
    -#> Cell1096     8.955393e+00  0.8989178
    -#> Cell940     -3.096028e+00  0.8254503
    -#> Cell1846     2.936438e+00  0.8622252
    -#> Cell1931     4.178638e+00  0.8697979
    -#> Cell292     -3.776034e+00  0.8213048
    -#> Cell638     -1.436608e+00  0.8355664
    -#> Cell12      -5.199827e+00  0.8126251
    -#> Cell1862     5.076202e+00  0.8752696
    -#> Cell358     -4.409637e-01  0.8416360
    -#> Cell1248     5.915112e+00  0.8803837
    -#> Cell1688     3.246616e+00  0.8641161
    -#> Cell340     -7.976478e-01  0.8394616
    -#> Cell786      4.118249e-01  0.8468347
    -#> Cell744      2.281988e+00  0.8582356
    -#> Cell429      2.419126e+00  0.8590716
    -#> Cell658     -3.870323e+00  0.8207300
    -#> Cell1220     4.250463e+00  0.8702358
    -#> Cell1472     8.179210e-01  0.8493104
    -#> Cell787     -5.758319e+00  0.8092205
    -#> Cell1745     3.718834e+00  0.8669948
    -#> Cell1793     1.916956e+00  0.8560103
    -#> Cell770     -2.023106e+00  0.8319910
    -#> Cell1278     4.410278e+00  0.8712100
    -#> Cell652     -9.557329e+00  0.7860610
    -#> Cell1253     1.467654e+00  0.8532713
    -#> Cell1481     2.346220e+00  0.8586272
    -#> Cell1437     4.697112e+00  0.8729586
    -#> Cell1562     8.895419e-01  0.8497470
    -#> Cell829     -8.435264e+00  0.7929013
    -#> Cell1213     2.961676e+00  0.8623791
    -#> Cell695     -2.691013e+00  0.8279193
    -#> Cell1256     4.848307e+00  0.8738803
    -#> Cell947     -7.166447e+00  0.8006363
    -#> Cell222     -2.560759e+00  0.8287133
    -#> Cell747     -9.706699e+00  0.7851504
    -#> Cell1100     1.667308e+00  0.8544884
    -#> Cell846     -3.211294e+00  0.8247476
    -#> Cell1134     2.105607e+00  0.8571603
    -#> Cell659     -6.499558e+00  0.8047017
    -#> Cell1432     3.135758e+00  0.8634403
    -#> Cell368      1.999551e+00  0.8565138
    -#> Cell1173     5.811540e+00  0.8797523
    -#> Cell1080     4.900860e+00  0.8742007
    -#> Cell176     -4.648930e+00  0.8159835
    -#> Cell1783     3.091339e+00  0.8631695
    -#> Cell1095     5.188361e+00  0.8759533
    -#> Cell1000    -5.348555e+00  0.8117185
    -#> Cell1676     2.616644e+00  0.8602757
    -#> Cell1207     4.214877e+00  0.8700188
    -#> Cell1470     4.120203e+00  0.8694417
    -#> Cell933     -2.774783e+00  0.8274086
    -#> Cell173     -7.446718e+00  0.7989277
    -#> Cell1742     3.337452e+00  0.8646699
    -#> Cell1015     2.838582e+00  0.8616287
    -#> Cell1209     3.433913e+00  0.8652579
    -#> Cell731     -1.186691e+01  0.7719814
    -#> Cell972      1.876529e-01  0.8454681
    -#> Cell511     -2.155100e+00  0.8311863
    -#> Cell588     -1.530208e+00  0.8349958
    -#> Cell1717     1.495559e+00  0.8534414
    -#> Cell510      7.657879e-01  0.8489926
    -#> Cell1908     1.557931e+00  0.8538216
    -#> Cell78      -2.645891e+00  0.8281944
    -#> Cell892      6.109130e-02  0.8446966
    -#> Cell331     -7.465589e+00  0.7988126
    -#> Cell433     -1.985159e+00  0.8322223
    -#> Cell865     -1.093210e+00  0.8376598
    -#> Cell651     -4.463854e+00  0.8171117
    -#> Cell508     -1.324912e+00  0.8362473
    -#> Cell1634     3.256197e+00  0.8641745
    -#> Cell1271     4.817588e+00  0.8736930
    -#> Cell281     -6.187340e+00  0.8066051
    -#> Cell481     -5.465691e+00  0.8110044
    -#> Cell542     -4.100632e+00  0.8193260
    -#> Cell1825     5.698393e+00  0.8790626
    -#> Cell1149     2.027099e+00  0.8566817
    -#> Cell571     -3.834967e+00  0.8209456
    -#> Cell490     -5.571305e+00  0.8103605
    -#> Cell501     -2.930850e+00  0.8264572
    -#> Cell427     -4.258967e+00  0.8183608
    -#> Cell576     -1.821674e+00  0.8332189
    -#> Cell776      1.245329e+00  0.8519159
    -#> Cell1458     6.134507e-01  0.8480639
    -#> Cell416     -4.414481e+00  0.8174127
    -#> Cell1696     3.058324e+00  0.8629683
    -#> Cell906     -6.802976e+00  0.8028520
    -#> Cell1819     3.406465e+00  0.8650906
    -#> Cell282     -1.857299e-01  0.8431919
    -#> Cell1857     3.677443e+00  0.8667425
    -#> Cell961     -2.209400e+00  0.8308553
    -#> Cell361     -5.240672e+00  0.8123761
    -#> Cell318     -3.061130e+00  0.8256630
    -#> Cell167     -4.038965e+00  0.8197019
    -#> Cell1812     2.598353e+00  0.8601642
    -#> Cell900     -5.003189e+00  0.8138239
    -#> Cell717     -6.758335e+00  0.8031242
    -#> Cell1392     5.742891e+00  0.8793339
    -#> Cell326     -1.826587e+01  0.7329722
    -#> Cell1811     4.128182e+00  0.8694903
    -#> Cell1595     2.197876e+00  0.8577228
    -#> Cell351     -1.856948e+00  0.8330039
    -#> Cell328     -4.637247e+00  0.8160547
    -#> Cell1396     3.138848e+00  0.8634591
    -#> Cell438      4.807430e-01  0.8472549
    -#> Cell80      -2.002775e+00  0.8321149
    -#> Cell333     -4.508183e+00  0.8168415
    -#> Cell461     -4.353326e+00  0.8177855
    -#> Cell1162     1.527596e+01  0.9374491
    -#> Cell1594     3.303991e+00  0.8644659
    -#> Cell975     -2.440686e+00  0.8294453
    -#> Cell1081     3.877699e+00  0.8679633
    -#> Cell1358     7.441887e+00  0.8896912
    -#> Cell444     -5.354372e+00  0.8116830
    -#> Cell119     -4.197567e+00  0.8187351
    -#> Cell1614     2.392537e+00  0.8589095
    -#> Cell1456     2.282547e+00  0.8582390
    -#> Cell1737     3.209152e+00  0.8638877
    -#> Cell1073     3.191203e+00  0.8637783
    -#> Cell1877     3.841473e+00  0.8677425
    -#> Cell1959     5.046189e+00  0.8750866
    -#> Cell605     -7.352027e-01  0.8398423
    -#> Cell155     -4.675026e+00  0.8158244
    -#> Cell1636     4.718995e-02  0.8446119
    -#> Cell1555     3.980262e+00  0.8685886
    -#> Cell690     -6.075248e+00  0.8072884
    -#> Cell25      -2.278224e+00  0.8304357
    -#> Cell1775     1.915576e+00  0.8560019
    -#> Cell140     -3.687203e+00  0.8218463
    -#> Cell1218     3.214863e+00  0.8639226
    -#> Cell1482     2.369019e+00  0.8587661
    -#> Cell1229     3.527793e+00  0.8658302
    -#> Cell1730     2.712156e+00  0.8608580
    -#> Cell1289     2.195212e+00  0.8577066
    -#> Cell1447     3.794372e+00  0.8674553
    -#> Cell216     -3.843653e+00  0.8208926
    -#> Cell1257     3.655495e+00  0.8666087
    -#> Cell1566     1.259520e+00  0.8520024
    -#> Cell988     -3.946715e-01  0.8419182
    -#> Cell1839     3.499144e+00  0.8656556
    -#> Cell1543     4.527436e+00  0.8719242
    -#> Cell352     -6.976907e+00  0.8017917
    -#> Cell1759     5.097751e+00  0.8754010
    -#> Cell147     -7.986963e+00  0.7956343
    -#> Cell544     -2.414924e+00  0.8296024
    -#> Cell419     -4.062967e+00  0.8195556
    -#> Cell1757     4.887216e+00  0.8741175
    -#> Cell1797     3.839514e+00  0.8677305
    -#> Cell280     -2.240158e+00  0.8306678
    -#> Cell531     -8.479710e+00  0.7926304
    -#> Cell1381     5.509834e+00  0.8779131
    -#> Cell29      -5.015415e+00  0.8137493
    -#> Cell214     -4.912004e+00  0.8143797
    -#> Cell1305     3.799995e+00  0.8674896
    -#> Cell705     -1.264260e+00  0.8366170
    -#> Cell1883     3.057634e+00  0.8629641
    -#> Cell1509     1.553197e+00  0.8537927
    -#> Cell1486     5.961691e+00  0.8806677
    -#> Cell1692     6.580177e+00  0.8844381
    -#> Cell59      -2.394602e+00  0.8297263
    -#> Cell262      5.023204e+00  0.8749465
    -#> Cell72      -2.631286e+00  0.8282834
    -#> Cell21      -6.450240e+00  0.8050024
    -#> Cell1413     4.485221e+00  0.8716669
    -#> Cell338     -1.514700e+01  0.7519854
    -#> Cell1796     3.494890e+00  0.8656296
    -#> Cell1710     1.439352e+00  0.8530987
    -#> Cell889     -3.710333e+00  0.8217053
    -#> Cell1526     5.918066e+00  0.8804017
    -#> Cell566     -4.678836e+00  0.8158012
    -#> Cell283     -3.498849e+00  0.8229946
    -#> Cell1326     7.322040e+00  0.8889606
    -#> Cell1239     4.381677e+00  0.8710357
    -#> Cell1277     4.259180e-01  0.8469207
    -#> Cell850     -5.714969e+00  0.8094847
    -#> Cell1304     1.633186e+00  0.8542804
    -#> Cell231     -6.066028e+00  0.8073446
    -#> Cell137      1.006406e-01  0.8449377
    -#> Cell1301     2.082097e+00  0.8570170
    -#> Cell274     -5.501316e+00  0.8107872
    -#> Cell560     -2.784770e+00  0.8273477
    -#> Cell880     -1.551019e+01  0.7497714
    -#> Cell687     -7.574809e+00  0.7981468
    -#> Cell1097     4.557561e+00  0.8721079
    -#> Cell219     -6.825235e+00  0.8027164
    -#> Cell428      1.654634e+00  0.8544111
    -#> Cell121     -5.873043e+00  0.8085211
    -#> Cell759     -4.836695e+00  0.8148388
    -#> Cell332      5.754681e-01  0.8478323
    -#> Cell1950     4.048628e+00  0.8690053
    -#> Cell1423     3.268933e+00  0.8642522
    -#> Cell1672     2.969972e+00  0.8624297
    -#> Cell1933     2.140840e+00  0.8573751
    -#> Cell307     -3.730342e+00  0.8215834
    -#> Cell607     -1.614551e+00  0.8344816
    -#> Cell1928     2.186463e+00  0.8576532
    -#> Cell813     -9.242206e-01  0.8386900
    -#> Cell1009     3.415880e+00  0.8651480
    -#> Cell935     -6.498383e+00  0.8047089
    -#> Cell1052     2.397818e+00  0.8589417
    -#> Cell107     -2.091316e+00  0.8315752
    -#> Cell91      -6.143081e+00  0.8068749
    -#> Cell872     -3.837571e+00  0.8209297
    -#> Cell827     -2.599654e+00  0.8284762
    -#> Cell1785     3.484115e+00  0.8655640
    -#> Cell204     -4.073165e+00  0.8194935
    -#> Cell767     -2.521967e+00  0.8289498
    -#> Cell1963     8.464207e-01  0.8494841
    -#> Cell750     -3.388674e+00  0.8236662
    -#> Cell359     -1.650923e+00  0.8342599
    -#> Cell1436     3.045643e+00  0.8628910
    -#> Cell1325     4.851375e+00  0.8738990
    -#> Cell1550     5.102071e+00  0.8754273
    -#> Cell1066     3.789751e+00  0.8674272
    -#> Cell1452     2.978715e+00  0.8624829
    -#> Cell1475     2.560437e+00  0.8599331
    -#> Cell669     -8.142511e+00  0.7946860
    -#> Cell466     -3.171648e+00  0.8249893
    -#> Cell1387     1.290024e+00  0.8521884
    -#> Cell1255     2.319424e+00  0.8584638
    -#> Cell564     -5.331259e+00  0.8118239
    -#> Cell1148     4.714649e+00  0.8730655
    -#> Cell1655     4.792272e+00  0.8735387
    -#> Cell1117     3.183319e+00  0.8637303
    -#> Cell169     -2.921310e+00  0.8265154
    -#> Cell296     -2.316182e-01  0.8429122
    -#> Cell229     -5.889071e+00  0.8084234
    -#> Cell505      6.657080e-01  0.8483825
    -#> Cell745     -6.593013e-01  0.8403050
    -#> Cell53      -3.020890e+00  0.8259083
    -#> Cell161     -7.415454e+00  0.7991183
    -#> Cell277     -8.239001e+00  0.7940978
    -#> Cell258     -1.938742e+00  0.8325053
    -#> Cell195     -7.220083e+00  0.8003093
    -#> Cell1571     1.297414e+00  0.8522334
    -#> Cell1340     3.891764e+00  0.8680491
    -#> Cell598     -3.115143e+00  0.8253337
    -#> Cell440     -3.629724e-01  0.8421114
    -#> Cell405     -3.118424e+00  0.8253137
    -#> Cell1300     1.603117e+00  0.8540971
    -#> Cell1018     1.948847e+00  0.8562047
    -#> Cell574     -4.716389e+00  0.8155722
    -#> Cell226     -4.693817e+00  0.8157099
    -#> Cell1174     2.068747e+00  0.8569356
    -#> Cell582     -4.669245e+00  0.8158596
    -#> Cell526     -2.282387e+00  0.8304104
    -#> Cell595     -2.082865e-03  0.8443115
    -#> Cell225     -2.907184e+00  0.8266015
    -#> Cell896     -6.381066e-01  0.8404342
    -#> Cell220     -5.370176e+00  0.8115866
    -#> Cell105     -3.506897e+00  0.8229455
    -#> Cell120     -4.165303e-01  0.8417849
    -#> Cell1973     4.555069e+00  0.8720927
    -#> Cell711     -5.373539e+00  0.8115662
    -#> Cell1515     7.026531e+00  0.8871591
    -#> Cell1984     3.203246e-01  0.8462769
    -#> Cell618     -6.033430e+00  0.8075433
    -#> Cell1418     5.178101e+00  0.8758908
    -#> Cell1896     5.243042e+00  0.8762867
    -#> Cell1569     4.048764e+00  0.8690062
    -#> Cell503     -1.910114e+00  0.8326798
    -#> Cell1615     4.125922e+00  0.8694765
    -#> Cell1201     4.967158e+00  0.8746048
    -#> Cell1312     4.927209e+00  0.8743613
    -#> Cell1821     5.096821e-01  0.8474313
    -#> Cell864     -6.103643e-01  0.8406033
    -#> Cell1891     4.502614e+00  0.8717729
    -#> Cell430     -1.864689e+00  0.8329567
    -#> Cell680     -7.498379e-01  0.8397530
    -#> Cell1351     3.262226e+00  0.8642113
    -#> Cell1953     2.223310e+00  0.8578779
    -#> Cell380     -1.936683e+00  0.8325178
    -#> Cell1050     3.437410e+00  0.8652792
    -#> Cell1648     4.934439e+00  0.8744054
    -#> Cell1893     2.043078e+00  0.8567791
    -#> Cell1110     2.231037e+00  0.8579250
    -#> Cell539     -6.001406e+00  0.8077386
    -#> Cell111     -3.382416e+00  0.8237044
    -#> Cell1850     6.015278e+00  0.8809944
    -#> Cell1972     6.007107e+00  0.8809446
    -#> Cell1153     2.156118e+00  0.8574683
    -#> Cell95      -7.269256e+00  0.8000095
    -#> Cell463      6.269076e-01  0.8481459
    -#> Cell1674     2.133560e+00  0.8573307
    -#> Cell235     -2.812617e+00  0.8271780
    -#> Cell365     -7.569925e+00  0.7981766
    -#> Cell843      9.370951e-02  0.8448955
    -#> Cell272     -5.144375e+00  0.8129632
    -#> Cell803     -5.202824e+00  0.8126069
    -#> Cell1402     1.490359e+00  0.8534097
    -#> Cell1925     7.658634e-01  0.8489930
    -#> Cell1772     4.911765e+00  0.8742672
    -#> Cell215     -4.442662e+00  0.8172409
    -#> Cell1430     3.143584e+00  0.8634880
    -#> Cell515      3.017874e-01  0.8461639
    -#> Cell1878     6.958891e+00  0.8867468
    -#> Cell657     -5.234652e+00  0.8124128
    -#> Cell1450     3.102892e+00  0.8632400
    -#> Cell1751     3.052342e+00  0.8629318
    -#> Cell363     -2.497784e+00  0.8290973
    -#> Cell631     -8.340916e+00  0.7934765
    -#> Cell804      1.329239e+00  0.8524275
    -#> Cell1433     3.873284e+00  0.8679364
    -#> Cell685     -6.945614e+00  0.8019825
    -#> Cell608     -3.181663e+00  0.8249282
    -#> Cell1841     3.308432e+00  0.8644930
    -#> Cell371     -3.629258e+00  0.8221996
    -#> Cell964     -4.188391e+00  0.8187910
    -#> Cell370     -4.745255e+00  0.8153963
    -#> Cell858     -2.145241e-01  0.8430164
    -#> Cell1465     3.586194e+00  0.8661862
    -#> Cell903     -8.937069e-01  0.8388760
    -#> Cell400      1.193809e+00  0.8516018
    -#> Cell718      2.008210e+00  0.8565666
    -#> Cell1382     1.110675e+01  0.9120329
    -#> Cell1700     2.897870e+00  0.8619901
    -#> Cell801     -8.605064e+00  0.7918662
    -#> Cell1988     5.251090e+00  0.8763357
    -#> Cell1294     1.138340e+00  0.8512637
    -#> Cell398     -7.584313e+00  0.7980889
    -#> Cell1457     3.443685e+00  0.8653175
    -#> Cell852     -1.841001e+00  0.8331011
    -#> Cell1670     8.579196e-01  0.8495542
    -#> Cell1283     1.696793e+00  0.8546681
    -#> Cell1967     5.426420e+00  0.8774046
    -#> Cell1288     7.200561e+00  0.8882201
    -#> Cell861     -7.638791e+00  0.7977568
    -#> Cell516     -5.894441e+00  0.8083906
    -#> Cell1435     3.261256e+00  0.8642054
    -#> Cell1769     5.885843e+00  0.8802053
    -#> Cell774     -9.726718e+00  0.7850284
    -#> Cell1905     4.992353e+00  0.8747584
    -#> Cell468     -9.778891e+00  0.7847104
    -#> Cell1323     5.078190e+00  0.8752817
    -#> Cell1887     3.564311e+00  0.8660528
    -#> Cell1090     2.802675e+00  0.8614098
    -#> Cell664     -3.982899e+00  0.8200437
    -#> Cell1520     7.467828e+00  0.8898494
    -#> Cell1572     4.304011e+00  0.8705622
    -#> Cell837     -1.144457e+00  0.8373474
    -#> Cell36       1.710862e+00  0.8547539
    -#> Cell1298     1.949619e+00  0.8562094
    -#> Cell50      -4.688545e+00  0.8157420
    -#> Cell1580     2.893457e+00  0.8619632
    -#> Cell1130     3.194021e+00  0.8637955
    -#> Cell1027     2.877252e+00  0.8618644
    -#> Cell1682     3.398665e+00  0.8650430
    -#> Cell1057     3.508827e+00  0.8657146
    -#> Cell1205     4.906683e+00  0.8742362
    -#> Cell1114     4.140353e+00  0.8695645
    -#> Cell1354     6.044346e+00  0.8811716
    -#> Cell1448     5.351289e+00  0.8769466
    -#> Cell1467     3.706975e+00  0.8669225
    -#> Cell1823     4.315766e+00  0.8706338
    -#> Cell663     -3.892971e+00  0.8205919
    -#> Cell1105     4.871124e+00  0.8740194
    -#> Cell350     -5.856891e+00  0.8086195
    -#> Cell1394     4.368809e+00  0.8709572
    -#> Cell246     -1.865186e+00  0.8329537
    -#> Cell1055     5.991891e+00  0.8808518
    -#> Cell1065     3.442988e+00  0.8653132
    -#> Cell1744     6.303191e+00  0.8827495
    -#> Cell182     -2.299216e+00  0.8303078
    -#> Cell287      1.351415e+00  0.8525626
    -#> Cell1196     1.443416e+00  0.8531235
    -#> Cell275     -9.659975e+00  0.7854353
    -#> Cell1616     7.444284e+00  0.8897058
    -#> Cell1851     3.474343e+00  0.8655044
    -#> Cell649     -2.486285e+00  0.8291674
    -#> Cell312     -1.341652e+00  0.8361452
    -#> Cell1042     4.025797e+00  0.8688661
    -#> Cell152     -2.332458e+00  0.8301051
    -#> Cell1901     2.630160e+00  0.8603581
    -#> Cell1695     6.045114e+00  0.8811763
    -#> Cell1917     4.764196e+00  0.8733676
    -#> Cell1089     4.416587e+00  0.8712485
    -#> Cell764     -2.943015e+00  0.8263831
    -#> Cell1356     1.356056e+00  0.8525909
    -#> Cell1556     2.952237e+00  0.8623215
    -#> Cell1455     3.346602e+00  0.8647257
    -#> Cell1362     7.477613e+00  0.8899090
    -#> Cell1403     3.422879e+00  0.8651906
    -#> Cell1898     8.128245e+00  0.8938754
    -#> Cell1584     3.302191e+00  0.8644549
    -#> Cell924      8.197529e-01  0.8493215
    -#> Cell1188     2.790112e+00  0.8613332
    -#> Cell146      3.860961e-01  0.8466779
    -#> Cell376     -5.534698e+00  0.8105837
    -#> Cell1804     3.630532e+00  0.8664565
    -#> Cell103     -2.346748e+00  0.8300180
    -#> Cell766     -5.119777e-01  0.8412031
    -#> Cell435     -4.820987e+00  0.8149346
    -#> Cell1888     1.645193e+00  0.8543536
    -#> Cell620     -1.380160e+01  0.7601872
    -#> Cell1464     5.416359e+00  0.8773433
    -#> Cell185     -3.840412e+00  0.8209124
    -#> Cell645     -4.182135e-01  0.8417747
    -#> Cell144     -3.332216e+00  0.8240104
    -#> Cell610     -8.742003e+00  0.7910314
    -#> Cell1091     2.801564e+00  0.8614030
    -#> Cell1565     4.140734e+00  0.8695668
    -#> Cell1059     3.939935e+00  0.8683427
    -#> Cell563     -3.049525e+00  0.8257337
    -#> Cell1072     1.574722e+01  0.9403220
    -#> Cell845     -5.302509e+00  0.8119992
    -#> Cell54       4.776956e-01  0.8472363
    -#> Cell133      1.620048e+00  0.8542003
    -#> Cell960     -6.667556e-01  0.8402595
    -#> Cell303     -3.304544e+00  0.8241791
    -#> Cell1143     1.242507e+00  0.8518987
    -#> Cell1129     5.002102e+00  0.8748179
    -#> Cell1380     1.748233e+00  0.8549817
    -#> Cell1554     4.014637e+00  0.8687981
    -#> Cell1690     4.916968e+00  0.8742989
    -#> Cell1191     6.697021e+00  0.8851504
    -#> Cell1496     3.548517e+00  0.8659566
    -#> Cell1026     5.000829e+00  0.8748101
    -#> Cell816     -2.035782e+00  0.8319137
    -#> Cell694      1.443715e+00  0.8531253
    -#> Cell1786     2.360793e+00  0.8587160
    -#> Cell323     -1.126546e+00  0.8374566
    -#> Cell243     -2.878180e+00  0.8267783
    -#> Cell1459     2.910312e+00  0.8620660
    -#> Cell1795     3.638052e+00  0.8665024
    -#> Cell1025     2.697773e+00  0.8607703
    -#> Cell1341     6.737708e+00  0.8853984
    -#> Cell783     -2.020711e+00  0.8320056
    -#> Cell1078     5.815489e+00  0.8797764
    -#> Cell1460     1.235202e-01  0.8450772
    -#> Cell831      5.123096e-01  0.8474473
    -#> Cell232     -2.440265e+00  0.8294479
    -#> Cell1938     6.172342e+00  0.8819519
    -#> Cell1628     4.043549e+00  0.8689744
    -#> Cell1156     2.282823e+00  0.8582407
    -#> Cell1532     6.069629e+00  0.8813257
    -#> Cell1560     2.120105e+00  0.8572487
    -#> Cell948     -2.735137e+00  0.8276503
    -#> Cell1523     3.532187e+00  0.8658570
    -#> Cell1915     5.009858e+00  0.8748652
    -#> Cell1318     3.504385e-01  0.8464605
    -#> Cell661     -2.563705e+00  0.8286954
    -#> Cell122     -6.903038e+00  0.8022421
    -#> Cell592     -5.602448e+00  0.8101707
    -#> Cell139     -1.223010e+00  0.8368685
    -#> Cell1484     1.537295e+00  0.8536958
    -#> Cell1697     3.587075e+00  0.8661916
    -#> Cell1371     3.616565e+00  0.8663714
    -#> Cell247     -1.183339e+00  0.8371103
    -#> Cell1637     4.470325e+00  0.8715761
    -#> Cell550     -9.182961e+00  0.7883432
    -#> Cell1606     3.894338e+00  0.8680647
    -#> Cell403     -5.153906e+00  0.8129051
    -#> Cell1168     3.653922e+00  0.8665991
    -#> Cell79      -2.924591e+00  0.8264954
    -#> Cell1552     1.916419e+00  0.8560070
    -#> Cell1190     3.784759e+00  0.8673967
    -#> Cell128     -3.894451e+00  0.8205829
    -#> Cell1016     2.199875e+00  0.8577350
    -#> Cell1427     4.329922e+00  0.8707201
    -#> Cell1193     3.123494e+00  0.8633655
    -#> Cell423      8.177897e-01  0.8493096
    -#> Cell1285     2.182494e+00  0.8576290
    -#> Cell708     -4.752708e+00  0.8153508
    -#> Cell974     -2.371104e+00  0.8298695
    -#> Cell410      5.175616e-01  0.8474793
    -#> Cell1701     5.709354e+00  0.8791294
    -#> Cell676     -4.582072e+00  0.8163911
    -#> Cell1668     4.751542e+00  0.8732904
    -#> Cell665     -1.995468e+00  0.8321595
    -#> Cell61      -9.139995e+00  0.7886052
    -#> Cell1721     6.592624e+00  0.8845140
    -#> Cell1062     7.118597e+00  0.8877204
    -#> Cell946     -6.905567e-02  0.8439032
    -#> Cell1039     6.053066e+00  0.8812247
    -#> Cell2       -3.233870e+00  0.8246099
    -#> Cell678     -9.490204e+00  0.7864702
    -#> Cell253     -3.692694e+00  0.8218129
    -#> Cell1865     2.759221e+00  0.8611449
    -#> Cell715     -4.774183e+00  0.8152199
    -#> Cell943     -6.044608e+00  0.8074752
    -#> Cell1098     6.449359e+00  0.8836406
    -#> Cell716      1.983220e+00  0.8564142
    -#> Cell1013     3.611431e+00  0.8663401
    -#> Cell1848     5.072667e+00  0.8752480
    -#> Cell202     -4.655746e+00  0.8159419
    +    
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +pathwaydata   <- LoadPathway("Hypoxia_6hr", "human")
    +expr_filtered <- DataPreProcess(norm_matrix, pathwaydata)
    +pathway_stat  <- PathwayMaxMin(expr_filtered, pathwaydata)
    +scores        <- ComputeCellData(expr_filtered, pathway_stat)
    +} # }
     
     
    -
    - -
    +
    -
    - +
    diff --git a/docs/reference/ComputeCellData.md b/docs/reference/ComputeCellData.md new file mode 100644 index 0000000..06e5c1a --- /dev/null +++ b/docs/reference/ComputeCellData.md @@ -0,0 +1,50 @@ +# ComputeCellData + +Computes a per-cell pathway activation score by measuring each cell's +distance to the pathway ON and OFF reference states from +[`PathwayMaxMin()`](https://raredonlab.github.io/PathwayEmbed/reference/PathwayMaxMin.md). +Scores are normalized to \[0, 1\]\\ where 1 indicates proximity to the +ON state and 0 indicates proximity to the OFF state. + +## Usage + +``` r +ComputeCellData(expr_data, pathway.stat, distance.method = "manhattan") +``` + +## Arguments + +- expr_data: + + A z-scored gene-by-cell numeric matrix, e.g. from + [`DataPreProcess()`](https://raredonlab.github.io/PathwayEmbed/reference/DataPreProcess.md). + +- pathway.stat: + + A data frame from + [`PathwayMaxMin()`](https://raredonlab.github.io/PathwayEmbed/reference/PathwayMaxMin.md) + with columns `pathway.on` and `pathway.off`. Rownames must be gene + symbols. + +- distance.method: + + Character string specifying the distance metric. One of `"manhattan"` + (default) or `"euclidean"`. + +## Value + +A named numeric vector of length equal to the number of cells, with +scores in \[0, 1\]. A score near 1 indicates the cell is close to the ON +state; a score near 0 indicates proximity to the OFF state. Cells where +both distances are 0 return `NaN` with a warning. + +## Examples + +``` r +if (FALSE) { # \dontrun{ +pathwaydata <- LoadPathway("Hypoxia_6hr", "human") +expr_filtered <- DataPreProcess(norm_matrix, pathwaydata) +pathway_stat <- PathwayMaxMin(expr_filtered, pathwaydata) +scores <- ComputeCellData(expr_filtered, pathway_stat) +} # } +``` diff --git a/docs/reference/DataPreProcess.html b/docs/reference/DataPreProcess.html new file mode 100644 index 0000000..98243a9 --- /dev/null +++ b/docs/reference/DataPreProcess.html @@ -0,0 +1,124 @@ + +DataPreProcess — DataPreProcess • PathwayEmbed + Skip to contents + + +
    +
    +
    + +
    +

    Preprocess expression data for pathway analysis.

    +
    + +
    +

    Usage

    +
    DataPreProcess(
    +  x,
    +  pathwaydata,
    +  Seurat.object = FALSE,
    +  assay = "RNA",
    +  slot = "data",
    +  scale.data = TRUE
    +)
    +
    + +
    +

    Arguments

    + + +
    x
    +

    A Seurat object OR a gene-by-cell normalized expression matrix

    + + +
    pathwaydata
    +

    Pathway data from the output of LoadPathway()

    + + +
    Seurat.object
    +

    Logical; whether x is a Seurat object

    + + +
    assay
    +

    Assay to use if x is a Seurat object (default = "RNA")

    + + +
    slot
    +

    Slot to extract from Seurat object (default = "data")

    + + +
    scale.data
    +

    Logical; whether to apply row-wise z-score scaling +(default = TRUE). If FALSE, the filtered expression matrix is returned +as-is without any scaling.

    + +
    +
    +

    Value

    +

    A gene-by-cell expression matrix of pathway genes. If +scale.data = TRUE (default), values are row-wise z-scored; +if scale.data = FALSE, raw input filtered values are returned.

    +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +DataPreProcess(seurat_obj, pathwaydata, Seurat.object = TRUE)
    +DataPreProcess(norm_matrix, pathwaydata)
    +DataPreProcess(norm_matrix, pathwaydata, scale.data = FALSE)
    +} # }
    +
    +
    +
    +
    + + +
    + + + +
    + + + + + + + diff --git a/docs/reference/DataPreProcess.md b/docs/reference/DataPreProcess.md new file mode 100644 index 0000000..fa0336d --- /dev/null +++ b/docs/reference/DataPreProcess.md @@ -0,0 +1,60 @@ +# DataPreProcess + +Preprocess expression data for pathway analysis. + +## Usage + +``` r +DataPreProcess( + x, + pathwaydata, + Seurat.object = FALSE, + assay = "RNA", + slot = "data", + scale.data = TRUE +) +``` + +## Arguments + +- x: + + A Seurat object OR a gene-by-cell normalized expression matrix + +- pathwaydata: + + Pathway data from the output of LoadPathway() + +- Seurat.object: + + Logical; whether x is a Seurat object + +- assay: + + Assay to use if x is a Seurat object (default = "RNA") + +- slot: + + Slot to extract from Seurat object (default = "data") + +- scale.data: + + Logical; whether to apply row-wise z-score scaling (default = TRUE). + If FALSE, the filtered expression matrix is returned as-is without any + scaling. + +## Value + +A gene-by-cell expression matrix of pathway genes. If +`scale.data = TRUE` (default), values are row-wise z-scored; if +`scale.data = FALSE`, raw input filtered values are returned. + +## Examples + +``` r +if (FALSE) { # \dontrun{ +DataPreProcess(seurat_obj, pathwaydata, Seurat.object = TRUE) +DataPreProcess(norm_matrix, pathwaydata) +DataPreProcess(norm_matrix, pathwaydata, scale.data = FALSE) +} # } +``` diff --git a/docs/reference/ListPathway.html b/docs/reference/ListPathway.html new file mode 100644 index 0000000..fb613ab --- /dev/null +++ b/docs/reference/ListPathway.html @@ -0,0 +1,118 @@ + +ListPathway List available pathways or pathway metadata — ListPathway • PathwayEmbed + Skip to contents + + +
    +
    +
    + +
    +

    Reads the "SUMMARY" sheet from Pathway_Database_Combined.xlsx. +Behaviour depends on the query argument:

    • NULL: returns the full summary table as a tibble.

    • +
    • "Pathway": returns a sorted character vector of unique pathway names.

    • +
    • A valid pathway name (e.g. "WNT", "NOTCH"): returns the +subset of rows for that pathway as a tibble.

    • +
    + +
    +

    Usage

    +
    ListPathway(query = NULL, drop_empty = TRUE)
    +
    + +
    +

    Arguments

    + + +
    query
    +

    Optional character string. One of NULL, "Pathway", +or a valid pathway name. Default NULL.

    + + +
    drop_empty
    +

    Logical; if TRUE, removes entries with 0 genes. +Default TRUE.

    + +
    +
    +

    Value

    +

    A tibble (full table or pathway subset) or a character vector +(when query = "Pathway").

    +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +ListPathway()
    +ListPathway("Pathway")
    +ListPathway("WNT")
    +} # }
    +
    +
    +
    +
    + + +
    + + + +
    + + + + + + + diff --git a/docs/reference/ListPathway.md b/docs/reference/ListPathway.md new file mode 100644 index 0000000..49b75d1 --- /dev/null +++ b/docs/reference/ListPathway.md @@ -0,0 +1,44 @@ +# ListPathway List available pathways or pathway metadata + +Reads the "SUMMARY" sheet from Pathway_Database_Combined.xlsx. Behaviour +depends on the `query` argument: + +- `NULL`: returns the full summary table as a tibble. + +- `"Pathway"`: returns a sorted character vector of unique pathway + names. + +- A valid pathway name (e.g. `"WNT"`, `"NOTCH"`): returns the subset of + rows for that pathway as a tibble. + +## Usage + +``` r +ListPathway(query = NULL, drop_empty = TRUE) +``` + +## Arguments + +- query: + + Optional character string. One of `NULL`, `"Pathway"`, or a valid + pathway name. Default `NULL`. + +- drop_empty: + + Logical; if `TRUE`, removes entries with 0 genes. Default `TRUE`. + +## Value + +A tibble (full table or pathway subset) or a character vector (when +`query = "Pathway"`). + +## Examples + +``` r +if (FALSE) { # \dontrun{ +ListPathway() +ListPathway("Pathway") +ListPathway("WNT") +} # } +``` diff --git a/docs/reference/LoadPathway.html b/docs/reference/LoadPathway.html index 9c172a7..297be98 100644 --- a/docs/reference/LoadPathway.html +++ b/docs/reference/LoadPathway.html @@ -1,124 +1,109 @@ -LoadPathway — LoadPathway • PathwayEmbed - - -
    -
    +
    +
    +
    -
    - -
    -

    This function reads pathway data from the package's built-in Excel file.

    +
    +

    Reads pathway gene data from the package's built-in Excel database and +returns a two-column data frame with gene symbols and their coefficients +for the requested species.

    -
    -
    LoadPathway(pathway)
    +
    +

    Usage

    +
    LoadPathway(Sheet.name, species = "human")
    -
    -

    Arguments

    +
    +

    Arguments

    -
    pathway
    -

    A character string specifying the pathway name.

    +
    Sheet.name
    +

    A character string specifying the sheet name +(e.g. "Hypoxia_6hr", "HIPPO_heat"). Use ListPathway() +to see available sheets.

    + + +
    species
    +

    A character string specifying the species: either +"human" or "mouse". Determines which gene symbol column is +used. Default "human".

    -
    -

    Value

    -

    A data frame with pathway data.

    +
    +

    Value

    +

    A data frame with two columns:

    Gene_Symbol
    +

    Gene symbols for the requested species.

    + +
    Coefficient
    +

    Numeric pathway coefficients.

    + + +

    Rows with NA gene symbols are dropped.

    -
    -

    Examples

    -
    LoadPathway("Wnt")
    -#> # A tibble: 18 × 4
    -#>    Molecules Coefficients Notes Ref                                             
    -#>    <chr>            <dbl> <lgl> <chr>                                           
    -#>  1 Lgr5                 1 NA    https://www.ncbi.nlm.nih.gov/pmc/articles/PMC55…
    -#>  2 Rnf43                1 NA    NA                                              
    -#>  3 Lrp5                 1 NA    NA                                              
    -#>  4 Lrp6                 1 NA    NA                                              
    -#>  5 Fzd6                 1 NA    NA                                              
    -#>  6 Ctnnb1               1 NA    NA                                              
    -#>  7 Gsk3b                1 NA    NA                                              
    -#>  8 Ccnd1                1 NA    NA                                              
    -#>  9 Axin2                1 NA    NA                                              
    -#> 10 Myc                  1 NA    NA                                              
    -#> 11 Lef1                 1 NA    NA                                              
    -#> 12 Tcf7                 1 NA    NA                                              
    -#> 13 Tcf7l1               1 NA    NA                                              
    -#> 14 Tcf7l2               1 NA    NA                                              
    -#> 15 Tle1                 1 NA    NA                                              
    -#> 16 Apc                  1 NA    NA                                              
    -#> 17 Csnk1a1              1 NA    NA                                              
    -#> 18 Dvl1                -1 NA    NA                                              
    +    
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +LoadPathway("Hypoxia_6hr", "human")
    +LoadPathway("HIPPO_heat", "mouse")
    +} # }
    +
     
    -
    - -
    +
    -
    - +
    diff --git a/docs/reference/LoadPathway.md b/docs/reference/LoadPathway.md new file mode 100644 index 0000000..73a3c59 --- /dev/null +++ b/docs/reference/LoadPathway.md @@ -0,0 +1,49 @@ +# LoadPathway + +Reads pathway gene data from the package's built-in Excel database and +returns a two-column data frame with gene symbols and their coefficients +for the requested species. + +## Usage + +``` r +LoadPathway(Sheet.name, species = "human") +``` + +## Arguments + +- Sheet.name: + + A character string specifying the sheet name (e.g. `"Hypoxia_6hr"`, + `"HIPPO_heat"`). Use + [`ListPathway()`](https://raredonlab.github.io/PathwayEmbed/reference/ListPathway.md) + to see available sheets. + +- species: + + A character string specifying the species: either `"human"` or + `"mouse"`. Determines which gene symbol column is used. Default + `"human"`. + +## Value + +A data frame with two columns: + +- Gene_Symbol: + + Gene symbols for the requested species. + +- Coefficient: + + Numeric pathway coefficients. + +Rows with `NA` gene symbols are dropped. + +## Examples + +``` r +if (FALSE) { # \dontrun{ +LoadPathway("Hypoxia_6hr", "human") +LoadPathway("HIPPO_heat", "mouse") +} # } +``` diff --git a/docs/reference/PathwayMaxMin.html b/docs/reference/PathwayMaxMin.html index 1e278a2..7d7037c 100644 --- a/docs/reference/PathwayMaxMin.html +++ b/docs/reference/PathwayMaxMin.html @@ -1,132 +1,92 @@ -PathwayMaxMin — PathwayMaxMin • PathwayEmbed - - -
    -
    +
    +
    +
    -
    - -
    +

    A function to obtain the hypothetical max and min activation status of selected pathway for a given scRNA seq data set

    -
    -
    PathwayMaxMin(x, pathway, scale.data = TRUE)
    +
    +

    Usage

    +
    PathwayMaxMin(expr_data, pathwaydata)
    -
    -

    Arguments

    - - -
    x
    -

    A Seurat Object.

    +
    +

    Arguments

    -
    pathway
    -

    A character string specifying the pathway name.

    +
    expr_data
    +

    Pre-processed gene-by-cell matrix (z-scored, pathway-filtered)

    -
    scale.data
    -

    A logical indicating whether to use scaled data (scale.data = TRUE) or normalized data. Default is TRUE.

    +
    pathwaydata
    +

    Pathway data outcome from LoadPathway()

    -
    -

    Value

    -

    The hypothetical value for Pathway on and off (max and min value for features)

    +
    +

    Value

    +

    A data.frame with pathway.on and pathway.off values per gene

    -
    -

    Examples

    -
    data(fake_test_object) # load the fake test data
    -PathwayMaxMin(fake_test_object, "Wnt")
    -#> Centering and scaling data matrix
    -#>         pathway.on pathway.off
    -#> Lgr5      1.851647  -11.600077
    -#> Rnf43     1.479722   -9.998238
    -#> Lrp5      1.880735   -7.935503
    -#> Lrp6      1.635447   -7.746165
    -#> Fzd6      1.873864   -8.215280
    -#> Ctnnb1    1.896552   -8.294299
    -#> Gsk3b     1.981532  -11.693745
    -#> Ccnd1     1.975098  -13.129679
    -#> Axin2     1.994353  -13.235483
    -#> Myc       1.685388  -11.679067
    -#> Lef1      1.596498  -10.771246
    -#> Tcf7      1.595631  -10.436295
    -#> Tcf7l1    1.497348   -9.843343
    -#> Tcf7l2    1.716832  -11.026494
    -#> Tle1      1.891611  -12.632374
    -#> Apc       1.944771   -8.883710
    -#> Csnk1a1   1.808021   -8.091854
    -#> Dvl1     -8.132137    2.135900
    +    
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +pathwaydata <- LoadPathway("Hypoxia_6hr", "human")
    +matrix_filtered <- DataPreProcess(expr_data, pathwaydata)
    +PathwayMaxMin(matrix_filtered, pathwaydata)
    +} # }
     
    -
    - -
    +
    -
    - +
    diff --git a/docs/reference/PathwayMaxMin.md b/docs/reference/PathwayMaxMin.md new file mode 100644 index 0000000..4f5fe75 --- /dev/null +++ b/docs/reference/PathwayMaxMin.md @@ -0,0 +1,34 @@ +# PathwayMaxMin + +A function to obtain the hypothetical max and min activation status of +selected pathway for a given scRNA seq data set + +## Usage + +``` r +PathwayMaxMin(expr_data, pathwaydata) +``` + +## Arguments + +- expr_data: + + Pre-processed gene-by-cell matrix (z-scored, pathway-filtered) + +- pathwaydata: + + Pathway data outcome from LoadPathway() + +## Value + +A data.frame with pathway.on and pathway.off values per gene + +## Examples + +``` r +if (FALSE) { # \dontrun{ +pathwaydata <- LoadPathway("Hypoxia_6hr", "human") +matrix_filtered <- DataPreProcess(expr_data, pathwaydata) +PathwayMaxMin(matrix_filtered, pathwaydata) +} # } +``` diff --git a/docs/reference/PlotPathway-1.png b/docs/reference/PlotPathway-1.png deleted file mode 100644 index 2d9c1e3..0000000 Binary files a/docs/reference/PlotPathway-1.png and /dev/null differ diff --git a/docs/reference/PlotPathway.html b/docs/reference/PlotPathway.html index af58278..65fd29c 100644 --- a/docs/reference/PlotPathway.html +++ b/docs/reference/PlotPathway.html @@ -1,117 +1,112 @@ -PlotPathway — PlotPathway • PathwayEmbed - - -
    -
    +
    +
    +
    -
    - -
    -

    A function to plot the Pathway activation status

    +
    +

    Plot the activation status of a pathway across cell populations. +Creates a density plot of pathway activation (z-scored) for each group.

    -
    +
    +

    Usage

    PlotPathway(to.plot, pathway, group, color)
    -
    -

    Arguments

    +
    +

    Arguments

    to.plot
    -

    A data frame with pathway activation values genereated by PreparePlotData

    +

    A dataframe returned by PreparePlotData, containing at least:

    scale
    +

    Z-scored pathway activation values.

    + +
    group
    +

    Grouping variable for coloring (e.g., genotype).

    + + +
    pathway
    -

    A character string indicating the pathway name.

    +

    Character string indicating the pathway name (used in plot title).

    group
    -

    Column name to group and color by (e.g., genotype).

    +

    Column name in to.plot to group and color the plot by (e.g., "genotype").

    color
    -

    A character vector of colors to use for fill and outline.

    +

    Character vector of colors for each group (fill and outline). Length must match number of unique groups.

    -
    -

    Value

    -

    A ggplot object.

    +
    +

    Value

    +

    A ggplot2 object showing density distributions of pathway activity per group.

    -
    -

    Examples

    -
    data(fake_to_plot)
    -PlotPathway(to.plot = fake_to_plot,"Wnt","genotype",color = c("#ae282c", "#2066a8"))
    -
    +    
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +data(fake_to_plot)
    +PlotPathway(to.plot = fake_to_plot,
    +            pathway = "Wnt",
    +            group = "genotype",
    +            color = c("#ae282c", "#2066a8"))
    +} # }
     
    -
    - -
    +
    -
    - +
    diff --git a/docs/reference/PlotPathway.md b/docs/reference/PlotPathway.md new file mode 100644 index 0000000..1e2453f --- /dev/null +++ b/docs/reference/PlotPathway.md @@ -0,0 +1,55 @@ +# PlotPathway + +Plot the activation status of a pathway across cell populations. Creates +a density plot of pathway activation (z-scored) for each group. + +## Usage + +``` r +PlotPathway(to.plot, pathway, group, color) +``` + +## Arguments + +- to.plot: + + A dataframe returned by PreparePlotData, containing at least: + + scale + + : Z-scored pathway activation values. + + group + + : Grouping variable for coloring (e.g., genotype). + +- pathway: + + Character string indicating the pathway name (used in plot title). + +- group: + + Column name in `to.plot` to group and color the plot by (e.g., + "genotype"). + +- color: + + Character vector of colors for each group (fill and outline). Length + must match number of unique groups. + +## Value + +A ggplot2 object showing density distributions of pathway activity per +group. + +## Examples + +``` r +if (FALSE) { # \dontrun{ +data(fake_to_plot) +PlotPathway(to.plot = fake_to_plot, + pathway = "Wnt", + group = "genotype", + color = c("#ae282c", "#2066a8")) +} # } +``` diff --git a/docs/reference/PreparePlotData.html b/docs/reference/PreparePlotData.html index d963a6e..0adf821 100644 --- a/docs/reference/PreparePlotData.html +++ b/docs/reference/PreparePlotData.html @@ -1,2114 +1,123 @@ -A function to prepare the signal transduction dataframe for plotting — PreparePlotData • PathwayEmbed +PreparePlotData — PreparePlotData • PathwayEmbed + Skip to contents -
    -
    +
    +
    +
    -
    - -
    -

    A function to prepare the signal transduction dataframe for plotting

    +
    +

    Prepares a tidy data frame of pathway activity scores per cell for +downstream plotting with PlotPathway() or CalculatePercentage(). +Accepts either a plain metadata data frame or a Seurat object.

    -
    -
    PreparePlotData(x, final_mds, group)
    +
    +

    Usage

    +
    PreparePlotData(x, score, group, Seurat.object = FALSE)
    -
    -

    Arguments

    +
    +

    Arguments

    x
    -

    A Seurat object containing single-cell RNA sequencing data.

    +

    A metadata data frame (rows = cells, columns = metadata fields) +or a Seurat object. Must contain the column specified by group.

    -
    final_mds
    -

    A 'dataframe' output from ComputeCellData.

    +
    score
    +

    A named numeric vector of per-cell scores from +ComputeCellData(). Names must be cell IDs matching rownames of x.

    group
    -

    group for the comparision

    +

    A character string giving the column name in x metadata +to use for grouping (e.g. "genotype", "Age").

    + + +
    Seurat.object
    +

    Logical; set TRUE if x is a Seurat object. +Default FALSE.

    -
    -

    Value

    -

    data for plotting

    -
    +
    +

    Value

    +

    A data frame with one row per cell and three columns:

    normalized
    +

    Normalized pathway activity score in [0, 1]\ from +ComputeCellData().

    -
    -

    Examples

    -
    data(fake_test_object)
    -data(fake_final_mds)
    -PreparePlotData(fake_test_object, fake_final_mds, "genotype")
    -#>                     V1 normalized genotype         scale
    -#> Cell819   -1.361697687  0.8360230       WT -0.3147161622
    -#> Cell124   -4.866033576  0.8146600       WT -1.0923828770
    -#> Cell1363   3.284125686  0.8643448   Mutant  0.7162644044
    -#> Cell1460   0.123520244  0.8450772   Mutant  0.0148768295
    -#> Cell117   -1.495637744  0.8352065       WT -0.3444395469
    -#> Cell1294   1.138340435  0.8512637   Mutant  0.2400812360
    -#> Cell606   -5.761865732  0.8091988       WT -1.2911819852
    -#> Cell415   -3.688227594  0.8218401       WT -0.8310093849
    -#> Cell787   -5.758319247  0.8092205       WT -1.2903949649
    -#> Cell210   -2.274698672  0.8304572       WT -0.5173253010
    -#> Cell1711   3.876811312  0.8679579   Mutant  0.8477905761
    -#> Cell1193   3.123493564  0.8633655   Mutant  0.6806176346
    -#> Cell361   -5.240672023  0.8123761       WT -1.1755209834
    -#> Cell1048   1.228167834  0.8518113   Mutant  0.2600153349
    -#> Cell1101   2.726820445  0.8609474   Mutant  0.5925896912
    -#> Cell1274   7.028436740  0.8871708   Mutant  1.5471853459
    -#> Cell1125   2.783756541  0.8612944   Mutant  0.6052246976
    -#> Cell1576   5.132836077  0.8756148   Mutant  1.1265220343
    -#> Cell982   -2.161525113  0.8311471       WT -0.4922103254
    -#> Cell1226   2.511031131  0.8596319   Mutant  0.5447026815
    -#> Cell854   -0.559051825  0.8409161       WT -0.1365965440
    -#> Cell40    -4.673461680  0.8158339       WT -1.0496481738
    -#> Cell973   -3.095113108  0.8254558       WT -0.6993880425
    -#> Cell518   -5.928802583  0.8081812       WT -1.3282278725
    -#> Cell1991   3.531548268  0.8658531   Mutant  0.7711713289
    -#> Cell1655   4.792272135  0.8735387   Mutant  1.0509455912
    -#> Cell1971  -0.102871913  0.8436971   Mutant -0.0353631162
    -#> Cell128   -3.894451401  0.8205829       WT -0.8767736596
    -#> Cell768    0.997244490  0.8504036       WT  0.2087698482
    -#> Cell1106   5.098449379  0.8754052   Mutant  1.1188910904
    -#> Cell1472   0.817921009  0.8493104   Mutant  0.1689751747
    -#> Cell365   -7.569925269  0.7981766       WT -1.6924185575
    -#> Cell452    0.636914829  0.8482069       WT  0.1288070840
    -#> Cell1273   1.586153260  0.8539936   Mutant  0.3394578767
    -#> Cell1936   3.466919616  0.8654591   Mutant  0.7568292245
    -#> Cell1325   4.851375323  0.8738990   Mutant  1.0640615092
    -#> Cell340   -0.797647803  0.8394616       WT -0.1895447077
    -#> Cell1187   2.211473303  0.8578057   Mutant  0.4782261337
    -#> Cell1496   3.548517245  0.8659566   Mutant  0.7749370092
    -#> Cell157   -3.143330309  0.8251619       WT -0.7100881904
    -#> Cell310   -1.391485728  0.8358414       WT -0.3213265924
    -#> Cell829   -8.435264399  0.7929013       WT -1.8844507883
    -#> Cell1391   2.796244201  0.8613706   Mutant  0.6079959039
    -#> Cell949   -6.211385893  0.8064585       WT -1.3909375104
    -#> Cell1731   3.162725566  0.8636047   Mutant  0.6893238269
    -#> Cell398   -7.584312587  0.7980889       WT -1.6956113274
    -#> Cell951   -4.708977282  0.8156174       WT -1.0575296392
    -#> Cell471    0.088344814  0.8448627       WT  0.0070708536
    -#> Cell1884   2.920808547  0.8621299   Mutant  0.6356386725
    -#> Cell18    -4.235923057  0.8185013       WT -0.9525515387
    -#> Cell1743   4.683413344  0.8728751   Mutant  1.0267881299
    -#> Cell737   -0.384585902  0.8419797       WT -0.0978798383
    -#> Cell145   -3.842298695  0.8209009       WT -0.8652001619
    -#> Cell1144   1.532098968  0.8536641   Mutant  0.3274623874
    -#> Cell1648   4.934439486  0.8744054   Mutant  1.0824947408
    -#> Cell1031   5.056764874  0.8751511   Mutant  1.1096406495
    -#> Cell49    -2.564632675  0.8286897       WT -0.5816661720
    -#> Cell1574   5.900179299  0.8802927   Mutant  1.2968074468
    -#> Cell229   -5.889071205  0.8084234       WT -1.3194108609
    -#> Cell626   -3.901158602  0.8205420       WT -0.8782620921
    -#> Cell965   -0.048221456  0.8440302       WT -0.0232353287
    -#> Cell94    -2.922874788  0.8265058       WT -0.6611656765
    -#> Cell110   -0.384174046  0.8419822       WT -0.0977884411
    -#> Cell916   -7.622405495  0.7978567       WT -1.7040647371
    -#> Cell61    -9.139994794  0.7886052       WT -2.0408414394
    -#> Cell1697   3.587075369  0.8661916   Mutant  0.7834936574
    -#> Cell190   -2.002755068  0.8321150       WT -0.4569767797
    -#> Cell1364   5.600513823  0.8784659   Mutant  1.2303070103
    -#> Cell890    1.133066567  0.8512316       WT  0.2389108824
    -#> Cell1119   5.987505139  0.8808251   Mutant  1.3161864108
    -#> Cell1157   4.395225667  0.8711182   Mutant  0.9628347958
    -#> Cell700   -7.229416255  0.8002524       WT -1.6168543037
    -#> Cell1613   6.837192624  0.8860049   Mutant  1.5047452980
    -#> Cell354   -1.777760668  0.8334866       WT -0.4070470180
    -#> Cell1023   3.233407146  0.8640356   Mutant  0.7050091703
    -#> Cell749   -2.601269135  0.8284664       WT -0.5897963731
    -#> Cell232   -2.440264740  0.8294479       WT -0.5540669902
    -#> Cell807   -6.101310484  0.8071295       WT -1.3665100626
    -#> Cell550   -9.182960894  0.7883432       WT -2.0503762861
    -#> Cell148   -5.132085142  0.8130381       WT -1.1514238633
    -#> Cell1051   3.635022305  0.8664839   Mutant  0.7941338295
    -#> Cell335   -1.024197509  0.8380805       WT -0.2398196161
    -#> Cell1173   5.811539565  0.8797523   Mutant  1.2771369092
    -#> Cell1206   3.879334852  0.8679733   Mutant  0.8483505887
    -#> Cell1429   3.684289423  0.8667843   Mutant  0.8050669702
    -#> Cell22    -2.336216569  0.8300822       WT -0.5309770804
    -#> Cell1997   3.814125316  0.8675758   Mutant  0.8338795770
    -#> Cell102   -2.228032892  0.8307417       WT -0.5069694376
    -#> Cell429    2.419125800  0.8590716       WT  0.5243074570
    -#> Cell104   -5.555988977  0.8104539       WT -1.2454947267
    -#> Cell100   -2.825999118  0.8270964       WT -0.6396674566
    -#> Cell980   -1.941271131  0.8324899       WT -0.4433325364
    -#> Cell59    -2.394602050  0.8297263       WT -0.5439337280
    -#> Cell840   -4.835286111  0.8148474       WT -1.0855595356
    -#> Cell676   -4.582072394  0.8163911       WT -1.0293674678
    -#> Cell346   -9.100277862  0.7888473       WT -2.0320276336
    -#> Cell1445   4.173118022  0.8697642   Mutant  0.9135456501
    -#> Cell107   -2.091316118  0.8315752       WT -0.4766298560
    -#> Cell1775   1.915576101  0.8560019   Mutant  0.4125619360
    -#> Cell295   -1.396819951  0.8358089       WT -0.3225103396
    -#> Cell1488   2.123955227  0.8572722   Mutant  0.4588045094
    -#> Cell1465   3.586193683  0.8661862   Mutant  0.7832979976
    -#> Cell1182   2.487085077  0.8594859   Mutant  0.5393886791
    -#> Cell1297  -0.817225971  0.8393422   Mutant -0.1938894081
    -#> Cell1446   6.314464277  0.8828183   Mutant  1.3887437361
    -#> Cell417   -3.302960491  0.8241888       WT -0.7455126141
    -#> Cell1024   3.575678466  0.8661221   Mutant  0.7809645073
    -#> Cell293   -3.756013138  0.8214269       WT -0.8460520529
    -#> Cell533   -8.081572479  0.7950575       WT -1.8059610425
    -#> Cell30    -3.949773029  0.8202457       WT -0.8890503906
    -#> Cell1869   3.000673665  0.8626168   Mutant  0.6533619861
    -#> Cell1421   4.339233195  0.8707769   Mutant  0.9504091943
    -#> Cell1984   0.320324635  0.8462769   Mutant  0.0585507891
    -#> Cell486   -3.492257897  0.8230348       WT -0.7875206569
    -#> Cell1632   1.683145163  0.8545849   Mutant  0.3609818906
    -#> Cell975   -2.440686321  0.8294453       WT -0.5541605455
    -#> Cell753  -10.580639455  0.7798228       WT -2.3605429280
    -#> Cell790    2.133719973  0.8573317       WT  0.4609714587
    -#> Cell1171   5.107750506  0.8754619   Mutant  1.1209551553
    -#> Cell1370   4.733619777  0.8731812   Mutant  1.0379297194
    -#> Cell1302   1.834924197  0.8555102   Mutant  0.3946640222
    -#> Cell782   -2.202498308  0.8308974       WT -0.5013029157
    -#> Cell201   -1.587512083  0.8346464       WT -0.3648278938
    -#> Cell1216   3.260351862  0.8641999   Mutant  0.7109886225
    -#> Cell645   -0.418213463  0.8417747       WT -0.1053423178
    -#> Cell28    -1.225058159  0.8368560       WT -0.2843937227
    -#> Cell1487   4.147450170  0.8696078   Mutant  0.9078495540
    -#> Cell1244   0.773216622  0.8490378   Mutant  0.1590545749
    -#> Cell828   -2.404265102  0.8296674       WT -0.5460781098
    -#> Cell144   -3.332216147  0.8240104       WT -0.7520048998
    -#> Cell884   -1.040785277  0.8379794       WT -0.2435007002
    -#> Cell1148   4.714648502  0.8730655   Mutant  1.0337196980
    -#> Cell1345   2.035759316  0.8567345   Mutant  0.4392324632
    -#> Cell1701   5.709353901  0.8791294   Mutant  1.2544603189
    -#> Cell801   -8.605063906  0.7918662       WT -1.9221319435
    -#> Cell508   -1.324912319  0.8362473       WT -0.3065529161
    -#> Cell956   -6.024846252  0.8075957       WT -1.3495414587
    -#> Cell1705   5.468638316  0.8776620   Mutant  1.2010417814
    -#> Cell543   -3.521890162  0.8228541       WT -0.7940965179
    -#> Cell1009   3.415879802  0.8651480   Mutant  0.7455026949
    -#> Cell1096   8.955393404  0.8989178   Mutant  1.9748070425
    -#> Cell1061   1.054412718  0.8507521   Mutant  0.2214563684
    -#> Cell1479   3.519981229  0.8657826   Mutant  0.7686044228
    -#> Cell962   -1.098184060  0.8376295       WT -0.2562383840
    -#> Cell1741   3.331637954  0.8646344   Mutant  0.7268081167
    -#> Cell1897   2.161410831  0.8575005   Mutant  0.4671164914
    -#> Cell1620   0.267738847  0.8459564   Mutant  0.0468811837
    -#> Cell834   -3.667926777  0.8219639       WT -0.8265043174
    -#> Cell485   -5.101009901  0.8132275       WT -1.1445277833
    -#> Cell1673   1.439939092  0.8531023   Mutant  0.3070106754
    -#> Cell468   -9.778891135  0.7847104       WT -2.1826224883
    -#> Cell778   -2.628158275  0.8283025       WT -0.5957634922
    -#> Cell353  -10.835053614  0.7782718       WT -2.4170013925
    -#> Cell565   -1.012065142  0.8381545       WT -0.2371272548
    -#> Cell1738   5.516290041  0.8779525   Mutant  1.2116164414
    -#> Cell91    -6.143080660  0.8068749       WT -1.3757795152
    -#> Cell1185   3.646979025  0.8665568   Mutant  0.7967872119
    -#> Cell1668   4.751542325  0.8732904   Mutant  1.0419070119
    -#> Cell134   -2.864676052  0.8268606       WT -0.6482504707
    -#> Cell691   -5.382384691  0.8115122       WT -1.2069692317
    -#> Cell1733   2.251957209  0.8580525   Mutant  0.4872101429
    -#> Cell327   -4.066606863  0.8195334       WT -0.9149776381
    -#> Cell221   -5.022717035  0.8137048       WT -1.1271533769
    -#> Cell1656   2.655234970  0.8605110   Mutant  0.5767037593
    -#> Cell1671   4.161647504  0.8696943   Mutant  0.9110001635
    -#> Cell769   -2.294245579  0.8303381       WT -0.5216630641
    -#> Cell1145   1.761428015  0.8550622   Mutant  0.3783540747
    -#> Cell808    3.138942580  0.8634597       WT  0.6840460120
    -#> Cell1189   5.023361868  0.8749475   Mutant  1.1022280022
    -#> Cell1524   7.513489287  0.8901277   Mutant  1.6548260610
    -#> Cell837   -1.144457019  0.8373474       WT -0.2665070744
    -#> Cell1002   4.523968849  0.8719031   Mutant  0.9914049131
    -#> Cell1467   3.706974866  0.8669225   Mutant  0.8101012233
    -#> Cell1279   4.008096495  0.8687582   Mutant  0.8769248029
    -#> Cell581   -1.386549216  0.8358715       WT -0.3202311034
    -#> Cell613   -6.936688074  0.8020369       WT -1.5518933612
    -#> Cell1667   4.530619740  0.8719436   Mutant  0.9928808494
    -#> Cell1459   2.910312012  0.8620660   Mutant  0.6333093277
    -#> Cell196   -5.580251109  0.8103060       WT -1.2508788716
    -#> Cell1381   5.509834329  0.8779131   Mutant  1.2101838182
    -#> Cell1622   6.550178148  0.8842552   Mutant  1.4410523154
    -#> Cell1983   6.504760982  0.8839783   Mutant  1.4309735388
    -#> Cell1894   3.336180928  0.8646621   Mutant  0.7278162733
    -#> Cell1405   3.858294669  0.8678450   Mutant  0.8436814445
    -#> Cell1604   4.217865401  0.8700370   Mutant  0.9234757903
    -#> Cell814   -7.718217741  0.7972726       WT -1.7253269666
    -#> Cell455   -1.473736434  0.8353400       WT -0.3395793051
    -#> Cell1612   3.825034723  0.8676423   Mutant  0.8363005444
    -#> Cell1089   4.416587184  0.8712485   Mutant  0.9675752491
    -#> Cell542   -4.100632256  0.8193260       WT -0.9225284026
    -#> Cell1010   2.789917517  0.8613320   Mutant  0.6065919142
    -#> Cell1122   2.808428978  0.8614449   Mutant  0.6106998958
    -#> Cell1813   8.061320187  0.8934674   Mutant  1.7763982702
    -#> Cell1651   3.300398615  0.8644440   Mutant  0.7198756207
    -#> Cell736   -3.452738591  0.8232757       WT -0.7787507073
    -#> Cell163    0.984616558  0.8503266       WT  0.2059675133
    -#> Cell1521   3.146338992  0.8635048   Mutant  0.6856873909
    -#> Cell936   -3.497309559  0.8230040       WT -0.7886416993
    -#> Cell1436   3.045642779  0.8628910   Mutant  0.6633413327
    -#> Cell306   -1.653313931  0.8342453       WT -0.3794303486
    -#> Cell48    -2.005105615  0.8321007       WT -0.4574984027
    -#> Cell597    0.287790289  0.8460786       WT  0.0513309111
    -#> Cell1949   5.004020526  0.8748296   Mutant  1.0979358572
    -#> Cell1021   4.769793259  0.8734017   Mutant  1.0459571786
    -#> Cell9     -0.883859935  0.8389360       WT -0.2086765226
    -#> Cell1688   3.246616189  0.8641161   Mutant  0.7079404628
    -#> Cell478    5.231595783  0.8762169       WT  1.1484383513
    -#> Cell908   -7.641382454  0.7977410       WT -1.7082760197
    -#> Cell998   -3.556226529  0.8226448       WT -0.8017162925
    -#> Cell1964   5.282284322  0.8765259   Mutant  1.1596869275
    -#> Cell344   -5.460695917  0.8110348       WT -1.2243477125
    -#> Cell1595   2.197875700  0.8577228   Mutant  0.4752086138
    -#> Cell423    0.817789660  0.8493096       WT  0.1689460264
    -#> Cell1598  10.613845114  0.9090280   Mutant  2.3428433079
    -#> Cell1603   5.001504010  0.8748142   Mutant  1.0973774031
    -#> Cell1832   5.534667547  0.8780645   Mutant  1.2156946960
    -#> Cell1298   1.949619488  0.8562094   Mutant  0.4201166936
    -#> Cell1116   2.366846100  0.8587529   Mutant  0.5127057773
    -#> Cell68    -7.757721249  0.7970318       WT -1.7340934105
    -#> Cell1728   6.403440311  0.8833607   Mutant  1.4084889037
    -#> Cell1695   6.045113983  0.8811763   Mutant  1.3289707106
    -#> Cell1183   3.660341044  0.8666383   Mutant  0.7997524519
    -#> Cell1623   4.864560139  0.8739794   Mutant  1.0669874252
    -#> Cell972    0.187652888  0.8454681       WT  0.0291088621
    -#> Cell331   -7.465588627  0.7988126       WT -1.6692646316
    -#> Cell1109   8.857410626  0.8983205   Mutant  1.9530631379
    -#> Cell243   -2.878180266  0.8267783       WT -0.6512472660
    -#> Cell1951   2.112293398  0.8572011   Mutant  0.4562165680
    -#> Cell1393   5.596570440  0.8784419   Mutant  1.2294319123
    -#> Cell311   -2.019316321  0.8320141       WT -0.4606519796
    -#> Cell604   -1.655241218  0.8342335       WT -0.3798580438
    -#> Cell1734   2.247682808  0.8580264   Mutant  0.4862615868
    -#> Cell1440   3.031404651  0.8628042   Mutant  0.6601816705
    -#> Cell1558   5.255200961  0.8763608   Mutant  1.1536767080
    -#> Cell1582   3.733589916  0.8670848   Mutant  0.8160075175
    -#> Cell1588   3.693784729  0.8668421   Mutant  0.8071741265
    -#> Cell381    0.812361309  0.8492765       WT  0.1677413906
    -#> Cell566   -4.678835899  0.8158012       WT -1.0508407967
    -#> Cell1172   2.695875385  0.8607587   Mutant  0.5857225003
    -#> Cell938   -3.253830408  0.8244883       WT -0.7346098834
    -#> Cell1163   4.807844183  0.8736336   Mutant  1.0544012713
    -#> Cell939   -2.964059105  0.8262548       WT -0.6703051180
    -#> Cell1217   0.459142721  0.8471232   Mutant  0.0893566846
    -#> Cell25    -2.278223762  0.8304357       WT -0.5181075733
    -#> Cell1045  -1.481385467  0.8352934   Mutant -0.3412767446
    -#> Cell1170   5.846668464  0.8799665   Mutant  1.2849325592
    -#> Cell72    -2.631285678  0.8282834       WT -0.5964575115
    -#> Cell1729   1.053435876  0.8507461   Mutant  0.2212395918
    -#> Cell474   -7.600605343  0.7979896       WT -1.6992269437
    -#> Cell1453   6.930854651  0.8865759   Mutant  1.5255303605
    -#> Cell762   -8.678230809  0.7914202       WT -1.9383688190
    -#> Cell1512   4.714015627  0.8730616   Mutant  1.0335792531
    -#> Cell1536   2.599281238  0.8601699   Mutant  0.5642867547
    -#> Cell1921   5.258277967  0.8763796   Mutant  1.1543595435
    -#> Cell1725   4.684972679  0.8728846   Mutant  1.0271341707
    -#> Cell1757   4.887216244  0.8741175   Mutant  1.0720151677
    -#> Cell184   -5.738339839  0.8093423       WT -1.2859612232
    -#> Cell646   -5.856346761  0.8086229       WT -1.3121487972
    -#> Cell1123   6.083251283  0.8814087   Mutant  1.3374339715
    -#> Cell1250   1.929086990  0.8560842   Mutant  0.4155602127
    -#> Cell391   -2.187684787  0.8309877       WT -0.4980155646
    -#> Cell1821   0.509682132  0.8474313   Mutant  0.1005721671
    -#> Cell1288   7.200560526  0.8882201   Mutant  1.5853822949
    -#> Cell1260   2.323416464  0.8584881   Mutant  0.5030680648
    -#> Cell1567   4.235475170  0.8701444   Mutant  0.9273836724
    -#> Cell1513   2.163585874  0.8575138   Mutant  0.4675991673
    -#> Cell1650   6.068290008  0.8813175   Mutant  1.3341138315
    -#> Cell1626   3.863855419  0.8678789   Mutant  0.8449154617
    -#> Cell364   -3.557349073  0.8226380       WT -0.8019654025
    -#> Cell1761   2.378837740  0.8588260   Mutant  0.5153669090
    -#> Cell289   -3.440122872  0.8233526       WT -0.7759510828
    -#> Cell1196   1.443415506  0.8531235   Mutant  0.3077821457
    -#> Cell924    0.819752900  0.8493215       WT  0.1693816999
    -#> Cell1485   6.179335420  0.8819945   Mutant  1.3587565380
    -#> Cell524   -1.781798056  0.8334620       WT -0.4079429771
    -#> Cell1569   4.048763896  0.8690062   Mutant  0.8859495327
    -#> Cell1605   3.501325834  0.8656689   Mutant  0.7644645002
    -#> Cell722   -6.643534474  0.8038240       WT -1.4868380113
    -#> Cell332    0.575468095  0.8478323       WT  0.1151710968
    -#> Cell1390   5.618155426  0.8785734   Mutant  1.2342219569
    -#> Cell408   -5.784621645  0.8090601       WT -1.2962318768
    -#> Cell1367   5.942578847  0.8805512   Mutant  1.3062165669
    -#> Cell841   -4.193895017  0.8187575       WT -0.9432248619
    -#> Cell1285   2.182493505  0.8576290   Mutant  0.4717950652
    -#> Cell1385   4.675322405  0.8728258   Mutant  1.0249926247
    -#> Cell1379   2.306977356  0.8583879   Mutant  0.4994199705
    -#> Cell656   -0.256014899  0.8427635       WT -0.0693479301
    -#> Cell672   -5.776461193  0.8091099       WT -1.2944209454
    -#> Cell517   -2.511700193  0.8290124       WT -0.5699196299
    -#> Cell109   -2.055887381  0.8317911       WT -0.4687676674
    -#> Cell875   -5.022786907  0.8137044       WT -1.1271688825
    -#> Cell1638   3.724671257  0.8670304   Mutant  0.8140283282
    -#> Cell26    -1.347845310  0.8361075       WT -0.3116421039
    -#> Cell390   -5.048260481  0.8135491       WT -1.1328218654
    -#> Cell798   -5.282588541  0.8121206       WT -1.1848229115
    -#> Cell1422   1.957907393  0.8562599   Mutant  0.4219559089
    -#> Cell541   -1.570781983  0.8347484       WT -0.3611152240
    -#> Cell1308   1.752834071  0.8550098   Mutant  0.3764469447
    -#> Cell457   -4.922316496  0.8143169       WT -1.1048729336
    -#> Cell958   -5.000886103  0.8138379       WT -1.1223087529
    -#> Cell620  -13.801596599  0.7601872       WT -3.0753234856
    -#> Cell192   -6.907141691  0.8022170       WT -1.5453365586
    -#> Cell1976   4.420621073  0.8712731   Mutant  0.9684704321
    -#> Cell1901   2.630159582  0.8603581   Mutant  0.5711391402
    -#> Cell598   -3.115142716  0.8253337       WT -0.7038329244
    -#> Cell1544   3.996915000  0.8686901   Mutant  0.8744434549
    -#> Cell1286   6.978705101  0.8868676   Mutant  1.5361491206
    -#> Cell442    0.811831819  0.8492733       WT  0.1676238886
    -#> Cell547    0.077313218  0.8447955       WT  0.0046227707
    -#> Cell905   -1.965606373  0.8323415       WT -0.4487329057
    -#> Cell618   -6.033430226  0.8075433       WT -1.3514463760
    -#> Cell175   -2.311414024  0.8302334       WT -0.5254730095
    -#> Cell1266   1.707764027  0.8547350   Mutant  0.3664451999
    -#> Cell199   -1.413353958  0.8357081       WT -0.3261794932
    -#> Cell1961   4.397946985  0.8711348   Mutant  0.9634386986
    -#> Cell1965   2.819974751  0.8615152   Mutant  0.6132620825
    -#> Cell226   -4.693816739  0.8157099       WT -1.0541652784
    -#> Cell970  -12.202279212  0.7699370       WT -2.7204100476
    -#> Cell944    0.834301696  0.8494102       WT  0.1726103042
    -#> Cell1597   3.834620171  0.8677007   Mutant  0.8384277046
    -#> Cell1824   3.844375953  0.8677602   Mutant  0.8405926647
    -#> Cell1493  14.096638401  0.9302598   Mutant  3.1157293838
    -#> Cell1218   3.214863249  0.8639226   Mutant  0.7008939909
    -#> Cell1337   2.883115931  0.8619002   Mutant  0.6272740939
    -#> Cell1852   1.458071253  0.8532128   Mutant  0.3110344844
    -#> Cell720   -3.251843285  0.8245004       WT -0.7341689098
    -#> Cell1413   4.485220975  0.8716669   Mutant  0.9828061563
    -#> Cell268  -11.526484033  0.7740567       WT -2.5704405717
    -#> Cell639   -4.620982153  0.8161539       WT -1.0380021495
    -#> Cell297   -4.806658438  0.8150220       WT -1.0792066089
    -#> Cell1418   5.178101268  0.8758908   Mutant  1.1365670852
    -#> Cell1714   7.859776280  0.8922388   Mutant  1.7316725382
    -#> Cell1887   3.564310784  0.8660528   Mutant  0.7784418415
    -#> Cell856   -5.914378561  0.8082691       WT -1.3250269573
    -#> Cell1237   3.100347535  0.8632244   Mutant  0.6754811703
    -#> Cell755   -4.475971984  0.8170379       WT -1.0058221343
    -#> Cell1205   4.906683334  0.8742362   Mutant  1.0763352182
    -#> Cell1136   2.629879377  0.8603564   Mutant  0.5710769584
    -#> Cell362    1.725328474  0.8548421       WT  0.3703430243
    -#> Cell320   -0.930279935  0.8386530       WT -0.2189778436
    -#> Cell835   -6.185537553  0.8066161       WT -1.3852013610
    -#> Cell1817   2.473187320  0.8594012   Mutant  0.5363045504
    -#> Cell1827   1.750728100  0.8549969   Mutant  0.3759795970
    -#> Cell650   -6.759905272  0.8031146       WT -1.5126625038
    -#> Cell1209   3.433912618  0.8652579   Mutant  0.7495044576
    -#> Cell804    1.329238900  0.8524275       WT  0.2824445787
    -#> Cell1321   5.487961564  0.8777798   Mutant  1.2053299110
    -#> Cell816   -2.035782346  0.8319137       WT -0.4643060471
    -#> Cell93    -1.680101026  0.8340820       WT -0.3853748222
    -#> Cell396   -3.655224536  0.8220413       WT -0.8236854923
    -#> Cell1762   2.058807337  0.8568750   Mutant  0.4443471780
    -#> Cell1014   3.840937531  0.8677392   Mutant  0.8398296252
    -#> Cell1781   0.788931529  0.8491336   Mutant  0.1625419576
    -#> Cell1207   4.214877358  0.8700188   Mutant  0.9228126971
    -#> Cell1158   1.812324292  0.8553724   Mutant  0.3896487514
    -#> Cell887   -2.846890977  0.8269690       WT -0.6443036856
    -#> Cell1450   3.102891602  0.8632400   Mutant  0.6760457384
    -#> Cell898   -2.657024434  0.8281265       WT -0.6021693424
    -#> Cell236   -2.320016634  0.8301810       WT -0.5273820626
    -#> Cell1008   4.445477052  0.8714246   Mutant  0.9739863608
    -#> Cell1795   3.638052494  0.8665024   Mutant  0.7948062755
    -#> Cell1201   4.967158121  0.8746048   Mutant  1.0897555154
    -#> Cell36     1.710862461  0.8547539       WT  0.3671327907
    -#> Cell42    -7.133920224  0.8008346       WT -1.5956622470
    -#> Cell1164   2.663221087  0.8605596   Mutant  0.5784760030
    -#> Cell619   -1.084055693  0.8377156       WT -0.2531030793
    -#> Cell279   -5.463196977  0.8110196       WT -1.2249027365
    -#> Cell316   -3.112156062  0.8253519       WT -0.7031701394
    -#> Cell451   -1.675321799  0.8341111       WT -0.3843142374
    -#> Cell1063   0.077403733  0.8447960   Mutant  0.0046428574
    -#> Cell1862   5.076201644  0.8752696   Mutant  1.1139539716
    -#> Cell765   -4.497114731  0.8169090       WT -1.0105140392
    -#> Cell1675   5.536262560  0.8780742   Mutant  1.2160486544
    -#> Cell694    1.443714899  0.8531253       WT  0.3078485857
    -#> Cell1085   5.519275754  0.8779707   Mutant  1.2122790176
    -#> Cell860   -3.278277485  0.8243392       WT -0.7400350706
    -#> Cell1732   7.582570032  0.8905489   Mutant  1.6701561542
    -#> Cell1128   5.978390237  0.8807695   Mutant  1.3141636722
    -#> Cell167   -4.038964895  0.8197019       WT -0.9088434548
    -#> Cell974   -2.371104049  0.8298695       WT -0.5387191557
    -#> Cell126   -1.729902781  0.8337784       WT -0.3964266073
    -#> Cell317   -7.354865111  0.7994876       WT -1.6446933588
    -#> Cell873   -1.445274384  0.8355135       WT -0.3332631328
    -#> Cell1313  -1.398594485  0.8357981   Mutant -0.3229041363
    -#> Cell1580   2.893457186  0.8619632   Mutant  0.6295689794
    -#> Cell957   -4.127493295  0.8191623       WT -0.9284892857
    -#> Cell568   -4.627982200  0.8161112       WT -1.0395555689
    -#> Cell494   -1.026004705  0.8380695       WT -0.2402206609
    -#> Cell1099   1.345222571  0.8525249   Mutant  0.2859916041
    -#> Cell14    -0.496625249  0.8412967       WT -0.1227431145
    -#> Cell1110   2.231036958  0.8579250   Mutant  0.4825676134
    -#> Cell1169   4.488091070  0.8716844   Mutant  0.9834430752
    -#> Cell1557   3.964399007  0.8684919   Mutant  0.8672276498
    -#> Cell839   -7.451147539  0.7989007       WT -1.6660599292
    -#> Cell577   -4.648033417  0.8159890       WT -1.0440052463
    -#> Cell1267   0.497422597  0.8473566   Mutant  0.0978515853
    -#> Cell375   -3.199803855  0.8248176       WT -0.7226205498
    -#> Cell1469   5.711182483  0.8791405   Mutant  1.2548661096
    -#> Cell673   -5.718998948  0.8094602       WT -1.2816691782
    -#> Cell482   -1.688151293  0.8340329       WT -0.3871613020
    -#> Cell139   -1.223009512  0.8368685       WT -0.2839390960
    -#> Cell615   -4.386850676  0.8175812       WT -0.9860447280
    -#> Cell617   -1.178983297  0.8371369       WT -0.2741689932
    -#> Cell1678   1.040850617  0.8506694   Mutant  0.2184467268
    -#> Cell1809   4.959103676  0.8745557   Mutant  1.0879681085
    -#> Cell1606   3.894338306  0.8680647   Mutant  0.8516800890
    -#> Cell1190   3.784759071  0.8673967   Mutant  0.8273627501
    -#> Cell1047   0.747154077  0.8488790   Mutant  0.1532708902
    -#> Cell1560   2.120105028  0.8572487   Mutant  0.4579500905
    -#> Cell1033  10.793850256  0.9101254   Mutant  2.3827892525
    -#> Cell583   -4.992521381  0.8138889       WT -1.1204524909
    -#> Cell1320   4.232162975  0.8701242   Mutant  0.9266486448
    -#> Cell1920   2.417014883  0.8590587   Mutant  0.5238390117
    -#> Cell761   -6.027181391  0.8075814       WT -1.3500596622
    -#> Cell288   -3.839365603  0.8209187       WT -0.8645492631
    -#> Cell560   -2.784769655  0.8273477       WT -0.6305179967
    -#> Cell1178   2.457754058  0.8593071   Mutant  0.5328796691
    -#> Cell1300   1.603117135  0.8540971   Mutant  0.3432224248
    -#> Cell504   -4.652896716  0.8159593       WT -1.0450844880
    -#> Cell789   -1.475443025  0.8353296       WT -0.3399580243
    -#> Cell1806   2.120350479  0.8572502   Mutant  0.4580045598
    -#> Cell374   -1.988832941  0.8321999       WT -0.4538872429
    -#> Cell1211   3.809431453  0.8675471   Mutant  0.8328379358
    -#> Cell1669   0.952069157  0.8501282   Mutant  0.1987447382
    -#> Cell784    1.270151186  0.8520672       WT  0.2693320947
    -#> Cell1525   4.976566723  0.8746622   Mutant  1.0918434308
    -#> Cell1443   3.178557493  0.8637012   Mutant  0.6928371780
    -#> Cell575   -1.013407473  0.8381463       WT -0.2374251389
    -#> Cell823   -4.865908431  0.8146608       WT -1.0923551053
    -#> Cell1822   2.617659532  0.8602819   Mutant  0.5683651844
    -#> Cell959   -1.348652497  0.8361026       WT -0.3118212312
    -#> Cell521   -1.040847213  0.8379790       WT -0.2435144446
    -#> Cell1324   3.896960969  0.8680807   Mutant  0.8522620987
    -#> Cell880  -15.510186148  0.7497714       WT -3.4544861185
    -#> Cell1784   4.624068630  0.8725133   Mutant  1.0136186136
    -#> Cell1715   1.125425269  0.8511850   Mutant  0.2372151594
    -#> Cell1383   5.131597576  0.8756073   Mutant  1.1262471915
    -#> Cell1923   3.849343260  0.8677905   Mutant  0.8416949875
    -#> Cell1295   4.433528547  0.8713517   Mutant  0.9713348014
    -#> Cell1484   1.537295209  0.8536958   Mutant  0.3286155140
    -#> Cell475   -5.108410771  0.8131824       WT -1.1461701516
    -#> Cell1886   3.725249632  0.8670340   Mutant  0.8141566787
    -#> Cell1881   2.162977985  0.8575101   Mutant  0.4674642673
    -#> Cell169   -2.921309701  0.8265154       WT -0.6608183595
    -#> Cell136   -3.074668000  0.8255805       WT -0.6948509546
    -#> Cell76    -6.437923832  0.8050775       WT -1.4412098074
    -#> Cell1823   4.315765974  0.8706338   Mutant  0.9452014524
    -#> Cell334   -5.946781369  0.8080716       WT -1.3322176452
    -#> Cell1100   1.667307923  0.8544884   Mutant  0.3574673604
    -#> Cell849   -6.875966530  0.8024071       WT -1.5384183046
    -#> Cell41    -5.962514186  0.8079757       WT -1.3357090023
    -#> Cell1458   0.613450696  0.8480639   Mutant  0.1236000275
    -#> Cell127    1.009587802  0.8504788       WT  0.2115090214
    -#> Cell963   -3.722376974  0.8216319       WT -0.8385876641
    -#> Cell996   -0.056950543  0.8439770       WT -0.0251724491
    -#> Cell218   -4.935780384  0.8142348       WT -1.1078607799
    -#> Cell911   -4.425448208  0.8173459       WT -0.9946101214
    -#> Cell764   -2.943014520  0.8263831       WT -0.6656349969
    -#> Cell1093   3.998314337  0.8686986   Mutant  0.8747539896
    -#> Cell1305   3.799995113  0.8674896   Mutant  0.8307438651
    -#> Cell661   -2.563705039  0.8286954       WT -0.5814603151
    -#> Cell462   -6.449408812  0.8050075       WT -1.4437585033
    -#> Cell1932   7.419869375  0.8895570   Mutant  1.6340503443
    -#> Cell1660   2.148319967  0.8574207   Mutant  0.4642114247
    -#> Cell1052   2.397818122  0.8589417   Mutant  0.5195789514
    -#> Cell1072  15.747224286  0.9403220   Mutant  3.4820201001
    -#> Cell1601   2.797245540  0.8613767   Mutant  0.6082181167
    -#> Cell806   -2.508081312  0.8290345       WT -0.5691165437
    -#> Cell188   -0.300440558  0.8424926       WT -0.0792066759
    -#> Cell601   -3.824720192  0.8210080       WT -0.8612992184
    -#> Cell1672   2.969972318  0.8624297   Mutant  0.6465488790
    -#> Cell1332   3.549073549  0.8659600   Mutant  0.7750604618
    -#> Cell421   -5.784453031  0.8090611       WT -1.2961944586
    -#> Cell1803   4.827867243  0.8737557   Mutant  1.0588447001
    -#> Cell177   -5.459927684  0.8110395       WT -1.2241772296
    -#> Cell1386   1.636956594  0.8543034   Mutant  0.3507319277
    -#> Cell1530   1.902498670  0.8559221   Mutant  0.4096598502
    -#> Cell24    -4.355617872  0.8177716       WT -0.9791136823
    -#> Cell1819   3.406465395  0.8650906   Mutant  0.7434134913
    -#> Cell1999   4.324124222  0.8706848   Mutant  0.9470562779
    -#> Cell1617   1.782221069  0.8551889   Mutant  0.3829683772
    -#> Cell1753   4.307346274  0.8705825   Mutant  0.9433329897
    -#> Cell1212   3.329496904  0.8646214   Mutant  0.7263329844
    -#> Cell1073   3.191202763  0.8637783   Mutant  0.6956433604
    -#> Cell1831   4.375984709  0.8710010   Mutant  0.9585649277
    -#> Cell1309   1.008636574  0.8504730   Mutant  0.2112979289
    -#> Cell1432   3.135758455  0.8634403   Mutant  0.6833394050
    -#> Cell553   -3.467408858  0.8231863       WT -0.7820062680
    -#> Cell1319  -0.162075334  0.8433361   Mutant -0.0485012776
    -#> Cell1866   2.761910198  0.8611613   Mutant  0.6003766539
    -#> Cell986   -1.910366233  0.8326783       WT -0.4364742583
    -#> Cell928   -2.648884290  0.8281761       WT -0.6003629177
    -#> Cell950   -3.879478211  0.8206742       WT -0.8734508756
    -#> Cell1933   2.140840025  0.8573751   Mutant  0.4625515092
    -#> Cell1229   3.527792694  0.8658302   Mutant  0.7703379087
    -#> Cell58    -1.972284790  0.8323008       WT -0.4502149504
    -#> Cell15     0.790491100  0.8491432       WT  0.1628880506
    -#> Cell812   -4.116034286  0.8192321       WT -0.9259463530
    -#> Cell948   -2.735137070  0.8276503       WT -0.6195037530
    -#> Cell667   -5.035387417  0.8136276       WT -1.1299651320
    -#> Cell87     0.144387676  0.8452044       WT  0.0195076376
    -#> Cell1176   4.157537450  0.8696693   Mutant  0.9100880784
    -#> Cell855   -2.597147769  0.8284915       WT -0.5888817779
    -#> Cell1548   2.498212906  0.8595537   Mutant  0.5418581176
    -#> Cell886   -2.352135770  0.8299852       WT -0.5345097991
    -#> Cell1882   2.492004873  0.8595159   Mutant  0.5404804583
    -#> Cell1079   2.395341874  0.8589266   Mutant  0.5190294334
    -#> Cell842   -5.304537908  0.8119868       WT -1.1896938181
    -#> Cell1553   6.111333870  0.8815799   Mutant  1.3436659350
    -#> Cell1411   6.102750848  0.8815276   Mutant  1.3417612287
    -#> Cell272   -5.144374935  0.8129632       WT -1.1541511597
    -#> Cell437   -1.963355810  0.8323552       WT -0.4482334707
    -#> Cell1480   2.820251338  0.8615169   Mutant  0.6133234615
    -#> Cell1449   2.973986699  0.8624541   Mutant  0.6474397326
    -#> Cell760   -1.197136099  0.8370262       WT -0.2781973826
    -#> Cell222   -2.560759207  0.8287133       WT -0.5808065892
    -#> Cell858   -0.214524061  0.8430164       WT -0.0601404670
    -#> Cell684   -4.317017162  0.8180069       WT -0.9705475836
    -#> Cell913   -4.612035395  0.8162084       WT -1.0360167244
    -#> Cell654    0.237775381  0.8457737       WT  0.0402318239
    -#> Cell1643   5.427486383  0.8774111   Mutant  1.1919095264
    -#> Cell505    0.665707959  0.8483825       WT  0.1351967281
    -#> Cell1025   2.697772608  0.8607703   Mutant  0.5861435237
    -#> Cell434   -9.784708677  0.7846749       WT -2.1839134916
    -#> Cell750   -3.388674265  0.8236662       WT -0.7645338356
    -#> Cell1969   2.163835692  0.8575153   Mutant  0.4676546059
    -#> Cell713    0.816841445  0.8493038       WT  0.1687356026
    -#> Cell1130   3.194021228  0.8637955   Mutant  0.6962688218
    -#> Cell1392   5.742891403  0.8793339   Mutant  1.2619028129
    -#> Cell113   -4.088663388  0.8193990       WT -0.9198723244
    -#> Cell961   -2.209399972  0.8308553       WT -0.5028345024
    -#> Cell810   -5.558811033  0.8104367       WT -1.2461209848
    -#> Cell1849   5.286355061  0.8765507   Mutant  1.1605902879
    -#> Cell1518   3.334957360  0.8646547   Mutant  0.7275447446
    -#> Cell1358   7.441886976  0.8896912   Mutant  1.6389363928
    -#> Cell152   -2.332458003  0.8301051       WT -0.5301429961
    -#> Cell359   -1.650923338  0.8342599       WT -0.3788998390
    -#> Cell440   -0.362972388  0.8421114       WT -0.0930834628
    -#> Cell1624   3.008374230  0.8626638   Mutant  0.6550708613
    -#> Cell1875   5.073292155  0.8752519   Mutant  1.1133083106
    -#> Cell1501   0.629858212  0.8481639   Mutant  0.1272411108
    -#> Cell506    1.828282208  0.8554697       WT  0.3931900614
    -#> Cell260   -2.855632936  0.8269157       WT -0.6462436623
    -#> Cell878   -1.618420692  0.8344580       WT -0.3716869956
    -#> Cell1919   3.676085523  0.8667342   Mutant  0.8032463971
    -#> Cell278   -4.518570696  0.8167782       WT -1.0152754521
    -#> Cell256   -5.303474373  0.8119933       WT -1.1894578031
    -#> Cell217   -3.335876716  0.8239881       WT -0.7528172370
    -#> Cell1070   2.428662870  0.8591297   Mutant  0.5264238814
    -#> Cell1135   2.600026552  0.8601744   Mutant  0.5644521515
    -#> Cell1878   6.958891308  0.8867468   Mutant  1.5317521314
    -#> Cell1426   4.946295709  0.8744777   Mutant  1.0851258212
    -#> Cell73    -1.517182046  0.8350752       WT -0.3492205632
    -#> Cell1883   3.057634440  0.8629641   Mutant  0.6660024693
    -#> Cell830   -5.134258693  0.8130248       WT -1.1519062081
    -#> Cell98     0.014714916  0.8444139       WT -0.0092687676
    -#> Cell1372   4.379911848  0.8710249   Mutant  0.9594364209
    -#> Cell1744   6.303191279  0.8827495   Mutant  1.3862420822
    -#> Cell557   -4.548873392  0.8165935       WT -1.0220000922
    -#> Cell1532   6.069628736  0.8813257   Mutant  1.3344109160
    -#> Cell1815   3.054876067  0.8629472   Mutant  0.6653903432
    -#> Cell465   -1.420364837  0.8356654       WT -0.3277353164
    -#> Cell1112   3.980903399  0.8685925   Mutant  0.8708902314
    -#> Cell578    2.813923248  0.8614784       WT  0.6119191598
    -#> Cell1451   5.470021379  0.8776704   Mutant  1.2013487045
    -#> Cell677   -1.701957714  0.8339487       WT -0.3902251617
    -#> Cell275   -9.659974714  0.7854353       WT -2.1562330825
    -#> Cell1607  -2.116325795  0.8314227   Mutant -0.4821798928
    -#> Cell65    -5.238278391  0.8123907       WT -1.1749897992
    -#> Cell265  -14.088440045  0.7584386       WT -3.1389785140
    -#> Cell528    0.550461288  0.8476799       WT  0.1096216968
    -#> Cell609   -5.921293409  0.8082269       WT -1.3265614699
    -#> Cell1507   3.327981014  0.8646121   Mutant  0.7259965848
    -#> Cell624   -8.942327993  0.7898102       WT -1.9969760975
    -#> Cell458   -3.216937946  0.8247132       WT -0.7264228716
    -#> Cell1681   5.007296675  0.8748495   Mutant  1.0986628858
    -#> Cell1993   3.835135042  0.8677038   Mutant  0.8385419626
    -#> Cell803   -5.202823848  0.8126069       WT -1.1671218840
    -#> Cell665   -1.995467644  0.8321595       WT -0.4553595868
    -#> Cell1830  -2.443915095  0.8294256   Mutant -0.5548770608
    -#> Cell532   -4.282955264  0.8182145       WT -0.9629887179
    -#> Cell644   -2.377470676  0.8298307       WT -0.5401320093
    -#> Cell1490   2.941128296  0.8622538   Mutant  0.6401479413
    -#> Cell990   -0.189122168  0.8431713       WT -0.0545033913
    -#> Cell1448   5.351288790  0.8769466   Mutant  1.1750000937
    -#> Cell1931   4.178638112  0.8697979   Mutant  0.9147706441
    -#> Cell1665   3.382918223  0.8649470   Mutant  0.7381880071
    -#> Cell1736   3.700279139  0.8668817   Mutant  0.8086153372
    -#> Cell208   -4.474562235  0.8170465       WT -1.0055092891
    -#> Cell758   -4.774790460  0.8152162       WT -1.0721346084
    -#> Cell227   -2.399824132  0.8296944       WT -0.5450925893
    -#> Cell781   -5.581493741  0.8102984       WT -1.2511546311
    -#> Cell1456   2.282546644  0.8582390   Mutant  0.4939984150
    -#> Cell1111   4.923235536  0.8743371   Mutant  1.0800084096
    -#> Cell1454   0.802827364  0.8492184   Mutant  0.1656256599
    -#> Cell57    -2.356628169  0.8299578       WT -0.5355067324
    -#> Cell1925   0.765863398  0.8489930   Mutant  0.1574227801
    -#> Cell180   -3.723327590  0.8216261       WT -0.8387986208
    -#> Cell1213   2.961676237  0.8623791   Mutant  0.6447078493
    -#> Cell360   -7.501587108  0.7985932       WT -1.6772532551
    -#> Cell1388   0.625634345  0.8481382   Mutant  0.1263037691
    -#> Cell968   -2.321066475  0.8301746       WT -0.5276150386
    -#> Cell149   -5.999438736  0.8077506       WT -1.3439031351
    -#> Cell449   -0.757431426  0.8397067       WT -0.1806200672
    -#> Cell1654   4.096880894  0.8692995   Mutant  0.8966274439
    -#> Cell1596   5.547733595  0.8781441   Mutant  1.2185942556
    -#> Cell407   -3.318486856  0.8240941       WT -0.7489581563
    -#> Cell1546   0.687352108  0.8485144   Mutant  0.1399999018
    -#> Cell1228   2.017229935  0.8566216   Mutant  0.4351205050
    -#> Cell1333   4.421323140  0.8712773   Mutant  0.9686262315
    -#> Cell1397   3.394335072  0.8650166   Mutant  0.7407215836
    -#> Cell931   -2.394115707  0.8297292       WT -0.5438258010
    -#> Cell492   -1.099543252  0.8376212       WT -0.2565400098
    -#> Cell1756   4.106705793  0.8693594   Mutant  0.8988077420
    -#> Cell710   -3.247728361  0.8245255       WT -0.7332557441
    -#> Cell135   -5.059854560  0.8134784       WT -1.1353947721
    -#> Cell1579   3.487951555  0.8655873   Mutant  0.7614965393
    -#> Cell1255   2.319424067  0.8584638   Mutant  0.5021820897
    -#> Cell1908   1.557930541  0.8538216   Mutant  0.3331948157
    -#> Cell1786   2.360793074  0.8587160   Mutant  0.5113625165
    -#> Cell481   -5.465691452  0.8110044       WT -1.2254562994
    -#> Cell173   -7.446718328  0.7989277       WT -1.6650770183
    -#> Cell74    -2.644633934  0.8282020       WT -0.5994196975
    -#> Cell1783   3.091339058  0.8631695   Mutant  0.6734820489
    -#> Cell1441   4.315746868  0.8706337   Mutant  0.9451972124
    -#> Cell1287   3.720360688  0.8670042   Mutant  0.8130717459
    -#> Cell1566   1.259519558  0.8520024   Mutant  0.2669727707
    -#> Cell122   -6.903038346  0.8022421       WT -1.5444259623
    -#> Cell1077   3.144717975  0.8634949   Mutant  0.6853276620
    -#> Cell469   -7.046616636  0.8013668       WT -1.5762882212
    -#> Cell638   -1.436607733  0.8355664       WT -0.3313398682
    -#> Cell1977   2.884556426  0.8619089   Mutant  0.6275937622
    -#> Cell1686   4.337423462  0.8707659   Mutant  0.9500075864
    -#> Cell851   -3.752315907  0.8214494       WT -0.8452315798
    -#> Cell242   -5.079950245  0.8133559       WT -1.1398543177
    -#> Cell1902   3.403932649  0.8650752   Mutant  0.7428514356
    -#> Cell1810   3.412701104  0.8651286   Mutant  0.7447972923
    -#> Cell773    2.349337186  0.8586462       WT  0.5088202766
    -#> Cell738   -3.995292851  0.8199682       WT -0.8991519480
    -#> Cell1137   3.098294021  0.8632119   Mutant  0.6750254635
    -#> Cell876   -0.048438604  0.8440289       WT -0.0232835173
    -#> Cell495   -3.997716888  0.8199534       WT -0.8996898796
    -#> Cell579   -3.504593100  0.8229596       WT -0.7902580306
    -#> Cell1155   4.998723260  0.8747973   Mutant  1.0967603114
    -#> Cell349   -2.462343655  0.8293133       WT -0.5589666454
    -#> Cell1275   2.687362053  0.8607068   Mutant  0.5838332594
    -#> Cell529    0.198503356  0.8455343       WT  0.0315167499
    -#> Cell989    0.630634701  0.8481686       WT  0.1274134260
    -#> Cell1068   4.821784766  0.8737186   Mutant  1.0574949037
    -#> Cell1231   3.786000660  0.8674043   Mutant  0.8276382778
    -#> Cell1542   1.892750173  0.8558627   Mutant  0.4074965071
    -#> Cell1766   5.619921230  0.8785842   Mutant  1.2346138161
    -#> Cell662   -6.814473680  0.8027820       WT -1.5247720835
    -#> Cell1939   2.997972391  0.8626003   Mutant  0.6527625312
    -#> Cell991   -5.035866359  0.8136247       WT -1.1300714168
    -#> Cell900   -5.003188574  0.8138239       WT -1.1228197073
    -#> Cell350   -5.856891405  0.8086195       WT -1.3122696621
    -#> Cell1105   4.871124094  0.8740194   Mutant  1.0684440690
    -#> Cell1161   3.460193650  0.8654181   Mutant  0.7553366278
    -#> Cell307   -3.730341555  0.8215834       WT -0.8403551288
    -#> Cell1680   3.586560418  0.8661885   Mutant  0.7833793819
    -#> Cell915   -1.184810678  0.8371014       WT -0.2754621798
    -#> Cell1537   3.854533637  0.8678221   Mutant  0.8428468129
    -#> Cell536   -2.115077973  0.8314303       WT -0.4819029817
    -#> Cell1464   5.416358653  0.8773433   Mutant  1.1894401099
    -#> Cell1718   3.321093218  0.8645701   Mutant  0.7244680755
    -#> Cell1222   1.350105892  0.8525547   Mutant  0.2870752892
    -#> Cell1346   0.242337028  0.8458015   Mutant  0.0412441245
    -#> Cell13    -1.336615416  0.8361759       WT -0.3091500155
    -#> Cell1264   2.241701508  0.8579900   Mutant  0.4849342431
    -#> Cell599   -3.898274872  0.8205596       WT -0.8776221475
    -#> Cell1578   5.409611130  0.8773021   Mutant  1.1879427295
    -#> Cell703   -3.201709335  0.8248060       WT -0.7230434056
    -#> Cell605   -0.735202723  0.8398423       WT -0.1756871718
    -#> Cell480   -5.120714897  0.8131074       WT -1.1489006289
    -#> Cell1829   4.823959523  0.8737319   Mutant  1.0579775161
    -#> Cell1056   4.792764816  0.8735417   Mutant  1.0510549248
    -#> Cell1956   8.552491378  0.8964617   Mutant  1.8853968076
    -#> Cell259   -7.553028226  0.7982796       WT -1.6886688405
    -#> Cell1694   6.047569007  0.8811912   Mutant  1.3295155186
    -#> Cell1074   2.347111270  0.8586326   Mutant  0.5083263111
    -#> Cell16    -5.797644550  0.8089807       WT -1.2991218623
    -#> Cell1444   1.768306627  0.8551041   Mutant  0.3798805458
    -#> Cell893    0.201007909  0.8455496       WT  0.0320725492
    -#> Cell1918   2.543403845  0.8598292   Mutant  0.5518866909
    -#> Cell686   -3.143237296  0.8251625       WT -0.7100675493
    -#> Cell1519   4.697006239  0.8729580   Mutant  1.0298046050
    -#> Cell1619   2.476559186  0.8594217   Mutant  0.5370528198
    -#> Cell1348   0.766450976  0.8489966   Mutant  0.1575531728
    -#> Cell745   -0.659301316  0.8403050       WT -0.1588434675
    -#> Cell1408   4.944346544  0.8744658   Mutant  1.0846932710
    -#> Cell1790  10.742260242  0.9098109   Mutant  2.3713406248
    -#> Cell183    1.387706707  0.8527839       WT  0.2954194957
    -#> Cell725   -2.634714944  0.8282625       WT -0.5972185192
    -#> Cell1027   2.877252483  0.8618644   Mutant  0.6259729034
    -#> Cell516   -5.894440669  0.8083906       WT -1.3206024285
    -#> Cell811   -4.506181354  0.8168537       WT -1.0125260641
    -#> Cell1905   4.992353197  0.8747584   Mutant  1.0953466951
    -#> Cell1461   2.964834268  0.8623983   Mutant  0.6454086656
    -#> Cell1568   3.973536437  0.8685476   Mutant  0.8692553877
    -#> Cell1278   4.410277935  0.8712100   Mutant  0.9661751286
    -#> Cell927   -0.134722958  0.8435029       WT -0.0424313593
    -#> Cell752   -1.746462316  0.8336774       WT -0.4001014261
    -#> Cell39    -3.285300100  0.8242964       WT -0.7415934982
    -#> Cell1641   3.354311456  0.8647727   Mutant  0.7318397199
    -#> Cell1769   5.885843395  0.8802053   Mutant  1.2936260866
    -#> Cell1271   4.817588253  0.8736930   Mutant  1.0565636320
    -#> Cell430   -1.864688830  0.8329567       WT -0.4263377310
    -#> Cell847    1.229967903  0.8518223       WT  0.2604147982
    -#> Cell1735   0.801656837  0.8492112   Mutant  0.1653659015
    -#> Cell1114   4.140353427  0.8695645   Mutant  0.9062746761
    -#> Cell251   -2.154466216  0.8311902       WT -0.4906438463
    -#> Cell693   -5.025854016  0.8136857       WT -1.1278495219
    -#> Cell1147   2.686011869  0.8606986   Mutant  0.5835336326
    -#> Cell527   -6.433225310  0.8051061       WT -1.4401671321
    -#> Cell37    -0.880086984  0.8389590       WT -0.2078392459
    -#> Cell460   -2.546460426  0.8288005       WT -0.5776334669
    -#> Cell1013   3.611430796  0.8663401   Mutant  0.7888985062
    -#> Cell29    -5.015415459  0.8137493       WT -1.1255330434
    -#> Cell822   -2.336409877  0.8300810       WT -0.5310199786
    -#> Cell1910   6.028404488  0.8810744   Mutant  1.3252626133
    -#> Cell1258   2.951003706  0.8623140   Mutant  0.6423394485
    -#> Cell33    -1.984246246  0.8322279       WT -0.4528693838
    -#> Cell1253   1.467654177  0.8532713   Mutant  0.3131610844
    -#> Cell917   -4.719723080  0.8155519       WT -1.0599142990
    -#> Cell1394   4.368808833  0.8709572   Mutant  0.9569724890
    -#> Cell1476   4.472466790  0.8715891   Mutant  0.9799758042
    -#> Cell815   -5.942406242  0.8080982       WT -1.3312467363
    -#> Cell203    0.274357520  0.8459967       WT  0.0483499704
    -#> Cell861   -7.638790863  0.7977568       WT -1.7077009053
    -#> Cell220   -5.370176126  0.8115866       WT -1.2042599609
    -#> Cell1589   5.551010699  0.8781641   Mutant  1.2193214962
    -#> Cell1235   4.870658083  0.8740166   Mutant  1.0683406538
    -#> Cell1000  -5.348555111  0.8117185       WT -1.1994619209
    -#> Cell416   -4.414480813  0.8174127       WT -0.9921762859
    -#> Cell1126   1.558195656  0.8538232   Mutant  0.3332536489
    -#> Cell1018   1.948846647  0.8562047   Mutant  0.4199451882
    -#> Cell1006   4.861111497  0.8739584   Mutant  1.0662221178
    -#> Cell1395   3.115589296  0.8633174   Mutant  0.6788635544
    -#> Cell1587   0.942958517  0.8500726   Mutant  0.1967229451
    -#> Cell1888   1.645193420  0.8543536   Mutant  0.3525598077
    -#> Cell47    -0.267747737  0.8426919       WT -0.0719516296
    -#> Cell1430   3.143583939  0.8634880   Mutant  0.6850760017
    -#> Cell954   -5.597396192  0.8102015       WT -1.2546836326
    -#> Cell20    -3.688963215  0.8218356       WT -0.8311726306
    -#> Cell1755   1.372905540  0.8526937   Mutant  0.2921348861
    -#> Cell106   -4.433565838  0.8172964       WT -0.9964115500
    -#> Cell499   -1.612528820  0.8344939       WT -0.3703794973
    -#> Cell1246   2.448497074  0.8592506   Mutant  0.5308254001
    -#> Cell6     -3.214696805  0.8247268       WT -0.7259255273
    -#> Cell32    -2.615157036  0.8283817       WT -0.5928783148
    -#> Cell770   -2.023106052  0.8319910       WT -0.4614929799
    -#> Cell445   -1.237742433  0.8367787       WT -0.2872085607
    -#> Cell1851   3.474343355  0.8655044   Mutant  0.7584766677
    -#> Cell1805   4.640861512  0.8726157   Mutant  1.0173452158
    -#> Cell1059   3.939934653  0.8683427   Mutant  0.8617986286
    -#> Cell1676   2.616644027  0.8602757   Mutant  0.5681398279
    -#> Cell739   -1.945994993  0.8324611       WT -0.4443808349
    -#> Cell301   -7.280541041  0.7999407       WT -1.6281996900
    -#> Cell95    -7.269255962  0.8000095       WT -1.6256953552
    -#> Cell1414   2.015880972  0.8566133   Mutant  0.4348211490
    -#> Cell328   -4.637247151  0.8160547       WT -1.0416116058
    -#> Cell498   -0.370219347  0.8420673       WT -0.0946916760
    -#> Cell171   -2.998080814  0.8260474       WT -0.6778550652
    -#> Cell132   -2.533510193  0.8288795       WT -0.5747596084
    -#> Cell1573   2.917303755  0.8621086   Mutant  0.6348609045
    -#> Cell263   -4.529245082  0.8167131       WT -1.0176442646
    -#> Cell623   -4.829405385  0.8148833       WT -1.0842545109
    -#> Cell1482   2.369018940  0.8587661   Mutant  0.5131879643
    -#> Cell255   -6.715196623  0.8033872       WT -1.5027409584
    -#> Cell395   -4.903639814  0.8144307       WT -1.1007282870
    -#> Cell1730   2.712155676  0.8608580   Mutant  0.5893353506
    -#> Cell483   -4.774796983  0.8152162       WT -1.0721360558
    -#> Cell1034   6.959922286  0.8867531   Mutant  1.5319809216
    -#> Cell587   -4.069732113  0.8195144       WT -0.9156711796
    -#> Cell1322   2.270152463  0.8581634   Mutant  0.4912479533
    -#> Cell63    -3.237842942  0.8245857       WT -0.7310620156
    -#> Cell882   -1.881731178  0.8328528       WT -0.4301196934
    -#> Cell1427   4.329921631  0.8707201   Mutant  0.9483428130
    -#> Cell1627   5.130336580  0.8755996   Mutant  1.1259673570
    -#> Cell1948   3.381770705  0.8649400   Mutant  0.7379333549
    -#> Cell1011   6.063291409  0.8812871   Mutant  1.3330045646
    -#> Cell607   -1.614551319  0.8344816       WT -0.3708283213
    -#> Cell376   -5.534697730  0.8105837       WT -1.2407698673
    -#> Cell224   -2.657125666  0.8281259       WT -0.6021918074
    -#> Cell658   -3.870323272  0.8207300       WT -0.8714192521
    -#> Cell1447   3.794372237  0.8674553   Mutant  0.8294960612
    -#> Cell1659   4.608717809  0.8724197   Mutant  1.0102120273
    -#> Cell1223   3.585599715  0.8661826   Mutant  0.7831661870
    -#> Cell688   -2.407077844  0.8296502       WT -0.5467023010
    -#> Cell103   -2.346748340  0.8300180       WT -0.5333142445
    -#> Cell867   -4.026942764  0.8197752       WT -0.9061755567
    -#> Cell1371   3.616564881  0.8663714   Mutant  0.7900378396
    -#> Cell1802   5.245142860  0.8762995   Mutant  1.1514446586
    -#> Cell685   -6.945613827  0.8019825       WT -1.5538741247
    -#> Cell1724   4.570304919  0.8721856   Mutant  1.0016876088
    -#> Cell879   -8.904717776  0.7900395       WT -1.9886298045
    -#> Cell647   -3.360193202  0.8238399       WT -0.7582134440
    -#> Cell641    2.290561777  0.8582878       WT  0.4957770978
    -#> Cell1938   6.172341765  0.8819519   Mutant  1.3572045370
    -#> Cell1745   3.718833652  0.8669948   Mutant  0.8127328727
    -#> Cell1586   2.698654587  0.8607757   Mutant  0.5863392485
    -#> Cell326  -18.265870340  0.7329722       WT -4.0660153612
    -#> Cell1621   1.333476956  0.8524533   Mutant  0.2833850694
    -#> Cell1716   3.509726423  0.8657201   Mutant  0.7663287216
    -#> Cell1794   1.395343215  0.8528304   Mutant  0.2971141556
    -#> Cell872   -3.837570886  0.8209297       WT -0.8641509873
    -#> Cell843    0.093709509  0.8448955       WT  0.0082613630
    -#> Cell1165   1.030655316  0.8506072   Mutant  0.2161842308
    -#> Cell1343   6.124400510  0.8816596   Mutant  1.3465656258
    -#> Cell1572   4.304010610  0.8705622   Mutant  0.9425927539
    -#> Cell1870   3.617627058  0.8663779   Mutant  0.7902735531
    -#> Cell1329   3.096530794  0.8632012   Mutant  0.6746341759
    -#> Cell1142   2.224180990  0.8578832   Mutant  0.4810461673
    -#> Cell1917   4.764195933  0.8733676   Mutant  1.0447150448
    -#> Cell1926   5.464900342  0.8776392   Mutant  1.2002122667
    -#> Cell379   -3.685802622  0.8218549       WT -0.8304712458
    -#> Cell1081   3.877698917  0.8679633   Mutant  0.8479875494
    -#> Cell1020   2.450118402  0.8592605   Mutant  0.5311851982
    -#> Cell1387   1.290023873  0.8521884   Mutant  0.2737421534
    -#> Cell302   -1.948362100  0.8324466       WT -0.4449061330
    -#> Cell1658   4.537313460  0.8719844   Mutant  0.9943662903
    -#> Cell754   -3.049089327  0.8257364       WT -0.6891746485
    -#> Cell696   -2.936196494  0.8264246       WT -0.6641219708
    -#> Cell1531   5.842394476  0.8799404   Mutant  1.2839840947
    -#> Cell1740   3.259529110  0.8641948   Mutant  0.7108060410
    -#> Cell1692   6.580177340  0.8844381   Mutant  1.4477096033
    -#> Cell1240   3.497488321  0.8656455   Mutant  0.7636128963
    -#> Cell1043   2.196907383  0.8577169   Mutant  0.4749937292
    -#> Cell1435   3.261256493  0.8642054   Mutant  0.7111893742
    -#> Cell744    2.281988300  0.8582356       WT  0.4938745099
    -#> Cell1591   8.518784386  0.8962562   Mutant  1.8779167013
    -#> Cell114   -4.406950058  0.8174586       WT -0.9905050940
    -#> Cell809   -5.900812282  0.8083518       WT -1.3220163888
    -#> Cell1055   5.991890987  0.8808518   Mutant  1.3171596989
    -#> Cell17    -2.350680759  0.8299940       WT -0.5341869096
    -#> Cell683   -8.943098310  0.7898055       WT -1.9971470429
    -#> Cell1848   5.072666836  0.8752480   Mutant  1.1131695426
    -#> Cell746   -0.560815494  0.8409054       WT -0.1369879295
    -#> Cell1517   5.372093912  0.8770734   Mutant  1.1796170744
    -#> Cell969   -4.185426713  0.8188091       WT -0.9413456134
    -#> Cell995   -6.917044973  0.8021567       WT -1.5475342510
    -#> Cell456    2.959891273  0.8623682       WT  0.6443117382
    -#> Cell223   -0.933540501  0.8386332       WT -0.2197014139
    -#> Cell1719   3.982894994  0.8686046   Mutant  0.8713321973
    -#> Cell680   -0.749837851  0.8397530       WT -0.1789349347
    -#> Cell1046   5.927376131  0.8804585   Mutant  1.3028428475
    -#> Cell1234   5.571832247  0.8782910   Mutant  1.2239421218
    -#> Cell1054   2.176785408  0.8575942   Mutant  0.4705283496
    -#> Cell1067   2.038782854  0.8567530   Mutant  0.4399034335
    -#> Cell85    -3.751384863  0.8214551       WT -0.8450249667
    -#> Cell1280   5.396265062  0.8772208   Mutant  1.1849810291
    -#> Cell706   -2.085770642  0.8316090       WT -0.4753992286
    -#> Cell1913   0.150922006  0.8452442   Mutant  0.0209577071
    -#> Cell1416   2.954025419  0.8623324   Mutant  0.6430100137
    -#> Cell1722   2.830832128  0.8615814   Mutant  0.6156715037
    -#> Cell358   -0.440963717  0.8416360       WT -0.1103909536
    -#> Cell1259   2.834472726  0.8616036   Mutant  0.6164794091
    -#> Cell1098   6.449359090  0.8836406   Mutant  1.4186789962
    -#> Cell940   -3.096027781  0.8254503       WT -0.6995910227
    -#> Cell714   -3.794824327  0.8211903       WT -0.8546648603
    -#> Cell1867   3.080942020  0.8631061   Mutant  0.6711747842
    -#> Cell1838   5.675577294  0.8789235   Mutant  1.2469647638
    -#> Cell324    1.086230534  0.8509460       WT  0.2285172373
    -#> Cell659   -6.499557521  0.8047017       WT -1.4548872829
    -#> Cell1154   2.090085029  0.8570657   Mutant  0.4512881850
    -#> Cell1559   3.963602208  0.8684870   Mutant  0.8670508275
    -#> Cell1972   6.007106990  0.8809446   Mutant  1.3205363669
    -#> Cell1562   0.889541876  0.8497470   Mutant  0.1848689606
    -#> Cell1527   1.242014241  0.8518957   Mutant  0.2630880683
    -#> Cell1767   6.300441143  0.8827328   Mutant  1.3856317842
    -#> Cell704   -8.376010765  0.7932626       WT -1.8713014842
    -#> Cell1859   5.283789862  0.8765351   Mutant  1.1600210302
    -#> Cell902   -2.836085918  0.8270349       WT -0.6419058746
    -#> Cell303   -3.304543819  0.8241791       WT -0.7458639793
    -#> Cell1360   4.236161257  0.8701486   Mutant  0.9275359258
    -#> Cell901   -6.761271589  0.8031063       WT -1.5129657108
    -#> Cell1986   2.029917486  0.8566989   Mutant  0.4379360702
    -#> Cell853   -8.193048412  0.7943779       WT -1.8306992882
    -#> Cell881   -4.081652166  0.8194417       WT -0.9183164250
    -#> Cell99    -3.397826655  0.8236104       WT -0.7665648935
    -#> Cell133    1.620048292  0.8542003       WT  0.3469797122
    -#> Cell723   -3.242267624  0.8245588       WT -0.7320439215
    -#> Cell894   -3.946585894  0.8202651       WT -0.8883431156
    -#> Cell1785   3.484115328  0.8655640   Mutant  0.7606452209
    -#> Cell859   -3.457021405  0.8232496       WT -0.7797011305
    -#> Cell635   -3.675395765  0.8219183       WT -0.8281618023
    -#> Cell530   -5.663248662  0.8098000       WT -1.2692973214
    -#> Cell1384   5.632130393  0.8786586   Mutant  1.2373232197
    -#> Cell711   -5.373538554  0.8115662       WT -1.2050061360
    -#> Cell1117   3.183318917  0.8637303   Mutant  0.6938938123
    -#> Cell1953   2.223310056  0.8578779   Mutant  0.4808528936
    -#> Cell1970   5.304286040  0.8766600   Mutant  1.1645694514
    -#> Cell112   -4.408376761  0.8174499       WT -0.9908217015
    -#> Cell1149   2.027098930  0.8566817   Mutant  0.4373105887
    -#> Cell1907   6.688858104  0.8851006   Mutant  1.4718275576
    -#> Cell464   -5.695608982  0.8096028       WT -1.2764785804
    -#> Cell1940   5.301887782  0.8766454   Mutant  1.1640372408
    -#> Cell88     0.732908415  0.8487921       WT  0.1501095559
    -#> Cell300   -5.669291659  0.8097632       WT -1.2706383564
    -#> Cell1272   5.116512926  0.8755153   Mutant  1.1228996728
    -#> Cell546   -4.931889245  0.8142585       WT -1.1069972756
    -#> Cell1289   2.195212284  0.8577066   Mutant  0.4746175603
    -#> Cell1845   1.927293666  0.8560733   Mutant  0.4151622461
    -#> Cell1303   8.129755968  0.8938846   Mutant  1.7915852361
    -#> Cell143   -3.802415059  0.8211440       WT -0.8563493619
    -#> Cell254  -11.821139992  0.7722604       WT -2.6358293184
    -#> Cell967   -3.683881418  0.8218666       WT -0.8300449006
    -#> Cell576   -1.821673860  0.8332189       WT -0.4167920391
    -#> Cell507   -2.010882268  0.8320655       WT -0.4587803320
    -#> Cell1152   3.953152029  0.8684233   Mutant  0.8647317701
    -#> Cell889   -3.710332619  0.8217053       WT -0.8359148341
    -#> Cell724   -6.680320560  0.8035998       WT -1.4950014168
    -#> Cell1749   1.378398146  0.8527271   Mutant  0.2933537809
    -#> Cell763   -4.302723030  0.8180940       WT -0.9673754931
    -#> Cell1452   2.978714870  0.8624829   Mutant  0.6484889875
    -#> Cell1631   1.757163092  0.8550362   Mutant  0.3774076219
    -#> Cell984   -3.434538516  0.8233866       WT -0.7747118271
    -#> Cell1764   1.165758292  0.8514308   Mutant  0.2461656853
    -#> Cell1500   5.235601708  0.8762413   Mutant  1.1493273284
    -#> Cell348   -5.346972310  0.8117281       WT -1.1991106727
    -#> Cell1215   1.445845222  0.8531383   Mutant  0.3083213376
    -#> Cell1409   3.526213855  0.8658206   Mutant  0.7699875397
    -#> Cell947   -7.166447374  0.8006363       WT -1.6028805282
    -#> Cell666   -7.208716316  0.8003786       WT -1.6122606648
    -#> Cell1174   2.068746807  0.8569356   Mutant  0.4465529011
    -#> Cell151   -0.572379126  0.8408349       WT -0.1395540797
    -#> Cell1492   1.367946705  0.8526634   Mutant  0.2910344434
    -#> Cell1924   6.397851594  0.8833266   Mutant  1.4072486805
    -#> Cell1042   4.025797012  0.8688661   Mutant  0.8808528234
    -#> Cell1022   4.698735640  0.8729685   Mutant  1.0301883862
    -#> Cell791   -1.696228020  0.8339837       WT -0.3889536534
    -#> Cell1987   2.053340096  0.8568417   Mutant  0.4431339121
    -#> Cell2     -3.233870458  0.8246099       WT -0.7301804596
    -#> Cell214   -4.912004476  0.8143797       WT -1.1025845356
    -#> Cell932   -3.111385365  0.8253566       WT -0.7029991098
    -#> Cell1195   9.364763592  0.9014134   Mutant  2.0656526633
    -#> Cell1307   1.940139376  0.8561516   Mutant  0.4180129092
    -#> Cell1981   1.140097065  0.8512744   Mutant  0.2404710594
    -#> Cell419   -4.062967220  0.8195556       WT -0.9141699446
    -#> Cell1200   1.760294236  0.8550552   Mutant  0.3781024714
    -#> Cell664   -3.982899016  0.8200437       WT -0.8964015630
    -#> Cell1254   1.907233009  0.8559510   Mutant  0.4107104738
    -#> Cell567   -2.598860737  0.8284811       WT -0.5892619120
    -#> Cell50    -4.688545222  0.8157420       WT -1.0529954468
    -#> Cell836   -9.744687236  0.7849189       WT -2.1750321105
    -#> Cell1833   2.826915372  0.8615576   Mutant  0.6148023146
    -#> Cell1026   5.000829242  0.8748101   Mutant  1.0972276616
    -#> Cell682  -15.619162048  0.7491070       WT -3.4786695678
    -#> Cell382  -10.155737059  0.7824130       WT -2.2662504684
    -#> Cell137    0.100640586  0.8449377       WT  0.0097994769
    -#> Cell77    -0.238754312  0.8428687       WT -0.0655175370
    -#> Cell800   -3.810777707  0.8210930       WT -0.8582051636
    -#> Cell78    -2.645891301  0.8281944       WT -0.5996987267
    -#> Cell1064   2.865408979  0.8617922   Mutant  0.6233446453
    -#> Cell1647   4.868470780  0.8740032   Mutant  1.0678552573
    -#> Cell1994   0.583609639  0.8478820   Mutant  0.1169778323
    -#> Cell1978   6.962061096  0.8867661   Mutant  1.5324555566
    -#> Cell1377   3.954077099  0.8684289   Mutant  0.8649370576
    -#> Cell497   -4.234679356  0.8185088       WT -0.9522755420
    -#> Cell1084   3.509317153  0.8657176   Mutant  0.7662378983
    -#> Cell775   -1.172671324  0.8371754       WT -0.2727682680
    -#> Cell60     2.145432360  0.8574031       WT  0.4635706198
    -#> Cell357   -0.487277800  0.8413537       WT -0.1206687698
    -#> Cell740   -3.228914475  0.8246402       WT -0.7290806499
    -#> Cell1950   4.048628446  0.8690053   Mutant  0.8859194740
    -#> Cell717   -6.758334946  0.8031242       WT -1.5123140241
    -#> Cell589   -5.908401009  0.8083055       WT -1.3237004454
    -#> Cell1417   0.547208312  0.8476601   Mutant  0.1088998107
    -#> Cell935   -6.498382765  0.8047089       WT -1.4546265863
    -#> Cell1855   0.108139910  0.8449834   Mutant  0.0114636938
    -#> Cell1350   5.012268485  0.8748798   Mutant  1.0997662078
    -#> Cell138   -0.831108216  0.8392576       WT -0.1969700945
    -#> Cell1746   0.861889372  0.8495784   Mutant  0.1787324394
    -#> Cell892    0.061091298  0.8446966       WT  0.0010228741
    -#> Cell1342   3.893843524  0.8680617   Mutant  0.8515702891
    -#> Cell1679   9.559372710  0.9025998   Mutant  2.1088394578
    -#> Cell1516   2.401470418  0.8589640   Mutant  0.5203894528
    -#> Cell526   -2.282387097  0.8304104       WT -0.5190314822
    -#> Cell1470   4.120203300  0.8694417   Mutant  0.9018030491
    -#> Cell1281   1.556337813  0.8538119   Mutant  0.3328413646
    -#> Cell910   -4.453910428  0.8171724       WT -1.0009263314
    -#> Cell1311   3.189515739  0.8637680   Mutant  0.6952689836
    -#> Cell1599   0.326556684  0.8463149   Mutant  0.0599337779
    -#> Cell367   -5.155110321  0.8128977       WT -1.1565335092
    -#> Cell1057   3.508826647  0.8657146   Mutant  0.7661290474
    -#> Cell903   -0.893706855  0.8388760       WT -0.2108617074
    -#> Cell559   -4.417421260  0.8173948       WT -0.9928288167
    -#> Cell1107   1.434083425  0.8530666   Mutant  0.3057112118
    -#> Cell1341   6.737707834  0.8853984   Mutant  1.4826680734
    -#> Cell277   -8.239001362  0.7940978       WT -1.8408969636
    -#> Cell612   -5.328572569  0.8118403       WT -1.1950274836
    -#> Cell1129   5.002101720  0.8748179   Mutant  1.0975100442
    -#> Cell385   -5.286338654  0.8120977       WT -1.1856551202
    -#> Cell1998   2.131249125  0.8573166   Mutant  0.4604231392
    -#> Cell1455   3.346601949  0.8647257   Mutant  0.7301288603
    -#> Cell1475   2.560436774  0.8599331   Mutant  0.5556665630
    -#> Cell611   -0.386231572  0.8419696       WT -0.0982450380
    -#> Cell1498   4.065121534  0.8691059   Mutant  0.8895795473
    -#> Cell111   -3.382416008  0.8237044       WT -0.7631450307
    -#> Cell1759   5.097750834  0.8754010   Mutant  1.1187360724
    -#> Cell1791   1.478847999  0.8533395   Mutant  0.3156451679
    -#> Cell1963   0.846420719  0.8494841   Mutant  0.1752997042
    -#> Cell695   -2.691012660  0.8279193       WT -0.6097118591
    -#> Cell1780   2.640759568  0.8604227   Mutant  0.5734914422
    -#> Cell1328   6.043100793  0.8811640   Mutant  1.3285239525
    -#> Cell424   -3.293794843  0.8242446       WT -0.7434786141
    -#> Cell239  -10.634235037  0.7794960       WT -2.3724366226
    -#> Cell678   -9.490203543  0.7864702       WT -2.1185582154
    -#> Cell614   -0.142209557  0.8434572       WT -0.0440927523
    -#> Cell1001   3.775664784  0.8673413   Mutant  0.8253445861
    -#> Cell266   -2.255521151  0.8305741       WT -0.5130695103
    -#> Cell1914  -0.048914808  0.8440260   Mutant -0.0233891943
    -#> Cell154   -0.807224957  0.8394032       WT -0.1916700272
    -#> Cell652   -9.557329415  0.7860610       WT -2.1334544918
    -#> Cell712  -10.507526220  0.7802685       WT -2.3443179624
    -#> Cell937   -8.115943055  0.7948480       WT -1.8135884085
    -#> Cell1428   4.569222518  0.8721790   Mutant  1.0014474071
    -#> Cell453    0.058585269  0.8446813       WT  0.0004667472
    -#> Cell420   -1.141746369  0.8373639       WT -0.2659055388
    -#> Cell56    -4.258388181  0.8183643       WT -0.9575368996
    -#> Cell400    1.193808566  0.8516018       WT  0.2523904781
    -#> Cell551    0.026048725  0.8444830       WT -0.0067536188
    -#> Cell116   -6.671552889  0.8036532       WT -1.4930557340
    -#> Cell89     0.384392202  0.8466675       WT  0.0727683801
    -#> Cell591   -0.659384246  0.8403045       WT -0.1588618709
    -#> Cell874   -5.906678186  0.8083160       WT -1.3233181243
    -#> Cell1177   3.311328457  0.8645106   Mutant  0.7223011229
    -#> Cell115   -6.727406157  0.8033127       WT -1.5054504440
    -#> Cell1777   2.777922458  0.8612589   Mutant  0.6039300237
    -#> Cell1534   3.129268837  0.8634008   Mutant  0.6818992576
    -#> Cell432   -2.566191475  0.8286802       WT -0.5820120940
    -#> Cell1334   2.635727875  0.8603920   Mutant  0.5723748312
    -#> Cell413   -3.506912037  0.8229454       WT -0.7907726386
    -#> Cell45    -5.352630642  0.8116936       WT -1.2003663448
    -#> Cell716    1.983219917  0.8564142       WT  0.4275731522
    -#> Cell997   -0.514120401  0.8411900       WT -0.1266255612
    -#> Cell1873   6.854802779  0.8861123   Mutant  1.5086532657
    -#> Cell1353   3.306925882  0.8644838   Mutant  0.7213241230
    -#> Cell1094   4.435874195  0.8713660   Mutant  0.9718553374
    -#> Cell370   -4.745255154  0.8153963       WT -1.0655802639
    -#> Cell692   -3.653688004  0.8220507       WT -0.8233445119
    -#> Cell1140   4.764270671  0.8733680   Mutant  1.0447316303
    -#> Cell1899   1.443446450  0.8531237   Mutant  0.3077890127
    -#> Cell868   -4.173767705  0.8188802       WT -0.9387582978
    -#> Cell1663   5.278786608  0.8765046   Mutant  1.1589107304
    -#> Cell484   -2.890246707  0.8267047       WT -0.6539249972
    -#> Cell1682   3.398664796  0.8650430   Mutant  0.7416824169
    -#> Cell602   -2.460269547  0.8293259       WT -0.5585063685
    -#> Cell1494   3.751850387  0.8671961   Mutant  0.8200598005
    -#> Cell142   -2.087740416  0.8315970       WT -0.4758363521
    -#> Cell21    -6.450239979  0.8050024       WT -1.4439429522
    -#> Cell1816   3.808554282  0.8675418   Mutant  0.8326432779
    -#> Cell198   -1.845842561  0.8330716       WT -0.4221554504
    -#> Cell1974   2.421794769  0.8590879   Mutant  0.5248997429
    -#> Cell1758   1.074573451  0.8508750   Mutant  0.2259303489
    -#> Cell621   -4.709343129  0.8156152       WT -1.0576108263
    -#> Cell735   -8.851880477  0.7903616       WT -1.9769043849
    -#> Cell629    1.547000648  0.8537550       WT  0.3307693022
    -#> Cell1980   4.728021607  0.8731470   Mutant  1.0366873982
    -#> Cell627   -1.502393528  0.8351653       WT -0.3459387606
    -#> Cell1700   2.897869742  0.8619901   Mutant  0.6305481943
    -#> Cell1071   4.395256069  0.8711184   Mutant  0.9628415425
    -#> Cell679   -6.261440182  0.8061533       WT -1.4020453366
    -#> Cell1900   2.649728265  0.8604774   Mutant  0.5754817357
    -#> Cell1404   3.778424219  0.8673581   Mutant  0.8259569478
    -#> Cell767   -2.521966609  0.8289498       WT -0.5721979075
    -#> Cell590   -1.310648365  0.8363342       WT -0.3033875226
    -#> Cell11    -0.776900605  0.8395881       WT -0.1849405813
    -#> Cell1581   3.557353795  0.8660104   Mutant  0.7768979773
    -#> Cell552   -2.475870473  0.8292308       WT -0.5619684569
    -#> Cell653   -3.546061522  0.8227068       WT -0.7994605192
    -#> Cell899   -4.974173033  0.8140008       WT -1.1163807068
    -#> Cell473   -1.812677052  0.8332738       WT -0.4147955074
    -#> Cell342   -5.726944502  0.8094117       WT -1.2834324204
    -#> Cell1044   3.470057348  0.8654783   Mutant  0.7575255362
    -#> Cell795   -9.785980590  0.7846671       WT -2.1841957488
    -#> Cell1975   1.654986644  0.8544133   Mutant  0.3547330766
    -#> Cell1554   4.014636943  0.8687981   Mutant  0.8783762301
    -#> Cell314   -5.036891700  0.8136184       WT -1.1302989558
    -#> Cell411   -0.952210539  0.8385193       WT -0.2238445861
    -#> Cell926   -5.424036557  0.8112583       WT -1.2162124295
    -#> Cell1555   3.980261752  0.8685886   Mutant  0.8707478400
    -#> Cell488   -1.920004682  0.8326195       WT -0.4386131801
    -#> Cell1291   3.124824368  0.8633737   Mutant  0.6809129607
    -#> Cell888   -2.136139859  0.8313019       WT -0.4865769423
    -#> Cell555   -3.771045227  0.8213352       WT -0.8493879075
    -#> Cell593   -7.251074364  0.8001204       WT -1.6216605756
    -#> Cell1773   5.400549957  0.8772469   Mutant  1.1859319139
    -#> Cell540   -3.718339001  0.8216565       WT -0.8376915750
    -#> Cell355   -6.682578655  0.8035860       WT -1.4955025232
    -#> Cell1834   5.053115015  0.8751289   Mutant  1.1088306889
    -#> Cell1760   5.904522419  0.8803192   Mutant  1.2977712528
    -#> Cell262    5.023204132  0.8749465       WT  1.1021929982
    -#> Cell1872   7.147271994  0.8878952   Mutant  1.5735567396
    -#> Cell341   -6.436180158  0.8050881       WT -1.4408228589
    -#> Cell871   -4.625525939  0.8161262       WT -1.0390104864
    -#> Cell1811   4.128181981  0.8694903   Mutant  0.9035736426
    -#> Cell1520   7.467827523  0.8898494   Mutant  1.6446930043
    -#> Cell31    -4.871163777  0.8146287       WT -1.0935213485
    -#> Cell1198  -0.024338708  0.8441758   Mutant -0.0179353748
    -#> Cell165    0.034820310  0.8445365       WT -0.0048070674
    -#> Cell351   -1.856948261  0.8330039       WT -0.4246199783
    -#> Cell490   -5.571304829  0.8103605       WT -1.2488935528
    -#> Cell235   -2.812617125  0.8271780       WT -0.6366977839
    -#> Cell537   -7.486860184  0.7986830       WT -1.6739851214
    -#> Cell1992   2.356146096  0.8586877   Mutant  0.5103312798
    -#> Cell987   -4.694070759  0.8157083       WT -1.0542216495
    -#> Cell1326   7.322040020  0.8889606   Mutant  1.6123404868
    -#> Cell1985   4.174432303  0.8697723   Mutant  0.9138373094
    -#> Cell1522   0.041947113  0.8445799   Mutant -0.0032255188
    -#> Cell776    1.245328889  0.8519159       WT  0.2638236403
    -#> Cell1299   5.007456610  0.8748505   Mutant  1.0986983777
    -#> Cell780   -7.327076574  0.7996570       WT -1.6385266497
    -#> Cell1242   5.920307424  0.8804154   Mutant  1.3012741913
    -#> Cell1162  15.275956795  0.9374491   Mutant  3.3774385037
    -#> Cell156   -5.835136005  0.8087522       WT -1.3074418001
    -#> Cell1720   6.228643504  0.8822951   Mutant  1.3696987698
    -#> Cell1004   4.473263046  0.8715940   Mutant  0.9801525057
    -#> Cell261   -4.153011791  0.8190067       WT -0.9341522372
    -#> Cell19    -1.838533509  0.8331162       WT -0.4205334579
    -#> Cell1007   3.175780033  0.8636843   Mutant  0.6922208165
    -#> Cell1571   1.297413567  0.8522334   Mutant  0.2753820415
    -#> Cell241   -2.079388194  0.8316479       WT -0.4739828639
    -#> Cell23    -4.026702684  0.8197767       WT -0.9061222791
    -#> Cell479   -0.809253055  0.8393908       WT -0.1921200938
    -#> Cell1502   2.014902383  0.8566074   Mutant  0.4346039848
    -#> Cell793   -5.820650203  0.8088405       WT -1.3042271749
    -#> Cell1233   0.072723424  0.8447675   Mutant  0.0036042239
    -#> Cell1225   3.467461695  0.8654624   Mutant  0.7569495203
    -#> Cell681   -1.126704466  0.8374556       WT -0.2625675064
    -#> Cell466   -3.171647976  0.8249893       WT -0.7163723217
    -#> Cell953   -4.987645736  0.8139186       WT -1.1193705094
    -#> Cell883   -7.844705460  0.7965015       WT -1.7533965617
    -#> Cell1316   4.212488564  0.8700042   Mutant  0.9222825864
    -#> Cell1551   3.317191571  0.8645464   Mutant  0.7236022393
    -#> Cell709   -5.325916399  0.8118565       WT -1.1944380382
    -#> Cell756   -6.979195608  0.8017778       WT -1.5613264449
    -#> Cell1661   2.551152069  0.8598765   Mutant  0.5536061424
    -#> Cell1850   6.015278163  0.8809944   Mutant  1.3223496774
    -#> Cell1380   1.748232977  0.8549817   Mutant  0.3754258903
    -#> Cell1491   1.250303149  0.8519462   Mutant  0.2649275061
    -#> Cell1402   1.490358774  0.8534097   Mutant  0.3181995880
    -#> Cell292   -3.776034353  0.8213048       WT -0.8504950724
    -#> Cell1763   3.105260120  0.8632544   Mutant  0.6765713493
    -#> Cell906   -6.802976151  0.8028520       WT -1.5222206028
    -#> Cell425   -1.153364618  0.8372931       WT -0.2684838092
    -#> Cell1645   6.078817314  0.8813817   Mutant  1.3364500048
    -#> Cell988   -0.394671502  0.8419182       WT -0.1001179900
    -#> Cell240   -4.852682311  0.8147414       WT -1.0894200234
    -#> Cell865   -1.093209811  0.8376598       WT -0.2551345206
    -#> Cell1979   2.498944249  0.8595582   Mutant  0.5420204141
    -#> Cell1265   3.423274516  0.8651931   Mutant  0.7471436970
    -#> Cell1095   5.188361105  0.8759533   Mutant  1.1388439027
    -#> Cell371   -3.629257525  0.8221996       WT -0.8179230082
    -#> Cell1261   3.140156776  0.8634671   Mutant  0.6843154608
    -#> Cell1861   3.946410700  0.8683822   Mutant  0.8632357643
    -#> Cell1262   5.147295719  0.8757030   Mutant  1.1297308540
    -#> Cell1835  13.846165393  0.9287328   Mutant  3.0601455221
    -#> Cell1504   4.774665695  0.8734314   Mutant  1.0470384479
    -#> Cell1277   0.425918039  0.8469207   Mutant  0.0819836100
    -#> Cell1069   2.830607318  0.8615801   Mutant  0.6156216148
    -#> Cell282   -0.185729949  0.8431919       WT -0.0537506051
    -#> Cell1687   2.846559163  0.8616773   Mutant  0.6191615777
    -#> Cell1462   3.681620800  0.8667680   Mutant  0.8044747613
    -#> Cell296   -0.231618210  0.8429122       WT -0.0639339249
    -#> Cell1615   4.125922304  0.8694765   Mutant  0.9030721852
    -#> Cell1642   4.107392394  0.8693636   Mutant  0.8989601094
    -#> Cell1058   1.602222338  0.8540916   Mutant  0.3430238553
    -#> Cell1382  11.106750952  0.9120329   Mutant  2.4522267906
    -#> Cell1863   1.380145627  0.8527378   Mutant  0.2937415743
    -#> Cell1874   3.101145970  0.8632293   Mutant  0.6756583553
    -#> Cell545   -7.284642173  0.7999157       WT -1.6291097951
    -#> Cell1602   7.101674613  0.8876172   Mutant  1.5634379706
    -#> Cell315   -6.550498883  0.8043912       WT -1.4661919645
    -#> Cell234   -3.633526114  0.8221736       WT -0.8188702744
    -#> Cell207   -3.414598984  0.8235082       WT -0.7702869344
    -#> Cell428    1.654634415  0.8544111       WT  0.3546549115
    -#> Cell1252   3.909414471  0.8681567   Mutant  0.8550257248
    -#> Cell1247   5.830726234  0.8798693   Mutant  1.2813947301
    -#> Cell1160   3.424894376  0.8652029   Mutant  0.7475031692
    -#> Cell1941   8.133612240  0.8939081   Mutant  1.7924410029
    -#> Cell702   -3.037891256  0.8258047       WT -0.6866896223
    -#> Cell383   -0.176840852  0.8432461       WT -0.0517779759
    -#> Cell1304   1.633185934  0.8542804   Mutant  0.3498951595
    -#> Cell1143   1.242506854  0.8518987   Mutant  0.2631973867
    -#> Cell1314   3.080107203  0.8631011   Mutant  0.6709895254
    -#> Cell1239   4.381676892  0.8710357   Mutant  0.9598281116
    -#> Cell489   -5.886958016  0.8084363       WT -1.3189419113
    -#> Cell1836   6.476656991  0.8838070   Mutant  1.4247368254
    -#> Cell1876   2.297688737  0.8583313   Mutant  0.4973586813
    -#> Cell1825   5.698392985  0.8790626   Mutant  1.2520279208
    -#> Cell582   -4.669245352  0.8158596       WT -1.0487125050
    -#> Cell1839   3.499143738  0.8656556   Mutant  0.7639802590
    -#> Cell1629   6.003907428  0.8809251   Mutant  1.3198263344
    -#> Cell1219   1.951349455  0.8562199   Mutant  0.4205006003
    -#> Cell1880   5.570869320  0.8782852   Mutant  1.2237284334
    -#> Cell1523   3.532187127  0.8658570   Mutant  0.7713131016
    -#> Cell1885   3.339473980  0.8646822   Mutant  0.7285470528
    -#> Cell1693   4.442913860  0.8714090   Mutant  0.9734175487
    -#> Cell283   -3.498849163  0.8229946       WT -0.7889833614
    -#> Cell729   -2.750616411  0.8275559       WT -0.6229388597
    -#> Cell511   -2.155099788  0.8311863       WT -0.4907844459
    -#> Cell1374   0.964534689  0.8502042   Mutant  0.2015110338
    -#> Cell580   -2.048648719  0.8318353       WT -0.4671612956
    -#> Cell919   -3.896412807  0.8205710       WT -0.8772089262
    -#> Cell1699   6.279597284  0.8826057   Mutant  1.3810062073
    -#> Cell448   -3.801550021  0.8211493       WT -0.8561573964
    -#> Cell1828   3.585429849  0.8661816   Mutant  0.7831284910
    -#> Cell1486   5.961690831  0.8806677   Mutant  1.3104578139
    -#> Cell918   -6.040228357  0.8075019       WT -1.3529549872
    -#> Cell252   -2.419736570  0.8295730       WT -0.5495114696
    -#> Cell1765   5.540451717  0.8780997   Mutant  1.2169782935
    -#> Cell476   -4.177007796  0.8188604       WT -0.9394773246
    -#> Cell1776   1.729878582  0.8548698   Mutant  0.3713527642
    -#> Cell792    0.351297177  0.8464658       WT  0.0654240785
    -#> Cell1662   1.879104760  0.8557795   Mutant  0.4044683772
    -#> Cell999   -2.091833036  0.8315720       WT -0.4767445681
    -#> Cell1640   4.442638194  0.8714073   Mutant  0.9733563739
    -#> Cell818   -4.657221726  0.8159329       WT -1.0460442751
    -#> Cell977   -1.739451754  0.8337202       WT -0.3985456732
    -#> Cell62    -0.281411435  0.8426086       WT -0.0749838170
    -#> Cell799   -5.265791163  0.8122230       WT -1.1810953119
    -#> Cell1134   2.105606874  0.8571603   Mutant  0.4547327241
    -#> Cell1401   2.894139844  0.8619674   Mutant  0.6297204719
    -#> Cell394   -0.103762019  0.8436916       WT -0.0355606448
    -#> Cell1927   2.706802454  0.8608253   Mutant  0.5881473871
    -#> Cell386   -7.252081435  0.8001142       WT -1.6218840602
    -#> Cell1016   2.199874571  0.8577350   Mutant  0.4756521944
    -#> Cell1373   1.515290594  0.8535617   Mutant  0.3237323474
    -#> Cell1115   9.267986870  0.9008235   Mutant  2.0441764015
    -#> Cell643   -1.480602819  0.8352982       WT -0.3411030629
    -#> Cell427   -4.258967060  0.8183608       WT -0.9576653618
    -#> Cell1419   4.320443641  0.8706624   Mutant  0.9462394996
    -#> Cell1120   3.633496572  0.8664746   Mutant  0.7937952455
    -#> Cell1860   4.646908934  0.8726526   Mutant  1.0186872327
    -#> Cell1625   4.033234714  0.8689115   Mutant  0.8825033652
    -#> Cell1906   5.587828215  0.8783886   Mutant  1.2274918763
    -#> Cell572   -2.332036211  0.8301077       WT -0.5300493939
    -#> Cell418   -4.854737845  0.8147289       WT -1.0898761784
    -#> Cell52    -1.284232694  0.8364953       WT -0.2975254736
    -#> Cell1369   4.761970315  0.8733540   Mutant  1.0442211453
    -#> Cell43    -1.665190365  0.8341729       WT -0.3820659144
    -#> Cell1752   1.768542555  0.8551055   Mutant  0.3799329019
    -#> Cell966   -0.355312618  0.8421581       WT -0.0913836405
    -#> Cell345   -5.556627599  0.8104500       WT -1.2456364469
    -#> Cell1696   3.058323672  0.8629683   Mutant  0.6661554205
    -#> Cell1652   4.532720052  0.8719564   Mutant  0.9933469415
    -#> Cell520   -3.978581545  0.8200701       WT -0.8954434489
    -#> Cell925    0.607722374  0.8480290       WT  0.1223288236
    -#> Cell1124   0.545420052  0.8476492   Mutant  0.1085029680
    -#> Cell914   -1.350891874  0.8360889       WT -0.3123181839
    -#> Cell470   -1.666420926  0.8341654       WT -0.3823389951
    -#> Cell1653   2.983144898  0.8625100   Mutant  0.6494720795
    -#> Cell660   -5.533604488  0.8105904       WT -1.2405272600
    -#> Cell1251   2.525551995  0.8597204   Mutant  0.5479250873
    -#> Cell273   -2.541049635  0.8288335       WT -0.5764327281
    -#> Cell1080   4.900859541  0.8742007   Mutant  1.0750428279
    -#> Cell206   -7.439508308  0.7989716       WT -1.6634770027
    -#> Cell584   -6.808329098  0.8028194       WT -1.5234085050
    -#> Cell1108   2.985325742  0.8625232   Mutant  0.6499560429
    -#> Cell193   -6.290202627  0.8059780       WT -1.4084281713
    -#> Cell1868   5.307150607  0.8766775   Mutant  1.1652051435
    -#> Cell1635   5.823154811  0.8798232   Mutant  1.2797145134
    -#> Cell983   -3.723057736  0.8216278       WT -0.8387387360
    -#> Cell971    0.363067257  0.8465375       WT  0.0680360426
    -#> Cell897   -7.292057075  0.7998705       WT -1.6307552773
    -#> Cell1853   3.784066537  0.8673925   Mutant  0.8272090659
    -#> Cell209   -5.794884025  0.8089976       WT -1.2985092587
    -#> Cell1049   2.646390742  0.8604570   Mutant  0.5747410875
    -#> Cell431   -4.766562285  0.8152664       WT -1.0703086482
    -#> Cell1608   4.161314948  0.8696923   Mutant  0.9109263640
    -#> Cell1092   3.474113297  0.8655030   Mutant  0.7584256143
    -#> Cell993   -4.008546396  0.8198874       WT -0.9020931162
    -#> Cell885   -3.069706560  0.8256107       WT -0.6937499337
    -#> Cell1611   3.941651249  0.8683532   Mutant  0.8621795679
    -#> Cell1186   4.642131394  0.8726234   Mutant  1.0176270222
    -#> Cell1710   1.439352274  0.8530987   Mutant  0.3068804513
    -#> Cell1338   7.100033839  0.8876072   Mutant  1.5630738573
    -#> Cell294   -4.536028619  0.8166718       WT -1.0191496371
    -#> Cell397   -2.791427786  0.8273071       WT -0.6319955395
    -#> Cell649   -2.486284874  0.8291674       WT -0.5642795748
    -#> Cell463    0.626907589  0.8481459       WT  0.1265863216
    -#> Cell733   -2.432107455  0.8294976       WT -0.5522567616
    -#> Cell1194   4.550708535  0.8720661   Mutant  0.9973388659
    -#> Cell1141   4.331805821  0.8707316   Mutant  0.9487609443
    -#> Cell1284   3.973831407  0.8685494   Mutant  0.8693208462
    -#> Cell125   -3.022338823  0.8258995       WT -0.6832382953
    -#> Cell454   -5.030830878  0.8136554       WT -1.1289539650
    -#> Cell1312   4.927209427  0.8743613   Mutant  1.0808902779
    -#> Cell1904   2.783401789  0.8612923   Mutant  0.6051459728
    -#> Cell1359   1.143667121  0.8512962   Mutant  0.2412633106
    -#> Cell642  -10.787807556  0.7785598       WT -2.4065167564
    -#> Cell1403   3.422878758  0.8651906   Mutant  0.7470558722
    -#> Cell1473   4.643146162  0.8726296   Mutant  1.0178522151
    -#> Cell1362   7.477612519  0.8899090   Mutant  1.6468644473
    -#> Cell846   -3.211293511  0.8247476       WT -0.7251702835
    -#> Cell377   -2.669592074  0.8280499       WT -0.6049582975
    -#> Cell1499   4.025919231  0.8688669   Mutant  0.8808799456
    -#> Cell1990   4.541059016  0.8720073   Mutant  0.9951974874
    -#> Cell1375   3.475646546  0.8655123   Mutant  0.7587658662
    -#> Cell164   -4.979041263  0.8139711       WT -1.1174610428
    -#> Cell1704   0.755357181  0.8489290   Mutant  0.1550912868
    -#> Cell1121   3.451297325  0.8653639   Mutant  0.7533623948
    -#> Cell1019   3.476952031  0.8655203   Mutant  0.7590555736
    -#> Cell522   -0.884250153  0.8389336       WT -0.2087631179
    -#> Cell1683   2.768361863  0.8612006   Mutant  0.6018083789
    -#> Cell1103   2.058576228  0.8568736   Mutant  0.4442958914
    -#> Cell817   -1.818904432  0.8332358       WT -0.4161774601
    -#> Cell1946   2.947395620  0.8622920   Mutant  0.6415387581
    -#> Cell1808   2.902629649  0.8620191   Mutant  0.6316044919
    -#> Cell1717   1.495558768  0.8534414   Mutant  0.3193535477
    -#> Cell160  -17.008134662  0.7406396       WT -3.7869042246
    -#> Cell4     -3.185460954  0.8249051       WT -0.7194376367
    -#> Cell1133   3.403061224  0.8650698   Mutant  0.7426580526
    -#> Cell668    0.451937019  0.8470793       WT  0.0877576271
    -#> Cell336   -1.709403217  0.8339034       WT -0.3918774349
    -#> Cell569   -2.367582856  0.8298910       WT -0.5379377480
    -#> Cell53    -3.020889616  0.8259083       WT -0.6829166935
    -#> Cell1003   3.231104710  0.8640216   Mutant  0.7044982240
    -#> Cell51    -8.688829444  0.7913556       WT -1.9407208212
    -#> Cell708   -4.752707602  0.8153508       WT -1.0672340783
    -#> Cell1879   8.050219330  0.8933997   Mutant  1.7739348172
    -#> Cell270   -6.929098429  0.8020832       WT -1.5502091007
    -#> Cell1706   3.245238002  0.8641077   Mutant  0.7076346216
    -#> Cell833   -1.010919761  0.8381614       WT -0.2368730769
    -#> Cell554   -5.919187489  0.8082398       WT -1.3260941334
    -#> Cell1230   3.976274617  0.8685642   Mutant  0.8698630326
    -#> Cell1666   6.511467199  0.8840192   Mutant  1.4324617528
    -#> Cell264   -6.752699428  0.8031585       WT -1.5110634149
    -#> Cell66    -7.957103867  0.7958163       WT -1.7783395188
    -#> Cell1889   1.968309532  0.8563233   Mutant  0.4242643056
    -#> Cell1203   3.828078760  0.8676608   Mutant  0.8369760637
    -#> Cell380   -1.936682721  0.8325178       WT -0.4423142968
    -#> Cell228   -5.412731449  0.8113272       WT -1.2137036499
    -#> Cell1782   7.481669221  0.8899337   Mutant  1.6477646928
    -#> Cell826   -4.623204330  0.8161403       WT -1.0384952851
    -#> Cell813   -0.924220632  0.8386900       WT -0.2176331898
    -#> Cell1323   5.078190364  0.8752817   Mutant  1.1143952995
    -#> Cell1431   2.977148190  0.8624734   Mutant  0.6481413167
    -#> Cell1510   6.310529553  0.8827943   Mutant  1.3878705596
    -#> Cell1438   6.218522162  0.8822334   Mutant  1.3674526864
    -#> Cell322   -3.356956160  0.8238596       WT -0.7574950941
    -#> Cell1153   2.156117527  0.8574683   Mutant  0.4659418248
    -#> Cell393   -4.865024568  0.8146661       WT -1.0921589624
    -#> Cell922   -5.324163739  0.8118671       WT -1.1940490955
    -#> Cell1197   2.187650752  0.8576605   Mutant  0.4729395386
    -#> Cell862   -3.828964369  0.8209821       WT -0.8622410672
    -#> Cell487   -8.270615542  0.7939051       WT -1.8479126425
    -#> Cell211   -6.258158846  0.8061734       WT -1.4013171571
    -#> Cell1944   3.031898290  0.8628072   Mutant  0.6602912167
    -#> Cell1139   7.321685944  0.8889585   Mutant  1.6122619117
    -#> Cell1945   1.111526703  0.8511002   Mutant  0.2341308512
    -#> Cell1192   2.834216702  0.8616021   Mutant  0.6164225934
    -#> Cell1538   4.116599390  0.8694197   Mutant  0.9010032853
    -#> Cell1214   2.423492377  0.8590982   Mutant  0.5252764684
    -#> Cell1703   1.786449880  0.8552147   Mutant  0.3839068163
    -#> Cell563   -3.049524846  0.8257337       WT -0.6892712972
    -#> Cell1691   2.841200832  0.8616446   Mutant  0.6179724806
    -#> Cell779   -5.609980749  0.8101248       WT -1.2574763418
    -#> Cell1903   5.533058549  0.8780547   Mutant  1.2153376345
    -#> Cell333   -4.508183107  0.8168415       WT -1.0129702842
    -#> Cell1406   5.643447371  0.8787276   Mutant  1.2398346333
    -#> Cell513   -1.625009731  0.8344178       WT -0.3731492059
    -#> Cell1996   1.513606487  0.8535514   Mutant  0.3233586177
    -#> Cell3     -1.776181872  0.8334963       WT -0.4066966585
    -#> Cell82    -5.658418037  0.8098295       WT -1.2682253304
    -#> Cell1506   4.107172133  0.8693622   Mutant  0.8989112301
    -#> Cell909   -1.281301422  0.8365131       WT -0.2968749788
    -#> Cell1243   2.913179222  0.8620834   Mutant  0.6339456063
    -#> Cell1891   4.502614465  0.8717729   Mutant  0.9866660426
    -#> Cell1820   3.898603277  0.8680907   Mutant  0.8526265524
    -#> Cell1188   2.790112421  0.8613332   Mutant  0.6066351666
    -#> Cell373   -5.618769097  0.8100712       WT -1.2594266131
    -#> Cell187   -2.116925824  0.8314190       WT -0.4823130486
    -#> Cell1315   2.078345676  0.8569941   Mutant  0.4486830399
    -#> Cell941   -8.557644069  0.7921553       WT -1.9116087432
    -#> Cell291  -11.522235113  0.7740826       WT -2.5694976702
    -#> Cell403   -5.153906399  0.8129051       WT -1.1562663401
    -#> Cell1540   4.171761897  0.8697560   Mutant  0.9132447048
    -#> Cell979   -2.019439498  0.8320133       WT -0.4606793145
    -#> Cell1890   4.997894313  0.8747922   Mutant  1.0965763552
    -#> Cell588   -1.530208288  0.8349958       WT -0.3521112892
    -#> Cell1131   3.575455690  0.8661208   Mutant  0.7809150699
    -#> Cell1036   4.344174164  0.8708070   Mutant  0.9515056722
    -#> Cell372   -3.199534769  0.8248193       WT -0.7225608354
    -#> Cell1639   3.292804748  0.8643977   Mutant  0.7181904233
    -#> Cell1911   4.691621135  0.8729251   Mutant  1.0286095667
    -#> Cell304    0.375560576  0.8466137       WT  0.0708085047
    -#> Cell1221   6.697669433  0.8851543   Mutant  1.4737829288
    -#> Cell178   -3.881346936  0.8206628       WT -0.8738655747
    -#> Cell523   -7.890379642  0.7962230       WT -1.7635323741
    -#> Cell877   -2.711916185  0.8277919       WT -0.6143506769
    -#> Cell1871   4.390904619  0.8710919   Mutant  0.9618758879
    -#> Cell1600   5.104066503  0.8754395   Mutant  1.1201376177
    -#> Cell1858   5.744263723  0.8793422   Mutant  1.2622073522
    -#> Cell570   -3.217921776  0.8247072       WT -0.7266411988
    -#> Cell313   -4.136986857  0.8191044       WT -0.9305960549
    -#> Cell628   -3.189370529  0.8248812       WT -0.7203052324
    -#> Cell500   -7.090576888  0.8010988       WT -1.5860436857
    -#> Cell501   -2.930850404  0.8264572       WT -0.6629355901
    -#> Cell622   -3.458374349  0.8232413       WT -0.7800013698
    -#> Cell777   -1.352596436  0.8360785       WT -0.3126964528
    -#> Cell634   -6.896019834  0.8022848       WT -1.5428684453
    -#> Cell1585   5.450907404  0.8775539   Mutant  1.1971070157
    -#> Cell771   -1.004896259  0.8381982       WT -0.2355363679
    -#> Cell1029   4.628309224  0.8725392   Mutant  1.0145596675
    -#> Cell920   -3.197806294  0.8248298       WT -0.7221772599
    -#> Cell1712   1.904389462  0.8559337   Mutant  0.4100794464
    -#> Cell447   -1.107174071  0.8375747       WT -0.2582334075
    -#> Cell129  -11.844061352  0.7721207       WT -2.6409159252
    -#> Cell79    -2.924590923  0.8264954       WT -0.6615465137
    -#> Cell1497   3.874217958  0.8679421   Mutant  0.8472150704
    -#> Cell1684   3.338174956  0.8646743   Mutant  0.7282587791
    -#> Cell531   -8.479709885  0.7926304       WT -1.8943139340
    -#> Cell162   -2.949866410  0.8263413       WT -0.6671555379
    -#> Cell1989   1.791549835  0.8552458   Mutant  0.3850385757
    -#> Cell1349   4.322581676  0.8706754   Mutant  0.9467139629
    -#> Cell1075   5.444444181  0.8775145   Mutant  1.1956727259
    -#> Cell1060   4.870654104  0.8740165   Mutant  1.0683397709
    -#> Cell1801   1.995807872  0.8564910   Mutant  0.4303666156
    -#> Cell1028   5.046281051  0.8750872   Mutant  1.1073141259
    -#> Cell97     7.193236757  0.8881754       WT  1.5837570366
    -#> Cell161   -7.415454096  0.7991183       WT -1.6581389982
    -#> Cell1892   4.172627636  0.8697612   Mutant  0.9134368258
    -#> Cell1283   1.696793232  0.8546681   Mutant  0.3640106097
    -#> Cell1958   4.919009370  0.8743113   Mutant  1.0790705577
    -#> Cell1238   2.861059884  0.8617657   Mutant  0.6223795134
    -#> Cell191   -4.651417566  0.8159683       WT -1.0447562417
    -#> Cell1282   3.383313628  0.8649495   Mutant  0.7382757535
    -#> Cell1389   2.483951890  0.8594668   Mutant  0.5386933760
    -#> Cell1471   3.415747322  0.8651472   Mutant  0.7454732955
    -#> Cell844  -19.595295852  0.7248678       WT -4.3610355884
    -#> Cell1771   1.686081555  0.8546028   Mutant  0.3616335216
    -#> Cell12    -5.199826918  0.8126251       WT -1.1664568186
    -#> Cell827   -2.599653956  0.8284762       WT -0.5894379398
    -#> Cell176   -4.648930389  0.8159835       WT -1.0442042983
    -#> Cell1545   1.888876736  0.8558391   Mutant  0.4066369309
    -#> Cell422   -1.683599129  0.8340607       WT -0.3861511058
    -#> Cell230  -17.525291207  0.7374869       WT -3.9016693169
    -#> Cell1442   5.682652133  0.8789666   Mutant  1.2485347807
    -#> Cell1159   1.935234824  0.8561217   Mutant  0.4169245126
    -#> Cell930   -4.950147569  0.8141472       WT -1.1110490821
    -#> Cell670   -4.909241142  0.8143966       WT -1.1019713089
    -#> Cell369   -2.715543867  0.8277698       WT -0.6151557160
    -#> Cell1747   4.217433735  0.8700344   Mutant  0.9233799970
    -#> Cell707   -3.654020953  0.8220486       WT -0.8234183985
    -#> Cell1407   5.980624321  0.8807831   Mutant  1.3146594501
    -#> Cell1698   1.939626556  0.8561485   Mutant  0.4178991065
    -#> Cell1509   1.553196728  0.8537927   Mutant  0.3321443090
    -#> Cell690   -6.075247555  0.8072884       WT -1.3607262927
    -#> Cell64    -1.743308470  0.8336967       WT -0.3994015386
    -#> Cell794   -4.007670999  0.8198927       WT -0.9018988519
    -#> Cell1425   7.100449887  0.8876098   Mutant  1.5631661848
    -#> Cell1354   6.044345785  0.8811716   Mutant  1.3288002356
    -#> Cell595   -0.002082865  0.8443115       WT -0.0129964567
    -#> Cell323   -1.126546176  0.8374566       WT -0.2625323792
    -#> Cell1268   1.981964359  0.8564066   Mutant  0.4272945244
    -#> Cell274   -5.501315857  0.8107872       WT -1.2333619098
    -#> Cell558   -3.158194561  0.8250713       WT -0.7133867993
    -#> Cell1292   4.396207500  0.8711242   Mutant  0.9630526799
    -#> Cell1181   8.377765953  0.8953965   Mutant  1.8466225144
    -#> Cell35    -5.605459893  0.8101523       WT -1.2564730936
    -#> Cell477   -0.826269011  0.8392871       WT -0.1958961996
    -#> Cell450   -6.828779422  0.8026947       WT -1.5279467504
    -#> Cell258   -1.938741632  0.8325053       WT -0.4427712013
    -#> Cell1770   3.472923321  0.8654957   Mutant  0.7581615401
    -#> Cell1778   2.070509715  0.8569464   Mutant  0.4469441179
    -#> Cell1689   8.364137820  0.8953134   Mutant  1.8435982196
    -#> Cell1208   0.836188435  0.8494217   Mutant  0.1730290011
    -#> Cell1396   3.138847852  0.8634591   Mutant  0.6840249903
    -#> Cell1915   5.009858172  0.8748652   Mutant  1.0992313218
    -#> Cell90     0.283896208  0.8460549       WT  0.0504667538
    -#> Cell1590   6.228098815  0.8822918   Mutant  1.3695778948
    -#> Cell1327   0.332768685  0.8463528   Mutant  0.0613123176
    -#> Cell742   -2.084118258  0.8316190       WT -0.4750325388
    -#> Cell1807   0.096054819  0.8449097   Mutant  0.0087818239
    -#> Cell1378   3.167291617  0.8636325   Mutant  0.6903371046
    -#> Cell1954   5.827708934  0.8798509   Mutant  1.2807251441
    -#> Cell472   -2.709360668  0.8278074       WT -0.6137835680
    -#> Cell1737   3.209151725  0.8638877   Mutant  0.6996265147
    -#> Cell774   -9.726717519  0.7850284       WT -2.1710443504
    -#> Cell1039   6.053066366  0.8812247   Mutant  1.3307354682
    -#> Cell1955   4.538133273  0.8719894   Mutant  0.9945482195
    -#> Cell1912   5.827572565  0.8798501   Mutant  1.2806948818
    -#> Cell426   -2.136323274  0.8313008       WT -0.4866176449
    -#> Cell1916   2.767592369  0.8611959   Mutant  0.6016376162
    -#> Cell305   -3.229467840  0.8246368       WT -0.7292034502
    -#> Cell1646   3.497326159  0.8656445   Mutant  0.7635769099
    -#> Cell870   -1.415433341  0.8356955       WT -0.3266409408
    -#> Cell244   -4.554700673  0.8165579       WT -1.0232932567
    -#> Cell1400   4.581764369  0.8722554   Mutant  1.0042306391
    -#> Cell1398   2.880267289  0.8618828   Mutant  0.6266419358
    -#> Cell1037   1.628651600  0.8542527   Mutant  0.3488889202
    -#> Cell976   -4.902253161  0.8144392       WT -1.1004205670
    -#> Cell1942   3.309939046  0.8645021   Mutant  0.7219927911
    -#> Cell159   -0.907296085  0.8387931       WT -0.2138773693
    -#> Cell1511   3.600602589  0.8662741   Mutant  0.7864955584
    -#> Cell69   -10.783744585  0.7785846       WT -2.4056151199
    -#> Cell574   -4.716389216  0.8155722       WT -1.0591744628
    -#> Cell1789   6.472558800  0.8837820   Mutant  1.4238273731
    -#> Cell1167   3.331131994  0.8646313   Mutant  0.7266958363
    -#> Cell388   -2.395781716  0.8297191       WT -0.5441955143
    -#> Cell168   -7.060414690  0.8012827       WT -1.5793502242
    -#> Cell1840   1.570116051  0.8538959   Mutant  0.3358989703
    -#> Cell231   -6.066028263  0.8073446       WT -1.3586803882
    -#> Cell54     0.477695642  0.8472363       WT  0.0934738666
    -#> Cell625   -8.282924723  0.7938300       WT -1.8506442414
    -#> Cell213   -4.133438249  0.8191260       WT -0.9298085635
    -#> Cell1800   6.694701632  0.8851363   Mutant  1.4731243274
    -#> Cell1657   2.334848150  0.8585578   Mutant  0.5056049339
    -#> Cell309   -1.806024771  0.8333143       WT -0.4133192627
    -#> Cell194    0.392584287  0.8467174       WT  0.0745863314
    -#> Cell1263   3.763025960  0.8672642   Mutant  0.8225398341
    -#> Cell1236   0.051478216  0.8446380   Mutant -0.0011104187
    -#> Cell933   -2.774783073  0.8274086       WT -0.6283018186
    -#> Cell347   -4.785454481  0.8151512       WT -1.0745011208
    -#> Cell697   -5.651913343  0.8098691       WT -1.2667818376
    -#> Cell1180   3.228465425  0.8640055   Mutant  0.7039125255
    -#> Cell281   -6.187339699  0.8066051       WT -1.3856012854
    -#> Cell459    0.348688590  0.8464498       WT  0.0648451924
    -#> Cell1270   3.120614707  0.8633480   Mutant  0.6799787713
    -#> Cell1529   5.561813417  0.8782300   Mutant  1.2217187875
    -#> Cell1727   4.097341084  0.8693023   Mutant  0.8967295672
    -#> Cell994   -9.416685199  0.7869184       WT -2.1022433498
    -#> Cell1754   2.295328228  0.8583169   Mutant  0.4968348476
    -#> Cell245   -2.076642445  0.8316646       WT -0.4733735393
    -#> Cell399   -5.438963607  0.8111673       WT -1.2195249743
    -#> Cell433   -1.985159452  0.8322223       WT -0.4530720384
    -#> Cell698   -2.272651105  0.8304697       WT -0.5168709141
    -#> Cell1424   3.092832770  0.8631786   Mutant  0.6738135268
    -#> Cell366   -5.784738627  0.8090594       WT -1.2962578369
    -#> Cell1841   3.308432022  0.8644930   Mutant  0.7216583590
    -#> Cell1968   3.514428566  0.8657488   Mutant  0.7673722005
    -#> Cell1526   5.918065622  0.8804017   Mutant  1.3007767004
    -#> Cell312   -1.341651855  0.8361452       WT -0.3102676797
    -#> Cell671   -2.980140576  0.8261567       WT -0.6738738469
    -#> Cell674   -2.488876309  0.8291516       WT -0.5648546546
    -#> Cell392    3.146944234  0.8635085       WT  0.6858217034
    -#> Cell960   -0.666755602  0.8402595       WT -0.1604976896
    -#> Cell1966   1.313419499  0.8523310   Mutant  0.2789340072
    -#> Cell651   -4.463854353  0.8171117       WT -1.0031330432
    -#> Cell726   -6.072287799  0.8073065       WT -1.3600694768
    -#> Cell669   -8.142511210  0.7946860       WT -1.8194842961
    -#> Cell384   -0.113599631  0.8436317       WT -0.0377437640
    -#> Cell1796   3.494889994  0.8656296   Mutant  0.7630362871
    -#> Cell389   -6.606361623  0.8040506       WT -1.4785887767
    -#> Cell1804   3.630531831  0.8664565   Mutant  0.7931373233
    -#> Cell5     -9.328238740  0.7874576       WT -2.0826157029
    -#> Cell689   -1.154593327  0.8372856       WT -0.2687564790
    -#> Cell952   -1.434508344  0.8355792       WT -0.3308739809
    -#> Cell562   -0.252090924  0.8427874       WT -0.0684771391
    -#> Cell1960   2.263396534  0.8581222   Mutant  0.4897487075
    -#> Cell181  -10.233011078  0.7819420       WT -2.2833987767
    -#> Cell509   -5.880643738  0.8084747       WT -1.3175406747
    -#> Cell1539   5.923649080  0.8804358   Mutant  1.3020157567
    -#> Cell943   -6.044607666  0.8074752       WT -1.3539268241
    -#> Cell1930   2.855349890  0.8617309   Mutant  0.6211123770
    -#> Cell1330   4.440675958  0.8713953   Mutant  0.9729209233
    -#> Cell1633   2.869600964  0.8618178   Mutant  0.6242749123
    -#> Cell636   -4.479971775  0.8170135       WT -1.0067097503
    -#> Cell1844   4.018111892  0.8688193   Mutant  0.8791473755
    -#> Cell101   -0.613585933  0.8405837       WT -0.1486985119
    -#> Cell747   -9.706699153  0.7851504       WT -2.1666019632
    -#> Cell1788   5.821073911  0.8798105   Mutant  1.2792527292
    -#> Cell1478   4.942109471  0.8744521   Mutant  1.0841968297
    -#> Cell1318   0.350438524  0.8464605   Mutant  0.0652335301
    -#> Cell848   -6.573895618  0.8042486       WT -1.4713840645
    -#> Cell705   -1.264259584  0.8366170       WT -0.2930931294
    -#> Cell284    2.358416100  0.8587015       WT  0.5108350291
    -#> Cell1118   4.381234422  0.8710330   Mutant  0.9597299207
    -#> Cell1347   4.130869214  0.8695067   Mutant  0.9041699814
    -#> Cell105   -3.506896538  0.8229455       WT -0.7907691993
    -#> Cell155   -4.675025834  0.8158244       WT -1.0499952841
    -#> Cell785   -2.007245146  0.8320877       WT -0.4579731978
    -#> Cell648   -4.410303177  0.8174382       WT -0.9912492032
    -#> Cell446   -0.845093290  0.8391723       WT -0.2000736002
    -#> Cell1726  11.278718444  0.9130812   Mutant  2.4903890553
    -#> Cell123   -1.928198543  0.8325695       WT -0.4404315254
    -#> Cell866   -4.471697606  0.8170639       WT -1.0048735833
    -#> Cell249   -0.857219461  0.8390984       WT -0.2027645865
    -#> Cell1339   3.911760046  0.8681710   Mutant  0.8555462444
    -#> Cell921   -3.007083235  0.8259925       WT -0.6798528426
    -#> Cell519   -0.578933150  0.8407949       WT -0.1410085196
    -#> Cell797    0.653976559  0.8483109       WT  0.1325933478
    -#> Cell1552   1.916419391  0.8560070   Mutant  0.4127490752
    -#> Cell772   -3.498057273  0.8229994       WT -0.7888076288
    -#> Cell732   -6.250358776  0.8062209       WT -1.3995862000
    -#> Cell515    0.301787370  0.8461639       WT  0.0544370812
    -#> Cell992   -7.071853639  0.8012129       WT -1.5818887052
    -#> Cell337   -6.138042984  0.8069056       WT -1.3746615766
    -#> Cell86    -0.235834202  0.8428865       WT -0.0648695192
    -#> Cell869   -5.734908814  0.8093632       WT -1.2851998251
    -#> Cell748   -4.278770866  0.8182400       WT -0.9620601348
    -#> Cell864   -0.610364260  0.8406033       WT -0.1479835725
    -#> Cell1577   1.565861587  0.8538699   Mutant  0.3349548383
    -#> Cell404   -4.687260098  0.8157498       WT -1.0527102577
    -#> Cell538   -4.484420941  0.8169864       WT -1.0076970895
    -#> Cell945   -1.874991598  0.8328939       WT -0.4286240757
    -#> Cell197   -5.139934275  0.8129902       WT -1.1531657081
    -#> Cell34    -2.016121287  0.8320336       WT -0.4599429518
    -#> Cell845   -5.302508710  0.8119992       WT -1.1892435074
    -#> Cell1335   2.238092739  0.8579680   Mutant  0.4841334012
    -#> Cell1437   4.697112439  0.8729586   Mutant  1.0298281725
    -#> Cell1296   3.300300561  0.8644434   Mutant  0.7198538610
    -#> Cell158   -2.011055374  0.8320644       WT -0.4588187468
    -#> Cell759   -4.836694538  0.8148388       WT -1.0858720874
    -#> Cell831    0.512309634  0.8474473       WT  0.1011552507
    -#> Cell1468   3.555120804  0.8659968   Mutant  0.7764024418
    -#> Cell339   -4.157260920  0.8189808       WT -0.9350951852
    -#> Cell561   -5.958783807  0.8079984       WT -1.3348811730
    -#> Cell121   -5.873042940  0.8085211       WT -1.3158539393
    -#> Cell1826   3.305104394  0.8644727   Mutant  0.7209199065
    -#> Cell1344   2.517353860  0.8596704   Mutant  0.5461057934
    -#> Cell1674   2.133559587  0.8573307   Mutant  0.4609358665
    -#> Cell225   -2.907183774  0.8266015       WT -0.6576835962
    -#> Cell1793   1.916956072  0.8560103   Mutant  0.4128681729
    -#> Cell1837   4.501838485  0.8717682   Mutant  0.9864938406
    -#> Cell534   -2.841560517  0.8270015       WT -0.6431207733
    -#> Cell401  -15.973009309  0.7469499       WT -3.5571937863
    -#> Cell10    -2.457010617  0.8293458       WT -0.5577831612
    -#> Cell1584   3.302191137  0.8644549   Mutant  0.7202734093
    -#> Cell179    0.959640189  0.8501743       WT  0.2004248680
    -#> Cell503   -1.910114193  0.8326798       WT -0.4364183265
    -#> Cell1087   2.476127802  0.8594191   Mutant  0.5369570892
    -#> Cell751   -3.933876538  0.8203426       WT -0.8855227117
    -#> Cell1792   3.923161454  0.8682405   Mutant  0.8580763944
    -#> Cell1248   5.915112493  0.8803837   Mutant  1.3001213552
    -#> Cell1146   1.165036165  0.8514264   Mutant  0.2460054342
    -#> Cell1076   2.289754464  0.8582829   Mutant  0.4955979427
    -#> Cell378   -0.434472771  0.8416756       WT -0.1089505115
    -#> Cell757   -9.442341995  0.7867620       WT -2.1079369923
    -#> Cell805    5.533783697  0.8780591       WT  1.2154985560
    -#> Cell1614   2.392536987  0.8589095   Mutant  0.5184069852
    -#> Cell838  -12.016536703  0.7710693       WT -2.6791908919
    -#> Cell1670   0.857919638  0.8495542   Mutant  0.1778514934
    -#> Cell1113   6.667042558  0.8849676   Mutant  1.4669863481
    -#> Cell718    2.008210082  0.8565666       WT  0.4331188591
    -#> Cell1630   3.222509774  0.8639692   Mutant  0.7025908739
    -#> Cell640    0.287690332  0.8460780       WT  0.0513087290
    -#> Cell496   -7.002914099  0.8016332       WT -1.5665899476
    -#> Cell1331   4.031490958  0.8689009   Mutant  0.8821163986
    -#> Cell1547   3.497787304  0.8656473   Mutant  0.7636792451
    -#> Cell1847   6.175221217  0.8819694   Mutant  1.3578435323
    -#> Cell1865   2.759220547  0.8611449   Mutant  0.5997797785
    -#> Cell439   -0.981485161  0.8383409       WT -0.2303410808
    -#> Cell1495   3.037720740  0.8628427   Mutant  0.6615833089
    -#> Cell820   -6.764885772  0.8030843       WT -1.5137677545
    -#> Cell1078   5.815488593  0.8797764   Mutant  1.2780132600
    -#> Cell1166   2.632684939  0.8603735   Mutant  0.5716995563
    -#> Cell1138  -0.413339024  0.8418044   Mutant -0.1042606038
    -#> Cell1199   0.485094313  0.8472814   Mutant  0.0951157470
    -#> Cell1898   8.128245380  0.8938754   Mutant  1.7912500130
    -#> Cell55    -0.249797289  0.8428014       WT -0.0679681456
    -#> Cell1412   4.684050355  0.8728790   Mutant  1.0269294927
    -#> Cell81    -4.347717448  0.8178197       WT -0.9773604553
    -#> Cell1797   3.839513969  0.8677305   Mutant  0.8395137147
    -#> Cell267   -1.569615474  0.8347555       WT -0.3608563574
    -#> Cell1709   7.858539682  0.8922312   Mutant  1.7313981179
    -#> Cell1563   3.111449771  0.8632921   Mutant  0.6779449294
    -#> Cell1017   3.014114350  0.8626988   Mutant  0.6563446833
    -#> Cell238   -7.829027394  0.7965971       WT -1.7499173547
    -#> Cell802   -1.272071136  0.8365694       WT -0.2948266345
    -#> Cell286    5.631363589  0.8786540       WT  1.2371530539
    -#> Cell1842   4.937514514  0.8744241   Mutant  1.0831771373
    -#> Cell1351   3.262225940  0.8642113   Mutant  0.7114045097
    -#> Cell202   -4.655745848  0.8159419       WT -1.0457167548
    -#> Cell119   -4.197567149  0.8187351       WT -0.9440397653
    -#> Cell1366   2.958401708  0.8623591   Mutant  0.6439811805
    -#> Cell825    0.771298130  0.8490262       WT  0.1586288316
    -#> Cell1854   5.331843552  0.8768280   Mutant  1.1706848926
    -#> Cell1420   1.160349437  0.8513979   Mutant  0.2449653762
    -#> Cell257   -6.367491264  0.8055068       WT -1.4255797234
    -#> Cell1593   4.981783664  0.8746940   Mutant  1.0930011512
    -#> Cell1232   2.557334742  0.8599141   Mutant  0.5549781739
    -#> Cell985    1.443609047  0.8531247       WT  0.3078250955
    -#> Cell204   -4.073165032  0.8194935       WT -0.9164329979
    -#> Cell1357   3.756377057  0.8672237   Mutant  0.8210643391
    -#> Cell1481   2.346220208  0.8586272   Mutant  0.5081285706
    -#> Cell1592   2.091353672  0.8570734   Mutant  0.4515697167
    -#> Cell1618   4.846298215  0.8738681   Mutant  1.0629348197
    -#> Cell1549   3.694010834  0.8668435   Mutant  0.8072243028
    -#> Cell514   -1.222313732  0.8368727       WT -0.2837846915
    -#> Cell734   -4.230782413  0.8185326       WT -0.9514107496
    -#> Cell1053   4.239386963  0.8701682   Mutant  0.9282517601
    -#> Cell1768   5.093900304  0.8753775   Mutant  1.1178815799
    -#> Cell1184   5.873788282  0.8801318   Mutant  1.2909508691
    -#> Cell699   -6.860772268  0.8024997       WT -1.5350464613
    -#> Cell573   -2.998000817  0.8260478       WT -0.6778373126
    -#> Cell978   -0.825042535  0.8392946       WT -0.1956240254
    -#> Cell1015   2.838582416  0.8616287   Mutant  0.6173914132
    -#> Cell92    -2.264823163  0.8305174       WT -0.5151337717
    -#> Cell821   -4.883402919  0.8145541       WT -1.0962374047
    -#> Cell1241   2.638256338  0.8604075   Mutant  0.5729359364
    -#> Cell1609   4.262184280  0.8703072   Mutant  0.9333108398
    -#> Cell663   -3.892971273  0.8205919       WT -0.8764451962
    -#> Cell1088   7.047852539  0.8872891   Mutant  1.5514940142
    -#> Cell1973   4.555069329  0.8720927   Mutant  0.9983065939
    -#> Cell1690   4.916967811  0.8742989   Mutant  1.0786175038
    -#> Cell1685   2.508357170  0.8596156   Mutant  0.5441092878
    -#> Cell38    -4.802609816  0.8150466       WT -1.0783081567
    -#> Cell1702   2.685913957  0.8606980   Mutant  0.5835119045
    -#> Cell1038   3.944102297  0.8683681   Mutant  0.8627234937
    -#> Cell405   -3.118423743  0.8253137       WT -0.7045610355
    -#> Cell1104   4.255657939  0.8702674   Mutant  0.9318625433
    -#> Cell276   -1.879459448  0.8328667       WT -0.4296155612
    -#> Cell502    2.357720885  0.8586973       WT  0.5106807501
    -#> Cell1306   1.498045396  0.8534565   Mutant  0.3199053693
    -#> Cell730   -6.648068340  0.8037964       WT -1.4878441467
    -#> Cell1179   0.542483744  0.8476313   Mutant  0.1078513555
    -#> Cell1483   3.296510953  0.8644203   Mutant  0.7190128880
    -#> Cell1818   4.941171184  0.8744464   Mutant  1.0839886093
    -#> Cell1156   2.282823330  0.8582407   Mutant  0.4940598160
    -#> Cell1634   3.256197475  0.8641745   Mutant  0.7100666993
    -#> Cell1399  -1.224704043  0.8368582   Mutant -0.2843151389
    -#> Cell174   -3.911275428  0.8204804       WT -0.8805071732
    -#> Cell655   -0.105159505  0.8436831       WT -0.0358707686
    -#> Cell1528   3.219727649  0.8639522   Mutant  0.7019734770
    -#> Cell1561   3.923816362  0.8682445   Mutant  0.8582217288
    -#> Cell719   -6.068007098  0.8073325       WT -1.3591195225
    -#> Cell616   -1.966781678  0.8323343       WT -0.4489937242
    -#> Cell1628   4.043549181  0.8689744   Mutant  0.8847923060
    -#> Cell596   -0.434203241  0.8416772       WT -0.1088906987
    -#> Cell850   -5.714969234  0.8094847       WT -1.2807749219
    -#> Cell632   -3.043692806  0.8257693       WT -0.6879770767
    -#> Cell215   -4.442662286  0.8172409       WT -0.9984301936
    -#> Cell1814   5.328387744  0.8768070   Mutant  1.1699179951
    -#> Cell71    -1.661453976  0.8341957       WT -0.3812367514
    -#> Cell44    -9.462636505  0.7866383       WT -2.1124406602
    -#> Cell600   -0.657884472  0.8403136       WT -0.1585290477
    -#> Cell1249   2.122742589  0.8572648   Mutant  0.4585354063
    -#> Cell185   -3.840412020  0.8209124       WT -0.8647814792
    -#> Cell1463   5.337363616  0.8768617   Mutant  1.1719098808
    -#> Cell150   -6.804774843  0.8028411       WT -1.5226197606
    -#> Cell1856   4.937359112  0.8744232   Mutant  1.0831426513
    -#> Cell1928   2.186462900  0.8576532   Mutant  0.4726759357
    -#> Cell1723   3.806163697  0.8675272   Mutant  0.8321127699
    -#> Cell788   -4.225321038  0.8185659       WT -0.9501987856
    -#> Cell1649   3.548653523  0.8659574   Mutant  0.7749672514
    -#> Cell182   -2.299215831  0.8303078       WT -0.5227660404
    -#> Cell186   -3.682899415  0.8218726       WT -0.8298269789
    -#> Cell1175   3.283676794  0.8643420   Mutant  0.7161647882
    -#> Cell535   -0.368924616  0.8420752       WT -0.0944043549
    -#> Cell630   -4.594423424  0.8163158       WT -1.0321083539
    -#> Cell1082   2.156868601  0.8574728   Mutant  0.4661084997
    -#> Cell237   -3.690336667  0.8218272       WT -0.8314774211
    -#> Cell1503   4.310370328  0.8706010   Mutant  0.9440040744
    -#> Cell443   -0.324802234  0.8423441       WT -0.0846129111
    -#> Cell857   -3.880601023  0.8206674       WT -0.8737000451
    -#> Cell1376   3.932055418  0.8682947   Mutant  0.8600501036
    -#> Cell318   -3.061130343  0.8256630       WT -0.6918467377
    -#> Cell510    0.765787924  0.8489926       WT  0.1574060311
    -#> Cell1575   5.870996927  0.8801148   Mutant  1.2903314240
    -#> Cell8     -0.304597995  0.8424673       WT -0.0801292760
    -#> Cell1050   3.437409677  0.8652792   Mutant  0.7502805094
    -#> Cell70    -7.522571206  0.7984653       WT -1.6819099534
    -#> Cell1191   6.697020780  0.8851504   Mutant  1.4736389826
    -#> Cell1365   1.299194555  0.8522443   Mutant  0.2757772704
    -#> Cell1535   2.602376773  0.8601887   Mutant  0.5649737020
    -#> Cell338  -15.146998782  0.7519854       WT -3.3738891850
    -#> Cell1474   5.709286335  0.8791290   Mutant  1.2544453249
    -#> Cell929   -0.096022094  0.8437388       WT -0.0338430349
    -#> Cell1957   5.910271530  0.8803542   Mutant  1.2990470701
    -#> Cell657   -5.234651627  0.8124128       WT -1.1741849637
    -#> Cell1041   5.848269129  0.8799763   Mutant  1.2852877715
    -#> Cell1032   3.445563166  0.8653289   Mutant  0.7520898956
    -#> Cell200   -3.487177239  0.8230657       WT -0.7863931796
    -#> Cell912   -0.548781531  0.8409787       WT -0.1343174057
    -#> Cell253   -3.692693653  0.8218129       WT -0.8320004728
    -#> Cell461   -4.353326438  0.8177855       WT -0.9786051774
    -#> Cell1434   2.771523319  0.8612199   Mutant  0.6025099552
    -#> Cell247   -1.183339152  0.8371103       WT -0.2751356252
    -#> Cell147   -7.986962962  0.7956343       WT -1.7849657170
    -#> Cell412   -1.876144378  0.8328869       WT -0.4288798955
    -#> Cell216   -3.843652752  0.8208926       WT -0.8655006482
    -#> Cell687   -7.574808814  0.7981468       WT -1.6935022922
    -#> Cell592   -5.602448440  0.8101707       WT -1.2558048050
    -#> Cell172   -0.700530565  0.8400536       WT -0.1679928800
    -#> Cell1713   2.800926897  0.8613991   Mutant  0.6090350670
    -#> Cell84    -3.900975245  0.8205432       WT -0.8782214023
    -#> Cell728   -0.946714024  0.8385528       WT -0.2226248237
    -#> Cell1361   3.992385055  0.8686625   Mutant  0.8734381896
    -#> Cell1556   2.952236597  0.8623215   Mutant  0.6426130462
    -#> Cell1423   3.268933216  0.8642522   Mutant  0.7128929586
    -#> Cell7     -4.512267255  0.8168166       WT -1.0138766204
    -#> Cell352   -6.976907391  0.8017917       WT -1.5608186539
    -#> Cell1301   2.082096703  0.8570170   Mutant  0.4495154510
    -#> Cell248   -2.039951089  0.8318883       WT -0.4652311561
    -#> Cell783   -2.020710565  0.8320056       WT -0.4609613841
    -#> Cell356   -0.647599640  0.8403763       WT -0.1562466832
    -#> Cell549    0.191741079  0.8454931       WT  0.0300160953
    -#> Cell1     -0.107054702  0.8436716       WT -0.0362913423
    -#> Cell1086   2.239439761  0.8579762   Mutant  0.4844323263
    -#> Cell1982   0.904694276  0.8498394   Mutant  0.1882315142
    -#> Cell27    -4.733010792  0.8154709       WT -1.0628630494
    -#> Cell146    0.386096149  0.8466779       WT  0.0731465125
    -#> Cell329   -3.813459634  0.8210767       WT -0.8588003250
    -#> Cell1355   4.091853076  0.8692688   Mutant  0.8955116927
    -#> Cell1877   3.841473281  0.8677425   Mutant  0.8399485165
    -#> Cell130   -8.159772525  0.7945808       WT -1.8233148506
    -#> Cell299  -11.211894351  0.7759745       WT -2.5006282214
    -#> Cell80    -2.002774724  0.8321149       WT -0.4569811416
    -#> Cell852   -1.841001384  0.8331011       WT -0.4210811178
    -#> Cell1564   2.278426288  0.8582139   Mutant  0.4930840439
    -#> Cell525   -2.090867429  0.8315779       WT -0.4765302848
    -#> Cell907   -3.957329759  0.8201996       WT -0.8907273466
    -#> Cell140   -3.687203097  0.8218463       WT -0.8307820330
    -#> Cell1204   2.628264823  0.8603465   Mutant  0.5707186636
    -#> Cell141   -2.163523772  0.8311350       WT -0.4926538591
    -#> Cell153   -3.890934343  0.8206044       WT -0.8759931696
    -#> Cell1012   2.441325816  0.8592069   Mutant  0.5292339864
    -#> Cell287    1.351415210  0.8525626       WT  0.2873658471
    -#> Cell67    -6.091039863  0.8071921       WT -1.3642308519
    -#> Cell1779  11.205401994  0.9126343   Mutant  2.4741189933
    -#> Cell2000   4.809645318  0.8736446   Mutant  1.0548009711
    -#> Cell1739   2.102815098  0.8571433   Mutant  0.4541131857
    -#> Cell212   -3.941065303  0.8202988       WT -0.8871180106
    -#> Cell981    1.105003320  0.8510605       WT  0.2326832109
    -#> Cell955   -3.931901011  0.8203546       WT -0.8850843113
    -#> Cell1774   4.899100023  0.8741900   Mutant  1.0746523634
    -#> Cell1276   2.864828802  0.8617887   Mutant  0.6232158951
    -#> Cell741   -3.659584090  0.8220147       WT -0.8246529453
    -#> Cell1151   3.697735589  0.8668662   Mutant  0.8080508839
    -#> Cell1508   5.196014403  0.8760000   Mutant  1.1405422888
    -#> Cell1967   5.426419751  0.8774046   Mutant  1.1916728243
    -#> Cell1798   3.854174338  0.8678199   Mutant  0.8427670789
    -#> Cell743   -4.132134921  0.8191340       WT -0.9295193347
    -#> Cell269   -3.404979663  0.8235668       WT -0.7681522572
    -#> Cell766   -0.511977715  0.8412031       WT -0.1261500657
    -#> Cell1368   4.464678767  0.8715416   Mutant  0.9782475204
    -#> Cell280   -2.240158256  0.8306678       WT -0.5096602446
    -#> Cell1533   2.335499603  0.8585618   Mutant  0.5057495015
    -#> Cell1959   5.046188530  0.8750866   Mutant  1.1072935942
    -#> Cell721   -1.009087588  0.8381726       WT -0.2364664892
    -#> Cell438    0.480742983  0.8472549       WT  0.0941501192
    -#> Cell414   -8.182011529  0.7944452       WT -1.8282500321
    -#> Cell1742   3.337452450  0.8646699   Mutant  0.7280984439
    -#> Cell1895   6.660880586  0.8849301   Mutant  1.4656189107
    -#> Cell715   -4.774182621  0.8152199       WT -1.0719997194
    -#> Cell964   -4.188391126  0.8187910       WT -0.9420034628
    -#> Cell1937   2.620327334  0.8602982   Mutant  0.5689572113
    -#> Cell1909   3.797071720  0.8674718   Mutant  0.8300951186
    -#> Cell436   -1.509922807  0.8351194       WT -0.3476096250
    -#> Cell205   -7.265008462  0.8000354       WT -1.6247527689
    -#> Cell1929  -0.042900280  0.8440627   Mutant -0.0220544769
    -#> Cell96    -5.454876388  0.8110703       WT -1.2230562684
    -#> Cell1097   4.557561353  0.8721079   Mutant  0.9988596129
    -#> Cell1952   1.344951377  0.8525232   Mutant  0.2859314220
    -#> Cell796   -6.795746005  0.8028961       WT -1.5206161207
    -#> Cell1812   2.598353345  0.8601642   Mutant  0.5640808409
    -#> Cell1489   3.370765004  0.8648730   Mutant  0.7354910184
    -#> Cell731  -11.866909026  0.7719814       WT -2.6459861799
    -#> Cell1477   1.993907370  0.8564794   Mutant  0.4299448645
    -#> Cell246   -1.865185610  0.8329537       WT -0.4264479742
    -#> Cell330   -6.317147993  0.8058137       WT -1.4144077677
    -#> Cell290   -6.467835888  0.8048951       WT -1.4478477585
    -#> Cell319   -2.812208055  0.8271805       WT -0.6366070049
    -#> Cell1594   3.303990834  0.8644659   Mutant  0.7206727900
    -#> Cell1066   3.789751421  0.8674272   Mutant  0.8284706302
    -#> Cell1565   4.140733883  0.8695668   Mutant  0.9063591051
    -#> Cell321   -5.952137758  0.8080389       WT -1.3334063113
    -#> Cell1310   4.007849362  0.8687567   Mutant  0.8768699603
    -#> Cell1857   3.677443408  0.8667425   Mutant  0.8035477328
    -#> Cell1466   1.497820629  0.8534552   Mutant  0.3198554900
    -#> Cell1290   7.713513930  0.8913471   Mutant  1.6992146446
    -#> Cell891   -9.507693092  0.7863636       WT -2.1224394187
    -#> Cell1439   0.888140462  0.8497384   Mutant  0.1845579649
    -#> Cell904   -8.792506443  0.7907235       WT -1.9637283621
    -#> Cell368    1.999551465  0.8565138       WT  0.4311973771
    -#> Cell406   -5.014502823  0.8137549       WT -1.1253305152
    -#> Cell1340   3.891763634  0.8680491   Mutant  0.8511087292
    -#> Cell1150  13.801782678  0.9284623   Mutant  3.0502963064
    -#> Cell896   -0.638106593  0.8404342       WT -0.1541400283
    -#> Cell923   -4.207263189  0.8186760       WT -0.9461914675
    -#> Cell1864   5.315059251  0.8767257   Mutant  1.1669601948
    -#> Cell586   -6.309901734  0.8058579       WT -1.4127997098
    -#> Cell1707   0.074636562  0.8447792   Mutant  0.0040287791
    -#> Cell491   -2.693671957  0.8279031       WT -0.6103019986
    -#> Cell195   -7.220082577  0.8003093       WT -1.6147830151
    -#> Cell298   -3.485522881  0.8230758       WT -0.7860260518
    -#> Cell435   -4.820986517  0.8149346       WT -1.0823862328
    -#> Cell544   -2.414924239  0.8296024       WT -0.5484435382
    -#> Cell219   -6.825234587  0.8027164       WT -1.5271600965
    -#> Cell1637   4.470324918  0.8715761   Mutant  0.9795004893
    -#> Cell1644   4.927562871  0.8743635   Mutant  1.0809687127
    -#> Cell512   -8.234125005  0.7941275       WT -1.8398148240
    -#> Cell1799   3.653702774  0.8665978   Mutant  0.7982793166
    -#> Cell1202   1.969328716  0.8563296   Mutant  0.4244904783
    -#> Cell1664   4.272083815  0.8703676   Mutant  0.9355077009
    -#> Cell1636   0.047189952  0.8446119   Mutant -0.0020620512
    -#> Cell1062   7.118596954  0.8877204   Mutant  1.5671933016
    -#> Cell1934   2.884439163  0.8619082   Mutant  0.6275677396
    -#> Cell895   -6.013831173  0.8076628       WT -1.3470970410
    -#> Cell1269  -0.180215718  0.8432256   Mutant -0.0525269113
    -#> Cell1893   2.043078344  0.8567791   Mutant  0.4408566695
    -#> Cell493   -2.003233683  0.8321121       WT -0.4570829918
    -#> Cell1005   5.166262202  0.8758186   Mutant  1.1339398120
    -#> Cell1030   7.450965445  0.8897466   Mutant  1.6409510466
    -#> Cell402   -8.028658424  0.7953801       WT -1.7942185896
    -#> Cell1543   4.527435653  0.8719242   Mutant  0.9921742510
    -#> Cell1708   2.704543243  0.8608116   Mutant  0.5876460330
    -#> Cell271   -2.534469428  0.8288736       WT -0.5749724776
    -#> Cell1962   1.972807331  0.8563508   Mutant  0.4252624373
    -#> Cell250   -4.339542254  0.8178696       WT -0.9755462522
    -#> Cell934   -4.184356103  0.8188156       WT -0.9411080283
    -#> Cell170   -7.342755192  0.7995615       WT -1.6420059792
    -#> Cell285   -4.128973476  0.8191532       WT -0.9288177608
    -#> Cell594   -2.657656854  0.8281226       WT -0.6023096863
    -#> Cell387   -7.790524417  0.7968318       WT -1.7413729444
    -#> Cell108   -8.473636598  0.7926674       WT -1.8929661770
    -#> Cell1550   5.102070733  0.8754273   Mutant  1.1196947254
    -#> Cell1127   3.357788690  0.8647938   Mutant  0.7326113723
    -#> Cell564   -5.331258960  0.8118239       WT -1.1956236356
    -#> Cell1570   4.885413078  0.8741065   Mutant  1.0716150172
    -#> Cell1514   5.461089402  0.8776159   Mutant  1.1993665599
    -#> Cell343   -2.900191558  0.8266441       WT -0.6561319146
    -#> Cell942    0.436128551  0.8469829       WT  0.0842494817
    -#> Cell1947   2.093310352  0.8570854   Mutant  0.4520039345
    -#> Cell1721   6.592623540  0.8845140   Mutant  1.4504716090
    -#> Cell1317   6.142486147  0.8817699   Mutant  1.3505791104
    -#> Cell1102   4.412786733  0.8712253   Mutant  0.9667318699
    -#> Cell1210   1.988900748  0.8564489   Mutant  0.4288338171
    -#> Cell166   -5.634598522  0.8099747       WT -1.2629394090
    -#> Cell1433   3.873284033  0.8679364   Mutant  0.8470078179
    -#> Cell1616   7.444284058  0.8897058   Mutant  1.6394683428
    -#> Cell308    0.587252314  0.8479042       WT  0.1177861985
    -#> Cell786    0.411824937  0.8468347       WT  0.0788561312
    -#> Cell633   -1.760604197  0.8335912       WT -0.4032397298
    -#> Cell1610   4.734750792  0.8731881   Mutant  1.0381807092
    -#> Cell1846   2.936437911  0.8622252   Mutant  0.6391070718
    -#> Cell1748   4.196021005  0.8699039   Mutant  0.9186281787
    -#> Cell1787   3.088023745  0.8631493   Mutant  0.6727463293
    -#> Cell1090   2.802675210  0.8614098   Mutant  0.6094230449
    -#> Cell946   -0.069055666  0.8439032       WT -0.0278587645
    -#> Cell675   -2.847705918  0.8269641       WT -0.6444845337
    -#> Cell1040   4.634879733  0.8725792   Mutant  1.0160177659
    -#> Cell1457   3.443685315  0.8653175   Mutant  0.7516731712
    -#> Cell1750   5.260675022  0.8763942   Mutant  1.1548914873
    -#> Cell1035   3.441518042  0.8653043   Mutant  0.7511922196
    -#> Cell1410   2.791399923  0.8613410   Mutant  0.6069208832
    -#> Cell189   -2.193527953  0.8309521       WT -0.4993122542
    -#> Cell1352   2.551763488  0.8598802   Mutant  0.5537418258
    -#> Cell233   -5.731860493  0.8093818       WT -1.2845233552
    -#> Cell1132   5.564067008  0.8782437   Mutant  1.2222188945
    -#> Cell83    -4.606530880  0.8162420       WT -1.0347951869
    -#> Cell1245   2.669523844  0.8605981   Mutant  0.5798746830
    -#> Cell118   -4.142007167  0.8190738       WT -0.9317101399
    -#> Cell1896   5.243042440  0.8762867   Mutant  1.1509785427
    -#> Cell1227   2.922139709  0.8621381   Mutant  0.6359340781
    -#> Cell363   -2.497783954  0.8290973       WT -0.5668313997
    -#> Cell441   -1.330214336  0.8362150       WT -0.3077295163
    -#> Cell1943   6.527309502  0.8841158   Mutant  1.4359774066
    -#> Cell556   -5.257318024  0.8122747       WT -1.1792149904
    -#> Cell1224   2.684644622  0.8606902   Mutant  0.5832302192
    -#> Cell610   -8.742003279  0.7910314       WT -1.9525209233
    -#> Cell1772   4.911765113  0.8742672   Mutant  1.0774629441
    -#> Cell1257   3.655495292  0.8666087   Mutant  0.7986771041
    -#> Cell131    1.775726163  0.8551493       WT  0.3815270565
    -#> Cell1083   3.119370789  0.8633404   Mutant  0.6797027265
    -#> Cell1843   4.714858893  0.8730668   Mutant  1.0337663871
    -#> Cell727   -5.776191894  0.8091115       WT -1.2943611837
    -#> Cell1336   1.946799090  0.8561922   Mutant  0.4194908034
    -#> Cell637   -1.180422928  0.8371281       WT -0.2744884696
    -#> Cell631   -8.340915786  0.7934765       WT -1.8635133615
    -#> Cell1220   4.250463399  0.8702358   Mutant  0.9307097938
    -#> Cell1583   5.480167994  0.8777322   Mutant  1.2036003965
    -#> Cell1065   3.442988386  0.8653132   Mutant  0.7515185118
    -#> Cell120   -0.416530275  0.8417849       WT -0.1049687922
    -#> Cell603    0.662037856  0.8483601       WT  0.1343822752
    -#> Cell325   -1.676620159  0.8341032       WT -0.3846023637
    -#> Cell1415   5.669698521  0.8788877   Mutant  1.2456601725
    -#> Cell1988   5.251090385  0.8763357   Mutant  1.1527645071
    -#> Cell1256   4.848306950  0.8738803   Mutant  1.0633805894
    -#> Cell1091   2.801564190  0.8614030   Mutant  0.6091764924
    -#> Cell1677   2.107118726  0.8571695   Mutant  0.4550682276
    -#> Cell1541   4.470636583  0.8715780   Mutant  0.9795696526
    -#> Cell608   -3.181663465  0.8249282       WT -0.7185949147
    -#> Cell1293   2.612561519  0.8602508   Mutant  0.5672338559
    -#> Cell409   -2.757316002  0.8275151       WT -0.6244256034
    -#> Cell1995   0.408265379  0.8468130   Mutant  0.0780662100
    -#> Cell548   -2.900026560  0.8266451       WT -0.6560952989
    -#> Cell824   -0.683106243  0.8401598       WT -0.1641261515
    -#> Cell863   -4.569219152  0.8164694       WT -1.0265151332
    -#> Cell1505   3.408884325  0.8651053   Mutant  0.7439502896
    -#> Cell1515   7.026530867  0.8871591   Mutant  1.5467624031
    -#> Cell571   -3.834966797  0.8209456       WT -0.8635730995
    -#> Cell75    -2.210378067  0.8308493       WT -0.5030515568
    -#> Cell832  -10.928986512  0.7776992       WT -2.4378465657
    -#> Cell585    0.605540123  0.8480157       WT  0.1218445482
    -#> Cell467   -5.588367502  0.8102565       WT -1.2526800256
    -#> Cell1751   3.052341956  0.8629318   Mutant  0.6648279847
    -#> Cell410    0.517561592  0.8474793       WT  0.1023207419
    -#> Cell1168   3.653922146  0.8665991   Mutant  0.7983279986
    -#> Cell1922   2.890512331  0.8619453   Mutant  0.6289154702
    -#> Cell444   -5.354371560  0.8116830       WT -1.2007526816
    -#> Cell701    1.541114535  0.8537191       WT  0.3294630821
    -#> Cell1935   3.575983681  0.8661240   Mutant  0.7810322393
    -#> Cell46    -0.226588314  0.8429429       WT -0.0628177126
    -#> Cell539   -6.001406475  0.8077386       WT -1.3443398069
    -#> Cell1356   1.356056344  0.8525909   Mutant  0.2883957872
    +
    scale
    +

    Z-scored pathway activity across all cells.

    + +
    +

    The grouping variable, named after the group argument.

    + + +
    + +
    +

    Examples

    +
    if (FALSE) { # \dontrun{
    +# Using a plain metadata data frame
    +plotdata <- PreparePlotData(metadata_df, scores, "genotype")
    +
    +# Using a Seurat object
    +plotdata <- PreparePlotData(seurat_obj, scores, "orig.ident", Seurat.object = TRUE)
    +} # }
    +
     
    -
    - -
    +
    -
    - +
    diff --git a/docs/reference/PreparePlotData.md b/docs/reference/PreparePlotData.md new file mode 100644 index 0000000..67569b2 --- /dev/null +++ b/docs/reference/PreparePlotData.md @@ -0,0 +1,65 @@ +# PreparePlotData + +Prepares a tidy data frame of pathway activity scores per cell for +downstream plotting with +[`PlotPathway()`](https://raredonlab.github.io/PathwayEmbed/reference/PlotPathway.md) +or +[`CalculatePercentage()`](https://raredonlab.github.io/PathwayEmbed/reference/CalculatePercentage.md). +Accepts either a plain metadata data frame or a Seurat object. + +## Usage + +``` r +PreparePlotData(x, score, group, Seurat.object = FALSE) +``` + +## Arguments + +- x: + + A metadata data frame (rows = cells, columns = metadata fields) or a + Seurat object. Must contain the column specified by `group`. + +- score: + + A named numeric vector of per-cell scores from + [`ComputeCellData()`](https://raredonlab.github.io/PathwayEmbed/reference/ComputeCellData.md). + Names must be cell IDs matching rownames of `x`. + +- group: + + A character string giving the column name in `x` metadata to use for + grouping (e.g. `"genotype"`, `"Age"`). + +- Seurat.object: + + Logical; set `TRUE` if `x` is a Seurat object. Default `FALSE`. + +## Value + +A data frame with one row per cell and three columns: + +- normalized: + + Normalized pathway activity score in \[0, 1\]\\ from + [`ComputeCellData()`](https://raredonlab.github.io/PathwayEmbed/reference/ComputeCellData.md). + +- scale: + + Z-scored pathway activity across all cells. + +- : + + The grouping variable, named after the `group` argument. + +## Examples + +``` r +if (FALSE) { # \dontrun{ +# Using a plain metadata data frame +plotdata <- PreparePlotData(metadata_df, scores, "genotype") + +# Using a Seurat object +plotdata <- PreparePlotData(seurat_obj, scores, "orig.ident", Seurat.object = TRUE) +} # } +``` diff --git a/docs/reference/fake_final_mds.html b/docs/reference/fake_final_mds.html deleted file mode 100644 index 85a6d03..0000000 --- a/docs/reference/fake_final_mds.html +++ /dev/null @@ -1,115 +0,0 @@ - -Example Cell Status and Normalized Data — fake_final_mds • PathwayEmbed - - -
    -
    - - - -
    -
    - - -
    -

    A dataset generated by ComputeCellData applied to fake_test_object. -Contains cell status and normalized values.

    -
    - -
    -
    data(fake_final_mds)
    -
    - -
    -

    Format

    -

    A data frame with the following columns:

    V1
    -

    A numerical value presenting the status of the cell

    - -
    normalized
    -

    Numerical value representing normalized data

    - - -
    - -
    -

    Examples

    -
    data(fake_final_mds)
    -head(fake_final_mds)
    -#>                       V1 normalized
    -#> pathway.on    25.5366389  1.0000000
    -#> pathway.off -138.5006483  0.0000000
    -#> Cell819       -1.3616977  0.8360230
    -#> Cell124       -4.8660336  0.8146600
    -#> Cell1363       3.2841257  0.8643448
    -#> Cell1460       0.1235202  0.8450772
    -
    -
    -
    - -
    - - -
    - -
    -

    Site built with pkgdown 2.1.3.

    -
    - -
    - - - - - - - - diff --git a/docs/reference/fake_test_object.html b/docs/reference/fake_test_object.html deleted file mode 100644 index da8deaa..0000000 --- a/docs/reference/fake_test_object.html +++ /dev/null @@ -1,114 +0,0 @@ - -Example Seurat Object for Testing — fake_test_object • PathwayEmbed - - -
    -
    - - - -
    -
    - - -
    -

    A simulated Seurat object with fake gene expression data for the Wnt signaling pathway. -This Seurat object contains gene expression data from simulated cells with Wnt positive -and negative gene expression values.

    -
    - -
    -
    data(fake_test_object)
    -
    - -
    -

    Format

    -

    A Seurat object. The object contains:

    assays
    -

    List of assays used for data storage. Includes RNA expression data.

    - -
    meta.data
    -

    Metadata associated with the cells. Contains information about the groups (e.g., WT vs. Mutant).

    - -
    features
    -

    Gene features (including Wnt pathway genes) used in the analysis.

    - -
    cells
    -

    Cell names, labeled as Cell1, Cell2, ..., CellN.

    - - -
    -
    -

    Source

    -

    Simulated for demonstration purposes.

    -
    - -
    - -
    - - -
    - -
    -

    Site built with pkgdown 2.1.3.

    -
    - -
    - - - - - - - - diff --git a/docs/reference/fake_to_plot.html b/docs/reference/fake_to_plot.html deleted file mode 100644 index 39a94ec..0000000 --- a/docs/reference/fake_to_plot.html +++ /dev/null @@ -1,121 +0,0 @@ - -Example Processed Data for Plotting — fake_to_plot • PathwayEmbed - - -
    -
    - - - -
    -
    - - -
    -

    A dataset generated by running PreparePlotData on fake_test_object and fake_final_mds. -Contains processed data ready for visualization, with the following features:

    -
    - -
    -
    data(fake_to_plot)
    -
    - -
    -

    Format

    -

    A data frame with the following columns:

    V1
    -

    A numerical or categorical value depending on the specific analysis

    - -
    normalized
    -

    Normalized numerical value representing the cell's data

    - -
    genotype
    -

    Group classification of the cell (e.g., "WT", "Mutant")

    - -
    scale
    -

    Scaled data for visualization purposes

    - - -
    - -
    -

    Examples

    -
    data(fake_to_plot)
    -head(fake_to_plot)
    -#>                  V1 normalized genotype       scale
    -#> Cell819  -1.3616977  0.8360230       WT -0.31471616
    -#> Cell124  -4.8660336  0.8146600       WT -1.09238288
    -#> Cell1363  3.2841257  0.8643448   Mutant  0.71626440
    -#> Cell1460  0.1235202  0.8450772   Mutant  0.01487683
    -#> Cell117  -1.4956377  0.8352065       WT -0.34443955
    -#> Cell1294  1.1383404  0.8512637   Mutant  0.24008124
    -
    -
    -
    - -
    - - -
    - -
    -

    Site built with pkgdown 2.1.3.

    -
    - -
    - - - - - - - - diff --git a/docs/reference/index.html b/docs/reference/index.html index 961bb14..c4536c6 100644 --- a/docs/reference/index.html +++ b/docs/reference/index.html @@ -1,116 +1,155 @@ -Package index • PathwayEmbed - - -
    -
    +
    +
    +
    -
    - - - - - - - - - - - - - - - - - - - - -
    -

    All functions

    -

    -
    -

    CalculatePercentage()

    -

    CalculatePercentage

    -

    ComputeCellData()

    -

    ComputeCellData

    -

    LoadPathway()

    -

    LoadPathway

    -

    PathwayMaxMin()

    -

    PathwayMaxMin

    -

    PlotPathway()

    -

    PlotPathway

    -

    PreparePlotData()

    -

    A function to prepare the signal transduction dataframe for plotting

    -

    fake_final_mds

    -

    Example Cell Status and Normalized Data

    -

    fake_test_object

    -

    Example Seurat Object for Testing

    -

    fake_to_plot

    -

    Example Processed Data for Plotting

    - - -
    +
    +

    All functions

    -
    + + +
    -
    + +
    diff --git a/docs/reference/index.md b/docs/reference/index.md new file mode 100644 index 0000000..3ef4d3b --- /dev/null +++ b/docs/reference/index.md @@ -0,0 +1,30 @@ +# Package index + +## All functions + +- [`CalculatePercentage()`](https://raredonlab.github.io/PathwayEmbed/reference/CalculatePercentage.md) + : CalculatePercentage +- [`ComputeCellData()`](https://raredonlab.github.io/PathwayEmbed/reference/ComputeCellData.md) + : ComputeCellData +- [`DataPreProcess()`](https://raredonlab.github.io/PathwayEmbed/reference/DataPreProcess.md) + : DataPreProcess +- [`ListPathway()`](https://raredonlab.github.io/PathwayEmbed/reference/ListPathway.md) + : ListPathway List available pathways or pathway metadata +- [`LoadPathway()`](https://raredonlab.github.io/PathwayEmbed/reference/LoadPathway.md) + : LoadPathway +- [`PathwayMaxMin()`](https://raredonlab.github.io/PathwayEmbed/reference/PathwayMaxMin.md) + : PathwayMaxMin +- [`PlotPathway()`](https://raredonlab.github.io/PathwayEmbed/reference/PlotPathway.md) + : PlotPathway +- [`PreparePlotData()`](https://raredonlab.github.io/PathwayEmbed/reference/PreparePlotData.md) + : PreparePlotData +- [`synthetic_test_matrix`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_matrix.md) + : Example Matrix for Testing +- [`synthetic_test_matrix_100`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_matrix_100.md) + : Expanded Example Matrix for Testing (100 genes) +- [`synthetic_test_metadata`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_metadata.md) + : synthetic metadata for test cells +- [`synthetic_test_object`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object.md) + : Example Seurat Object for Testing +- [`synthetic_test_object_100`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object_100.md) + : Expanded Example Seurat Object for Testing (100 genes) diff --git a/docs/reference/synthetic_test_matrix.html b/docs/reference/synthetic_test_matrix.html new file mode 100644 index 0000000..c4ca0d2 --- /dev/null +++ b/docs/reference/synthetic_test_matrix.html @@ -0,0 +1,102 @@ + +Example Matrix for Testing — synthetic_test_matrix • PathwayEmbed + Skip to contents + + +
    +
    +
    + +
    +

    A numeric matrix containing single-cell gene expression data for demonstration purposes in the PathwayEmbed package. +Rows correspond to genes and columns correspond to individual cells.

    +
    + +
    +

    Usage

    +
    synthetic_test_matrix
    +
    + +
    +

    Format

    +

    A numeric matrix with genes (rows) and cells (columns).

    Rows
    +

    18 genes (e.g. "Lgr5", "Rnf43", "Lrp5", "Fzd6" ...)

    + +
    Columns
    +

    2000 cells (named "Cell1", "Cell2", ...)

    + +
    Values
    +

    35830 nonzero entries, representing expression values (numeric)

    + + +
    +
    +

    Source

    +

    Simulated for demonstration purposes.

    +
    +
    +

    Details

    +

    This is a synthetic dataset created for testing and demonstration purposes. +It mimics the structure of a gene-by-cell expression matrix used in single-cell +RNA sequencing analysis.

    +
    + +
    +

    Examples

    +
    data(synthetic_test_matrix)
    +
    +
    +
    + + +
    + + + +
    + + + + + + + diff --git a/docs/reference/synthetic_test_matrix.md b/docs/reference/synthetic_test_matrix.md new file mode 100644 index 0000000..6406375 --- /dev/null +++ b/docs/reference/synthetic_test_matrix.md @@ -0,0 +1,43 @@ +# Example Matrix for Testing + +A numeric matrix containing single-cell gene expression data for +demonstration purposes in the PathwayEmbed package. Rows correspond to +genes and columns correspond to individual cells. + +## Usage + +``` r +synthetic_test_matrix +``` + +## Format + +A numeric matrix with genes (rows) and cells (columns). + +- Rows: + + 18 genes (e.g. "Lgr5", "Rnf43", "Lrp5", "Fzd6" ...) + +- Columns: + + 2000 cells (named "Cell1", "Cell2", ...) + +- Values: + + 35830 nonzero entries, representing expression values (numeric) + +## Source + +Simulated for demonstration purposes. + +## Details + +This is a synthetic dataset created for testing and demonstration +purposes. It mimics the structure of a gene-by-cell expression matrix +used in single-cell RNA sequencing analysis. + +## Examples + +``` r +data(synthetic_test_matrix) +``` diff --git a/docs/reference/synthetic_test_matrix_100.html b/docs/reference/synthetic_test_matrix_100.html new file mode 100644 index 0000000..8bdd497 --- /dev/null +++ b/docs/reference/synthetic_test_matrix_100.html @@ -0,0 +1,119 @@ + +Expanded Example Matrix for Testing (100 genes) — synthetic_test_matrix_100 • PathwayEmbed + Skip to contents + + +
    +
    +
    + +
    +
    + + +
    +

    Format

    +

    A numeric matrix with 100 rows (genes) and 2000 columns (cells):

    Rows
    +

    100 genes. Rows 1–18 are the original Wnt pathway genes +with their original expression values unchanged. Rows 19–100 are randomly expressed genes from +housekeeping, cell-cycle, TF, Notch, MAPK/ERK, TGF-β/BMP, and +adhesion panels.

    + +
    Columns
    +

    2000 cells named "Cell1" through +"Cell2000", matching synthetic_test_matrix.

    + +
    Values
    +

    Non-negative integer expression counts. Rows 1–18 are +taken directly from synthetic_test_matrix. Rows 19–100 are +simulated via a zero-inflated negative-binomial distribution +(mu = 2.5, size = 0.8, ~35 \

    + + +

    Simulated for demonstration purposes, expanded from +synthetic_test_object. + + +synthetic_test_matrix_100 + + +A numeric matrix containing single-cell gene expression data for +demonstration and testing in the PathwayEmbed package. +This expanded version contains 100 genes: the original 18 Wnt-pathway +genes from synthetic_test_matrix (rows 1–18, values preserved +exactly) plus 82 additional randomly expressed genes drawn from +housekeeping, cell-cycle, transcription-factor, Notch, MAPK/ERK, +TGF-β/BMP, and adhesion gene sets. + + +Because the first 18 rows are byte-for-byte identical to +synthetic_test_matrix, any existing code that subsets to the +Wnt gene panel will return the same results as before. The 82 extra +genes carry no planted biological signal; they are intended for +testing functions that operate on larger or multi-pathway gene panels, +such as dimensionality reduction, clustering, or multi-pathway scoring. + + +data(synthetic_test_matrix_100) +dim(synthetic_test_matrix_100) # 100 x 2000 +rownames(synthetic_test_matrix_100)[1:18] # original Wnt genes +mean(synthetic_test_matrix_100 > 0) # ~0.35 non-zero density + + +synthetic_test_matrix, +synthetic_test_object_100 + +datasets

    +
    + +
    + + +
    + + + +
    + + + + + + + diff --git a/docs/reference/synthetic_test_matrix_100.md b/docs/reference/synthetic_test_matrix_100.md new file mode 100644 index 0000000..5ab26f3 --- /dev/null +++ b/docs/reference/synthetic_test_matrix_100.md @@ -0,0 +1,45 @@ +# Expanded Example Matrix for Testing (100 genes) + +## Format + +A numeric matrix with 100 rows (genes) and 2000 columns (cells): + +- Rows: + + 100 genes. Rows 1–18 are the original Wnt pathway genes with their + original expression values unchanged. Rows 19–100 are randomly + expressed genes from housekeeping, cell-cycle, TF, Notch, MAPK/ERK, + TGF-β/BMP, and adhesion panels. + +- Columns: + + 2000 cells named `"Cell1"` through `"Cell2000"`, matching + `synthetic_test_matrix`. + +- Values: + + Non-negative integer expression counts. Rows 1–18 are taken directly + from `synthetic_test_matrix`. Rows 19–100 are simulated via a + zero-inflated negative-binomial distribution (mu = 2.5, size = 0.8, + ~35 \\ + +Simulated for demonstration purposes, expanded from +`synthetic_test_object`. synthetic_test_matrix_100 A numeric matrix +containing single-cell gene expression data for demonstration and +testing in the PathwayEmbed package. This expanded version contains 100 +genes: the original 18 Wnt-pathway genes from `synthetic_test_matrix` +(rows 1–18, values preserved exactly) plus 82 additional randomly +expressed genes drawn from housekeeping, cell-cycle, +transcription-factor, Notch, MAPK/ERK, TGF-β/BMP, and adhesion gene +sets. Because the first 18 rows are byte-for-byte identical to +`synthetic_test_matrix`, any existing code that subsets to the Wnt gene +panel will return the same results as before. The 82 extra genes carry +no planted biological signal; they are intended for testing functions +that operate on larger or multi-pathway gene panels, such as +dimensionality reduction, clustering, or multi-pathway scoring. +data(synthetic_test_matrix_100) dim(synthetic_test_matrix_100) \# 100 x +2000 rownames(synthetic_test_matrix_100)\[1:18\] \# original Wnt genes +mean(synthetic_test_matrix_100 \> 0) \# ~0.35 non-zero density +[`synthetic_test_matrix`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_matrix.md), +[`synthetic_test_object_100`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object_100.md) +datasets diff --git a/docs/reference/synthetic_test_metadata.html b/docs/reference/synthetic_test_metadata.html new file mode 100644 index 0000000..4c6b075 --- /dev/null +++ b/docs/reference/synthetic_test_metadata.html @@ -0,0 +1,101 @@ + +synthetic metadata for test cells — synthetic_test_metadata • PathwayEmbed + Skip to contents + + +
    +
    +
    + +
    +

    A toy metadata table corresponding to the columns of synthetic_test_matrix. +Each row represents a single cell with associated metadata.

    +
    + +
    +

    Usage

    +
    synthetic_test_metadata
    +
    + +
    +

    Format

    +

    A data frame with 2000 rows and 4 variables:

    orig.ident
    +

    Character, project identifier

    + +
    nCount_RNA
    +

    Integer, total RNA counts per cell

    + +
    nFeature_RNA
    +

    Integer, number of detected features (genes) per cell

    + +
    genotype
    +

    Factor/character, cell genotype (e.g., "WT", "Mutant")

    + + +
    +
    +

    Details

    +

    This dataset provides toy cell-level metadata designed to accompany +synthetic_test_matrix. It mimics the structure of single-cell +experiment metadata used in analysis frameworks such as Seurat.

    +
    + +
    +

    Examples

    +
    data(synthetic_test_metadata)
    +
    +
    +
    + + +
    + + + +
    + + + + + + + diff --git a/docs/reference/synthetic_test_metadata.md b/docs/reference/synthetic_test_metadata.md new file mode 100644 index 0000000..50954b5 --- /dev/null +++ b/docs/reference/synthetic_test_metadata.md @@ -0,0 +1,43 @@ +# synthetic metadata for test cells + +A toy metadata table corresponding to the columns of +`synthetic_test_matrix`. Each row represents a single cell with +associated metadata. + +## Usage + +``` r +synthetic_test_metadata +``` + +## Format + +A data frame with 2000 rows and 4 variables: + +- orig.ident: + + Character, project identifier + +- nCount_RNA: + + Integer, total RNA counts per cell + +- nFeature_RNA: + + Integer, number of detected features (genes) per cell + +- genotype: + + Factor/character, cell genotype (e.g., "WT", "Mutant") + +## Details + +This dataset provides toy cell-level metadata designed to accompany +`synthetic_test_matrix`. It mimics the structure of single-cell +experiment metadata used in analysis frameworks such as Seurat. + +## Examples + +``` r +data(synthetic_test_metadata) +``` diff --git a/docs/reference/synthetic_test_metadata_100.html b/docs/reference/synthetic_test_metadata_100.html new file mode 100644 index 0000000..a1d217d --- /dev/null +++ b/docs/reference/synthetic_test_metadata_100.html @@ -0,0 +1,142 @@ + +Expanded Synthetic Metadata for Test Cells (100-gene dataset) — synthetic_test_metadata_100 • PathwayEmbed + Skip to contents + + +
    +
    +
    + +
    +

    A metadata table corresponding to the 2000 columns of +synthetic_test_matrix_100. Derived directly from +synthetic_test_object@meta.data with nCount_RNA and +nFeature_RNA recalculated to reflect the expanded 100-gene matrix. +The genotype assignments (WT / Mutant) and +orig.ident are unchanged from the original object.

    +
    + +
    +

    Usage

    +
    synthetic_test_metadata_100
    +
    + +
    +

    Format

    +

    A data frame with 2000 rows and 4 variables:

    orig.ident
    +

    Character. Project identifier +("SyntheticProject" for all cells).

    + +
    nCount_RNA
    +

    Integer. Total UMI counts per cell computed from +synthetic_test_matrix_100 (column sums).

    + +
    nFeature_RNA
    +

    Integer. Number of detected genes per cell +(number of non-zero entries per column in +synthetic_test_matrix_100).

    + +
    genotype
    +

    Factor with levels c("WT", "Mutant"). +Cells 1–1000 are "WT"; cells 1001–2000 are +"Mutant", matching the original object.

    + + +
    +
    +

    Source

    +

    Derived from synthetic_test_object@meta.data.

    +
    +
    +

    Details

    +

    Row names match the column names of synthetic_test_matrix_100 +("Cell1""Cell2000"). nCount_RNA and +nFeature_RNA are recalculated so they are internally consistent +with the 100-gene matrix rather than the original 18-gene matrix.

    +
    + + +
    +

    Examples

    +
    data(synthetic_test_metadata_100)
    +head(synthetic_test_metadata_100)
    +#>          orig.ident nCount_RNA nFeature_RNA genotype
    +#> Cell1 SeuratProject        202           41       WT
    +#> Cell2 SeuratProject        156           32       WT
    +#> Cell3 SeuratProject        115           34       WT
    +#> Cell4 SeuratProject        197           43       WT
    +#> Cell5 SeuratProject        169           36       WT
    +#> Cell6 SeuratProject        167           36       WT
    +table(synthetic_test_metadata_100$genotype)  # 1000 WT, 1000 Mutant
    +#> 
    +#> Mutant     WT 
    +#>   1000   1000 
    +
    +
    +
    + + +
    + + + +
    + + + + + + + diff --git a/docs/reference/synthetic_test_metadata_100.md b/docs/reference/synthetic_test_metadata_100.md new file mode 100644 index 0000000..5565918 --- /dev/null +++ b/docs/reference/synthetic_test_metadata_100.md @@ -0,0 +1,72 @@ +# Expanded Synthetic Metadata for Test Cells (100-gene dataset) + +A metadata table corresponding to the 2000 columns of +`synthetic_test_matrix_100`. Derived directly from +`synthetic_test_object@meta.data` with `nCount_RNA` and `nFeature_RNA` +recalculated to reflect the expanded 100-gene matrix. The genotype +assignments (`WT` / `Mutant`) and `orig.ident` are unchanged from the +original object. + +## Usage + +``` r +synthetic_test_metadata_100 +``` + +## Format + +A data frame with 2000 rows and 4 variables: + +- orig.ident: + + Character. Project identifier (`"SyntheticProject"` for all cells). + +- nCount_RNA: + + Integer. Total UMI counts per cell computed from + `synthetic_test_matrix_100` (column sums). + +- nFeature_RNA: + + Integer. Number of detected genes per cell (number of non-zero entries + per column in `synthetic_test_matrix_100`). + +- genotype: + + Factor with levels `c("WT", "Mutant")`. Cells 1–1000 are `"WT"`; cells + 1001–2000 are `"Mutant"`, matching the original object. + +## Source + +Derived from `synthetic_test_object@meta.data`. + +## Details + +Row names match the column names of `synthetic_test_matrix_100` +(`"Cell1"` … `"Cell2000"`). `nCount_RNA` and `nFeature_RNA` are +recalculated so they are internally consistent with the 100-gene matrix +rather than the original 18-gene matrix. + +## See also + +[`synthetic_test_metadata`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_metadata.md), +[`synthetic_test_matrix_100`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_matrix_100.md), +[`synthetic_test_object_100`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object_100.md) + +## Examples + +``` r +data(synthetic_test_metadata_100) +head(synthetic_test_metadata_100) +#> orig.ident nCount_RNA nFeature_RNA genotype +#> Cell1 SeuratProject 202 41 WT +#> Cell2 SeuratProject 156 32 WT +#> Cell3 SeuratProject 115 34 WT +#> Cell4 SeuratProject 197 43 WT +#> Cell5 SeuratProject 169 36 WT +#> Cell6 SeuratProject 167 36 WT +table(synthetic_test_metadata_100$genotype) # 1000 WT, 1000 Mutant +#> +#> Mutant WT +#> 1000 1000 +``` diff --git a/docs/reference/synthetic_test_object.html b/docs/reference/synthetic_test_object.html new file mode 100644 index 0000000..ac7dc5a --- /dev/null +++ b/docs/reference/synthetic_test_object.html @@ -0,0 +1,97 @@ + +Example Seurat Object for Testing — synthetic_test_object • PathwayEmbed + Skip to contents + + +
    +
    +
    + +
    +

    A simulated Seurat object with synthetic gene expression data for the Wnt signaling pathway. +This Seurat object contains gene expression data from simulated cells with Wnt positive +and negative gene expression values.

    +
    + +
    +

    Usage

    +
    data(synthetic_test_object)
    +
    + +
    +

    Format

    +

    A Seurat object. The object contains:

    assays
    +

    List of assays used for data storage. Includes RNA expression data.

    + +
    meta.data
    +

    Metadata associated with the cells. Contains information about the groups (e.g., WT vs. Mutant).

    + +
    features
    +

    Gene features (including Wnt pathway genes) used in the analysis.

    + +
    cells
    +

    Cell names, labeled as Cell1, Cell2, ..., CellN.

    + + +
    +
    +

    Source

    +

    Simulated for demonstration purposes.

    +
    + +
    + + +
    + + + +
    + + + + + + + diff --git a/docs/reference/synthetic_test_object.md b/docs/reference/synthetic_test_object.md new file mode 100644 index 0000000..f969b86 --- /dev/null +++ b/docs/reference/synthetic_test_object.md @@ -0,0 +1,37 @@ +# Example Seurat Object for Testing + +A simulated Seurat object with synthetic gene expression data for the +Wnt signaling pathway. This Seurat object contains gene expression data +from simulated cells with Wnt positive and negative gene expression +values. + +## Usage + +``` r +data(synthetic_test_object) +``` + +## Format + +A Seurat object. The object contains: + +- assays: + + List of assays used for data storage. Includes RNA expression data. + +- meta.data: + + Metadata associated with the cells. Contains information about the + groups (e.g., WT vs. Mutant). + +- features: + + Gene features (including Wnt pathway genes) used in the analysis. + +- cells: + + Cell names, labeled as Cell1, Cell2, ..., CellN. + +## Source + +Simulated for demonstration purposes. diff --git a/docs/reference/synthetic_test_object_100.html b/docs/reference/synthetic_test_object_100.html new file mode 100644 index 0000000..45975c9 --- /dev/null +++ b/docs/reference/synthetic_test_object_100.html @@ -0,0 +1,145 @@ + +Expanded Example Seurat Object for Testing (100 genes) — synthetic_test_object_100 • PathwayEmbed + Skip to contents + + +
    +
    +
    + +
    +

    A simulated Seurat object built from synthetic_test_matrix_100 +and synthetic_test_metadata. It is the 100-gene counterpart +of synthetic_test_object and is structurally identical except +for the larger gene panel. The original 18 Wnt genes and their +expression values are fully preserved.

    +
    + +
    +

    Usage

    +
    synthetic_test_object_100
    +
    + +
    +

    Format

    +

    A Seurat object containing:

    assays
    +

    A single RNA assay storing the 100 × 2000 +count matrix (synthetic_test_matrix_100).

    + +
    meta.data
    +

    Cell-level metadata with four columns: +orig.ident, nCount_RNA, nFeature_RNA, and +genotype (WT vs. Mutant). See +synthetic_test_metadata.

    + +
    features
    +

    100 genes: 18 original Wnt genes (rows 1–18) plus +82 randomly expressed genes from housekeeping, cell-cycle, TF, +Notch, MAPK/ERK, TGF-β/BMP, and adhesion panels (rows 19–100).

    + +
    cells
    +

    2000 cells named "Cell1""Cell2000".

    + + +
    +
    +

    Source

    +

    Expanded from synthetic_test_object for demonstration +purposes.

    +
    +
    +

    Details

    +

    Created with CreateSeuratObject(min.cells = 0, min.features = 0) +so every gene and cell in the underlying matrix is retained. +Compatible with Seurat v4 and v5 (SeuratObject >= 4.1).

    +
    + + +
    +

    Examples

    +
    data(synthetic_test_object_100)
    +synthetic_test_object_100
    +#> Loading required package: SeuratObject
    +#> Warning: package ‘SeuratObject’ was built under R version 4.4.3
    +#> Loading required package: sp
    +#> Warning: package ‘sp’ was built under R version 4.4.3
    +#> 
    +#> Attaching package: ‘SeuratObject’
    +#> The following objects are masked from ‘package:base’:
    +#> 
    +#>     intersect, t
    +#> An object of class Seurat 
    +#> 100 features across 2000 samples within 1 assay 
    +#> Active assay: RNA (100 features, 0 variable features)
    +#>  3 layers present: counts, data, scale.data
    +Seurat::Idents(synthetic_test_object_100) <- "genotype"
    +table(Seurat::Idents(synthetic_test_object_100))  # 1000 WT, 1000 Mutant
    +#> 
    +#>     WT Mutant 
    +#>   1000   1000 
    +
    +
    +
    + + +
    + + + +
    + + + + + + + diff --git a/docs/reference/synthetic_test_object_100.md b/docs/reference/synthetic_test_object_100.md new file mode 100644 index 0000000..1ad992a --- /dev/null +++ b/docs/reference/synthetic_test_object_100.md @@ -0,0 +1,78 @@ +# Expanded Example Seurat Object for Testing (100 genes) + +A simulated Seurat object built from `synthetic_test_matrix_100` and +`synthetic_test_metadata`. It is the 100-gene counterpart of +`synthetic_test_object` and is structurally identical except for the +larger gene panel. The original 18 Wnt genes and their expression values +are fully preserved. + +## Usage + +``` r +synthetic_test_object_100 +``` + +## Format + +A Seurat object containing: + +- assays: + + A single `RNA` assay storing the 100 × 2000 count matrix + (`synthetic_test_matrix_100`). + +- meta.data: + + Cell-level metadata with four columns: `orig.ident`, `nCount_RNA`, + `nFeature_RNA`, and `genotype` (WT vs. Mutant). See + [`synthetic_test_metadata`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_metadata.md). + +- features: + + 100 genes: 18 original Wnt genes (rows 1–18) plus 82 randomly + expressed genes from housekeeping, cell-cycle, TF, Notch, MAPK/ERK, + TGF-β/BMP, and adhesion panels (rows 19–100). + +- cells: + + 2000 cells named `"Cell1"` … `"Cell2000"`. + +## Source + +Expanded from `synthetic_test_object` for demonstration purposes. + +## Details + +Created with `CreateSeuratObject(min.cells = 0, min.features = 0)` so +every gene and cell in the underlying matrix is retained. Compatible +with Seurat v4 and v5 (`SeuratObject` \>= 4.1). + +## See also + +[`synthetic_test_object`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object.md), +[`synthetic_test_matrix_100`](https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_matrix_100.md), + +## Examples + +``` r +data(synthetic_test_object_100) +synthetic_test_object_100 +#> Loading required package: SeuratObject +#> Warning: package ‘SeuratObject’ was built under R version 4.4.3 +#> Loading required package: sp +#> Warning: package ‘sp’ was built under R version 4.4.3 +#> +#> Attaching package: ‘SeuratObject’ +#> The following objects are masked from ‘package:base’: +#> +#> intersect, t +#> An object of class Seurat +#> 100 features across 2000 samples within 1 assay +#> Active assay: RNA (100 features, 0 variable features) +#> 3 layers present: counts, data, scale.data +Seurat::Idents(synthetic_test_object_100) <- "genotype" +table(Seurat::Idents(synthetic_test_object_100)) # 1000 WT, 1000 Mutant +#> +#> WT Mutant +#> 1000 1000 +``` diff --git a/docs/search.json b/docs/search.json new file mode 100644 index 0000000..2c47293 --- /dev/null +++ b/docs/search.json @@ -0,0 +1 @@ +[{"path":"https://raredonlab.github.io/PathwayEmbed/LICENSE.html","id":null,"dir":"","previous_headings":"","what":"MIT License","title":"MIT License","text":"Copyright (c) 2025 Raredon Lab Permission hereby granted, free charge, person obtaining copy software associated documentation files (“Software”), deal Software without restriction, including without limitation rights use, copy, modify, merge, publish, distribute, sublicense, /sell copies Software, permit persons Software furnished , subject following conditions: copyright notice permission notice shall included copies substantial portions Software. SOFTWARE PROVIDED “”, WITHOUT WARRANTY KIND, EXPRESS IMPLIED, INCLUDING LIMITED WARRANTIES MERCHANTABILITY, FITNESS PARTICULAR PURPOSE NONINFRINGEMENT. EVENT SHALL AUTHORS COPYRIGHT HOLDERS LIABLE CLAIM, DAMAGES LIABILITY, WHETHER ACTION CONTRACT, TORT OTHERWISE, ARISING , CONNECTION SOFTWARE USE DEALINGS SOFTWARE.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/Notch_Analysis_updated.html","id":"overview","dir":"Articles","previous_headings":"","what":"Overview","title":"Notch_Analysis","text":"vignette demonstrates application PathwayEmbed Notch-perturbed system (Ncstn fl/fl cKO bone marrow) aging SSPCs. Reference: Remark et al., Bone Res 11, 50 (2023). https://doi.org/10.1038/s41413-023-00283-8","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/Notch_Analysis_updated.html","id":"load-packages","dir":"Articles","previous_headings":"","what":"Load Packages","title":"Notch_Analysis","text":"","code":"library(Seurat) library(PathwayEmbed) library(ggplot2) library(dplyr) library(patchwork) library(pheatmap) library(tidyr) library(pROC)"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/Notch_Analysis_updated.html","id":"helper-annotation-label-builder","dir":"Articles","previous_headings":"","what":"Helper: Annotation Label Builder","title":"Notch_Analysis","text":"","code":"make_label <- function(stats, group1, group2) { d <- round(stats$cohens_d[1], 3) p <- formatC(stats$p_value[1], format = \"e\", digits = 2) on1 <- stats$percentage_on[stats$group == group1] off1 <- stats$percentage_off[stats$group == group1] on2 <- stats$percentage_on[stats$group == group2] off2 <- stats$percentage_off[stats$group == group2] paste0( group1, \": ON=\", on1, \"%, OFF=\", off1, \"%\\n\", group2, \": ON=\", on2, \"%, OFF=\", off2, \"%\\n\", \"Cohen's d = \", d, \"\\n\", \"p = \", p ) }"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/Notch_Analysis_updated.html","id":"data-preprocessing-wt-vs--ko-ncstn-cko","dir":"Articles","previous_headings":"","what":"Data Preprocessing — WT vs. KO (Ncstn cKO)","title":"Notch_Analysis","text":"block eval=FALSE raw 10X data large. pre-processed SSPC subset (COI_2) loaded directly package next chunk.","code":"wt_data <- Read10X(data.dir = \"path/to/WT\", gene.column = 2) ko_data <- Read10X(data.dir = \"path/to/KO\", gene.column = 2) wt_seurat <- CreateSeuratObject(counts = wt_data, project = \"WT\") ko_seurat <- CreateSeuratObject(counts = ko_data, project = \"KO\") wt_seurat$condition <- \"WT\" ko_seurat$condition <- \"KO\" combined <- merge(wt_seurat, y = ko_seurat, add.cell.ids = c(\"WT\", \"KO\"), project = \"WT_vs_KO\") combined[[\"RNA\"]] <- JoinLayers(combined[[\"RNA\"]]) combined[[\"percent.mt\"]] <- PercentageFeatureSet(combined, pattern = \"^mt-\") combined <- subset(combined, subset = nFeature_RNA > 200 & nFeature_RNA < 2000 & percent.mt < 10) combined <- NormalizeData(combined, normalization.method = \"LogNormalize\", scale.factor = 10000) combined <- FindVariableFeatures(combined, selection.method = \"vst\", nfeatures = 2000) combined <- ScaleData(combined) combined <- RunPCA(combined) ElbowPlot(combined, ndims = 50) combined <- FindNeighbors(combined, dims = 1:20) combined <- FindClusters(combined, resolution = 1) combined <- RunUMAP(combined, dims = 1:20) DimPlot(combined, label = TRUE) FeaturePlot(combined, \"Cxcl12\") FeaturePlot(combined, \"Kitl\") COI_2 <- subset(combined, subset = seurat_clusters %in% c(\"23\", \"25\"))"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/Notch_Analysis_updated.html","id":"notch-signaling-in-ncstn-ko-vs--wt-sspcs","dir":"Articles","previous_headings":"","what":"Notch Signaling in Ncstn KO vs. WT SSPCs","title":"Notch_Analysis","text":"","code":"COI_2_matrix <- as.matrix(GetAssayData(COI_2, assay = \"RNA\", layer = \"data\")) COI_2_metadata <- COI_2@meta.data # Load both Notch databases ListPathway(\"NOTCH\") #> # A tibble: 6 × 8 #> Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes #> #> 1 NOTCH NOTCH_JAG1 GSE223734 rJAG1 li… Mouse embr… Mouse 5 NA #> 2 NOTCH NOTCH_CB1… GSE221577 CB-103 N… RPMI-8402 … Human 46 NA #> 3 NOTCH NOTCH_LY_… GSE221577 LY411575… RPMI-8402 … Human 46 NA #> 4 NOTCH NOTCH_JAG… GSE235637 JAG1 sti… SVG-A cells Human 11 NA #> 5 NOTCH NOTCH_JAG… GSE235637 JAG1 sti… SVG-A cells Human 11 NA #> 6 NOTCH NOTCH_JAG… GSE235637 JAG1 sti… SVG-A cells Human 11 NA pathwaydata_mus <- LoadPathway(\"NOTCH_JAG1\", \"mouse\") # mouse perturbation data pathwaydata_24hr <- LoadPathway(\"NOTCH_JAG1_24H\", \"mouse\") # human 24hr (cross-species) matrix_mus <- DataPreProcess(COI_2_matrix, pathwaydata_mus, Seurat.object = FALSE) matrix_24hr <- DataPreProcess(COI_2_matrix, pathwaydata_24hr, Seurat.object = FALSE) pathwaystat_mus <- PathwayMaxMin(matrix_mus, pathwaydata_mus) pathwaystat_24hr <- PathwayMaxMin(matrix_24hr, pathwaydata_24hr) Notch_score_mus <- ComputeCellData(matrix_mus, pathwaystat_mus) Notch_score_24hr <- ComputeCellData(matrix_24hr, pathwaystat_24hr) to_plot_1 <- PreparePlotData(COI_2_metadata, Notch_score_mus, \"condition\") to_plot_2 <- PreparePlotData(COI_2_metadata, Notch_score_24hr, \"condition\") pct_1 <- CalculatePercentage(to_plot_1, \"condition\") pct_2 <- CalculatePercentage(to_plot_2, \"condition\") pct_1; pct_2 #> # A tibble: 2 × 5 #> group percentage_on percentage_off cohens_d p_value #> #> 1 WT 46 54 0.369 0.141 #> 2 KO 35.4 64.6 0.369 0.141 #> # A tibble: 2 × 5 #> group percentage_on percentage_off cohens_d p_value #> #> 1 WT 52 48 0.553 0.00519 #> 2 KO 34.5 65.5 0.553 0.00519 # Database comparison: gene overlap and coefficient agreement genes_mus <- pathwaydata_mus$Gene_Symbol genes_24hr <- pathwaydata_24hr$Gene_Symbol shared <- intersect(genes_mus, genes_24hr) cat(\"Genes in mouse database: \", length(genes_mus), \"\\n\") #> Genes in mouse database: 5 cat(\"Genes in human 24hr database: \", length(genes_24hr), \"\\n\") #> Genes in human 24hr database: 9 cat(\"Shared genes: \", length(shared), \"\\n\") #> Shared genes: 4 cat(\"Unique to mouse database: \", length(setdiff(genes_mus, genes_24hr)), \"\\n\") #> Unique to mouse database: 1 cat(\"Unique to 24hr database: \", length(setdiff(genes_24hr, genes_mus)), \"\\n\") #> Unique to 24hr database: 5 coef_mus <- setNames(pathwaydata_mus$Coefficient, pathwaydata_mus$Gene_Symbol) coef_24hr <- setNames(pathwaydata_24hr$Coefficient, pathwaydata_24hr$Gene_Symbol) coef_agree <- mean(sign(coef_mus[shared]) == sign(coef_24hr[shared]), na.rm = TRUE) cat(sprintf(\"Coefficient direction agreement (shared genes): %.1f%%\\n\", coef_agree * 100)) #> Coefficient direction agreement (shared genes): 100.0% PlotPathway(to_plot_1, \"Notch (mouse database)\", \"condition\", c(\"#FFDAB9\", \"#A3BFD9\")) + annotate(\"text\", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, label = make_label(pct_1, \"WT\", \"KO\"), size = 3.5, color = \"black\") PlotPathway(to_plot_2, \"Notch (human 24hr database)\", \"condition\", c(\"#FFDAB9\", \"#A3BFD9\")) + annotate(\"text\", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, label = make_label(pct_2, \"WT\", \"KO\"), size = 3.5, color = \"black\")"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/Notch_Analysis_updated.html","id":"benchmark-ncstn-ko-vs--wt","dir":"Articles","previous_headings":"","what":"Benchmark — Ncstn KO vs. WT","title":"Notch_Analysis","text":"","code":"common_genes <- intersect(rownames(COI_2_matrix), pathwaydata_24hr$Gene_Symbol) gene_matrix <- as.matrix(COI_2_matrix[common_genes, ]) mean_expr <- colMeans(gene_matrix, na.rm = TRUE) zscore_mean_per_cell <- colMeans(t(scale(t(gene_matrix))), na.rm = TRUE) Notch_features <- rownames(matrix_24hr) COI_2 <- AddModuleScore( object = COI_2, features = list(Notch_features), name = \"Notch_ModuleScore\", ctrl = 5, nbin = 10 ) module_score <- setNames( COI_2@meta.data$Notch_ModuleScore1, rownames(COI_2@meta.data) ) cells <- names(Notch_score_24hr) benchmark_df <- data.frame( PathwayEmbed = as.numeric(Notch_score_24hr), AddModuleScore = as.numeric(module_score[cells]), mean_expr = as.numeric(mean_expr[cells]), zscore_expr = as.numeric(zscore_mean_per_cell[cells]), row.names = cells ) benchmark_cor <- cor(benchmark_df, method = \"spearman\", use = \"pairwise.complete.obs\") print(round(benchmark_cor, 3)) #> PathwayEmbed AddModuleScore mean_expr zscore_expr #> PathwayEmbed 1.000 0.645 0.730 0.690 #> AddModuleScore 0.645 1.000 0.899 0.848 #> mean_expr 0.730 0.899 1.000 0.954 #> zscore_expr 0.690 0.848 0.954 1.000 p_cor <- pheatmap( benchmark_cor, color = colorRampPalette(c(\"#185FA5\", \"white\", \"#993C1D\"))(100), breaks = seq(-1, 1, length.out = 101), display_numbers = TRUE, number_format = \"%.2f\", fontsize_number = 9, main = \"Method Benchmark — Spearman Correlation (Ncstn KO dataset)\" ) p_cor ko_label <- ifelse(COI_2@meta.data[cells, \"condition\"] == \"KO\", 1L, 0L) compute_auroc <- function(scores, labels) { r <- roc(labels, scores, quiet = TRUE) auc_val <- as.numeric(auc(r)) if (auc_val < 0.5) auc_val <- 1 - auc_val auc_val } auroc_results <- data.frame( Method = colnames(benchmark_df), AUROC = sapply(benchmark_df, compute_auroc, labels = ko_label) ) auroc_results <- auroc_results[order(-auroc_results$AUROC), ] print(auroc_results) #> Method AUROC #> PathwayEmbed PathwayEmbed 0.6288496 #> mean_expr mean_expr 0.6224779 #> zscore_expr zscore_expr 0.6175221 #> AddModuleScore AddModuleScore 0.5929204 compute_cohens_d_method <- function(scores_vec, seurat_obj, group_col) { pd <- PreparePlotData(seurat_obj, scores_vec, group_col, Seurat.object = TRUE) pct <- CalculatePercentage(pd, group_var = group_col) abs(pct$cohens_d[1]) } cohens_d_results <- data.frame( Method = colnames(benchmark_df), Cohens_d = sapply( colnames(benchmark_df), function(m) { sv <- setNames(benchmark_df[[m]], rownames(benchmark_df)) compute_cohens_d_method(sv, COI_2, \"condition\") } ) ) cohens_d_results <- cohens_d_results[order(-cohens_d_results$Cohens_d), ] print(cohens_d_results) #> Method Cohens_d #> mean_expr mean_expr 0.5751355 #> PathwayEmbed PathwayEmbed 0.5534599 #> zscore_expr zscore_expr 0.5397190 #> AddModuleScore AddModuleScore 0.4965140 method_colors <- c( \"PathwayEmbed\" = \"#534AB7\", \"zscore_expr\" = \"#E24B4A\", \"AddModuleScore\" = \"#EF9F27\", \"mean_expr\" = \"#888780\" ) p_cd <- ggplot(cohens_d_results, aes(x = reorder(Method, Cohens_d), y = Cohens_d, fill = Method)) + geom_bar(stat = \"identity\", width = 0.6) + coord_flip() + scale_fill_manual(values = method_colors) + labs(title = \"Effect size (Cohen's d): KO vs. WT\", x = NULL, y = \"Cohen's d (absolute)\") + theme_classic() + theme(legend.position = \"none\") p_cd p_auroc <- ggplot(auroc_results, aes(x = reorder(Method, AUROC), y = AUROC, fill = Method)) + geom_bar(stat = \"identity\", width = 0.6) + geom_hline(yintercept = 0.5, linetype = \"dashed\", color = \"black\") + coord_flip() + scale_fill_manual(values = method_colors) + labs(title = \"AUROC: KO vs. WT separation (Ncstn KO dataset)\", x = NULL, y = \"AUROC\") + ylim(0, 1) + theme_classic() + theme(legend.position = \"none\") p_auroc roc_list <- lapply(colnames(benchmark_df), function(m) { roc(ko_label, benchmark_df[[m]], quiet = TRUE) }) names(roc_list) <- colnames(benchmark_df) roc_df <- do.call(rbind, lapply(names(roc_list), function(m) { r <- roc_list[[m]] data.frame(Method = m, FPR = 1 - r$specificities, TPR = r$sensitivities) })) p_roc <- ggplot(roc_df, aes(x = FPR, y = TPR, color = Method)) + geom_line(linewidth = 0.9) + geom_abline(intercept = 0, slope = 1, linetype = \"dashed\", color = \"grey60\") + scale_color_manual(values = method_colors) + labs(title = \"ROC curves: KO vs. WT (Ncstn KO dataset)\", x = \"False positive rate\", y = \"True positive rate\") + theme_classic() p_roc"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/Notch_Analysis_updated.html","id":"data-preprocessing-middle-age-vs--young-sspcs","dir":"Articles","previous_headings":"","what":"Data Preprocessing — Middle-Age vs. Young SSPCs","title":"Notch_Analysis","text":"","code":"wt_data <- Read10X(\"path/to/WT\", gene.column = 2) young_data <- Read10X(\"path/to/Young\", gene.column = 2) WT_object <- CreateSeuratObject(counts = wt_data) Young_object <- CreateSeuratObject(counts = young_data) WT_object$Age <- \"MiddleAge\" Young_object$Age <- \"Young\" WT_object[[\"percent.mt\"]] <- PercentageFeatureSet(WT_object, pattern = \"^mt-\") Young_object[[\"percent.mt\"]] <- PercentageFeatureSet(Young_object, pattern = \"^mt-\") # NOTE: 30% threshold is intentionally permissive — skeletal stem cells retain # higher baseline mitochondrial content; tighter thresholds remove genuine SSPCs. WT_object_filtered <- subset(WT_object, subset = nFeature_RNA >= 100 & percent.mt < 30) Young_object_filtered <- subset(Young_object, subset = nFeature_RNA >= 100 & percent.mt < 30) merge_object <- merge(WT_object_filtered, Young_object_filtered, add.cell.ids = c(\"WT\", \"Young\")) merge_object[[\"RNA\"]] <- JoinLayers(merge_object[[\"RNA\"]]) merge_object <- NormalizeData(merge_object) merge_object <- subset( merge_object, features = rownames(merge_object)[ Matrix::rowSums(GetAssayData(merge_object, slot = \"counts\") > 0) > 5] ) merge_object <- FindVariableFeatures(merge_object, selection.method = \"vst\", nfeatures = 3000) merge_object <- ScaleData(merge_object) merge_object <- RunPCA(merge_object) ElbowPlot(merge_object) merge_object <- FindNeighbors(merge_object, dims = 1:10) merge_object <- FindClusters(merge_object, resolution = 1) merge_object <- RunUMAP(merge_object, dims = 1:10) DimPlot(merge_object, reduction = \"umap\", group.by = \"Age\", label = TRUE) FeaturePlot(merge_object, reduction = \"umap\", features = \"Cxcl12\", order = TRUE) cluster_of_interest <- subset(merge_object, subset = seurat_clusters == 11) saveRDS(cluster_of_interest, file = \"Middle_age_object.rds\")"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/Notch_Analysis_updated.html","id":"notch-signaling-in-middle-age-vs--young-sspcs","dir":"Articles","previous_headings":"","what":"Notch Signaling in Middle-Age vs. Young SSPCs","title":"Notch_Analysis","text":"","code":"# Re-use the human 24hr database loaded earlier matrix_notch <- DataPreProcess(cluster_of_interest, pathwaydata_24hr, Seurat.object = TRUE) pathwaystat_notch <- PathwayMaxMin(matrix_notch, pathwaydata_24hr) Notch_score <- ComputeCellData(matrix_notch, pathwaystat_notch) to_plot <- PreparePlotData(cluster_of_interest, Notch_score, \"Age\", Seurat.object = TRUE) age_stats <- CalculatePercentage(to_plot, \"Age\") age_stats #> # A tibble: 2 × 5 #> group percentage_on percentage_off cohens_d p_value #> #> 1 MiddleAge 55.8 44.2 0.605 0.00000455 #> 2 Young 26.1 73.9 0.605 0.00000455 PlotPathway(to_plot, \"Notch\", \"Age\", c(\"orange\", \"#6baed6\")) + annotate(\"text\", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, label = make_label(age_stats, \"MiddleAge\", \"Young\"), size = 3.5, color = \"black\")"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/Notch_Analysis_updated.html","id":"multi-pathway-analysis-middle-age-vs--young-sspcs","dir":"Articles","previous_headings":"","what":"Multi-Pathway Analysis — Middle-Age vs. Young SSPCs","title":"Notch_Analysis","text":"","code":"HIf1a_pathwaydata <- LoadPathway(\"Hypoxia_24hr\", \"mouse\") Hippo_pathwaydata <- LoadPathway(\"HIPPO_heat\", \"mouse\") TGFb_pathwaydata <- LoadPathway(\"TGFB_Mouse\", \"mouse\") Wnt_pathwaydata <- LoadPathway(\"WNT3A_SLOPE_ACTIVATION\", \"mouse\") pathway_list <- list( HIF1a = HIf1a_pathwaydata, Hippo = Hippo_pathwaydata, TGFb = TGFb_pathwaydata, Wnt = Wnt_pathwaydata ) score_list <- list() cohens_d_list <- list() for (pathway_name in names(pathway_list)) { pathway_data <- pathway_list[[pathway_name]] matrix_data <- DataPreProcess(cluster_of_interest, pathway_data, Seurat.object = TRUE) pathway_stat <- PathwayMaxMin(matrix_data, pathway_data) score <- ComputeCellData(matrix_data, pathway_stat) score_list[[pathway_name]] <- score to_plot_p <- PreparePlotData(cluster_of_interest, score, \"Age\", Seurat.object = TRUE) age_stats_p <- CalculatePercentage(to_plot_p, \"Age\") cohens_d_list[[pathway_name]] <- abs(age_stats_p$cohens_d[1]) p <- PlotPathway(to_plot_p, pathway_name, \"Age\", c(\"orange\", \"#6baed6\")) + annotate(\"text\", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, label = make_label(age_stats_p, \"MiddleAge\", \"Young\"), size = 3.5, color = \"black\") print(p) ggsave( filename = paste0(\"figs/\", gsub(\"[^A-Za-z0-9_]\", \"_\", pathway_name), \"_age.png\"), plot = p, width = 5, height = 4, dpi = 300 ) }"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/Notch_Analysis_updated.html","id":"cross-pathway-comparison","dir":"Articles","previous_headings":"","what":"Cross-Pathway Comparison","title":"Notch_Analysis","text":"","code":"# Add Notch to score list (computed in notch-aging chunk) score_list[[\"Notch\"]] <- Notch_score cohens_d_list[[\"Notch\"]] <- abs(age_stats$cohens_d[1]) # Build score data frame aligned to metadata score_df <- as.data.frame(score_list) score_df$cell <- rownames(score_df) meta_df <- cluster_of_interest@meta.data meta_df$cell <- rownames(meta_df) score_df$Age <- meta_df$Age[match(score_df$cell, meta_df$cell)] score_df$Age_binary <- ifelse(score_df$Age == \"MiddleAge\", 1, 0) pathway_cols <- c(\"HIF1a\", \"Hippo\", \"TGFb\", \"Wnt\", \"Notch\") pathway_mat <- score_df[, pathway_cols] # Spearman correlation heatmap pathway_cor <- cor(pathway_mat, method = \"spearman\", use = \"pairwise.complete.obs\") print(round(pathway_cor, 3)) #> HIF1a Hippo TGFb Wnt Notch #> HIF1a 1.000 -0.016 0.097 0.039 0.118 #> Hippo -0.016 1.000 -0.025 -0.097 -0.042 #> TGFb 0.097 -0.025 1.000 0.020 0.050 #> Wnt 0.039 -0.097 0.020 1.000 0.080 #> Notch 0.118 -0.042 0.050 0.080 1.000 pheatmap( pathway_cor, color = colorRampPalette(c(\"#185FA5\", \"white\", \"#993C1D\"))(100), breaks = seq(-1, 1, length.out = 101), display_numbers = TRUE, number_format = \"%.2f\", fontsize_number = 10, main = \"Spearman Correlation Between Pathways\" ) # PCA of pathway activity space pca <- prcomp(pathway_mat, scale. = TRUE) p_pca <- data.frame(pca$x, Age = score_df$Age) ggplot(p_pca, aes(PC1, PC2, color = Age)) + geom_point(alpha = 0.6) + theme_classic() + labs(title = \"PCA of pathway activity space\") # AUROC per pathway compute_auroc_safe <- function(scores, labels) { valid <- !is.na(scores) & !is.na(labels) if (length(unique(labels[valid])) < 2) return(NA) r <- roc(labels[valid], scores[valid], quiet = TRUE) a <- as.numeric(auc(r)) if (a < 0.5) a <- 1 - a a } auroc_df <- data.frame( Pathway = pathway_cols, AUROC = sapply(pathway_cols, function(pw) { compute_auroc_safe(score_df[[pw]], score_df$Age_binary) }) ) auroc_df <- auroc_df[order(-auroc_df$AUROC), ] print(auroc_df) #> Pathway AUROC #> Notch Notch 0.6560963 #> Hippo Hippo 0.5862802 #> HIF1a HIF1a 0.5615532 #> Wnt Wnt 0.5368016 #> TGFb TGFb 0.5026313 p_auroc_age <- ggplot(auroc_df, aes(x = reorder(Pathway, AUROC), y = AUROC, fill = Pathway)) + geom_col(width = 0.6) + coord_flip() + geom_hline(yintercept = 0.5, linetype = \"dashed\") + geom_text(aes(label = sprintf(\"%.2f\", AUROC)), hjust = -0.1, size = 3) + ylim(0, 1.05) + labs(title = \"AUROC comparison across pathways\", x = NULL, y = \"AUROC\") + theme_classic() + theme(legend.position = \"none\") p_auroc_age # Cohen's d per pathway cohens_d_df <- data.frame( Pathway = names(cohens_d_list), Cohens_d = unlist(cohens_d_list) ) cohens_d_df <- cohens_d_df[order(-cohens_d_df$Cohens_d), ] print(cohens_d_df) #> Pathway Cohens_d #> Notch Notch 0.60484360 #> Hippo Hippo 0.37912152 #> HIF1a HIF1a 0.17792267 #> Wnt Wnt 0.14897250 #> TGFb TGFb 0.08659418 p_cd <- ggplot(cohens_d_df, aes(x = reorder(Pathway, Cohens_d), y = Cohens_d, fill = Pathway)) + geom_col(width = 0.6) + coord_flip() + geom_text(aes(label = sprintf(\"%.2f\", Cohens_d)), hjust = -0.1, size = 3) + ylim(0, max(cohens_d_df$Cohens_d) * 1.1) + labs(title = \"Effect size (Cohen's d) across pathways\", x = NULL, y = \"Cohen's d (absolute)\") + theme_classic() + theme(legend.position = \"none\") p_cd"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/Notch_Analysis_updated.html","id":"technical-confounders","dir":"Articles","previous_headings":"","what":"Technical Confounders","title":"Notch_Analysis","text":"","code":"cc_genes <- Seurat::cc.genes.updated.2019 cluster_of_interest <- CellCycleScoring( cluster_of_interest, s.features = cc_genes$s.genes, g2m.features = cc_genes$g2m.genes, set.ident = FALSE ) stress_genes <- c( \"Fos\", \"Jun\", \"Junb\", \"Atf3\", \"Egr1\", \"Ddit3\", \"Atf4\", \"Xbp1\", \"Hspa5\", \"Hspa1a\", \"Hspa1b\", \"Hsp90aa1\", \"Gadd45a\", \"Gadd45b\", \"Gadd45g\" ) cluster_of_interest <- AddModuleScore( cluster_of_interest, features = list(stress_genes), name = \"StressScore\", ctrl = 25, nbin = 24 ) meta_cc <- cluster_of_interest@meta.data # Merge scores with metadata score_df_full <- score_df score_df_full$S_score <- meta_cc$S.Score[ match(score_df_full$cell, rownames(meta_cc))] score_df_full$G2M_score <- meta_cc$G2M.Score[match(score_df_full$cell, rownames(meta_cc))] score_df_full$Stress <- cluster_of_interest$StressScore1[ match(score_df_full$cell, rownames(meta_cc))] score_df_full$nCount_RNA <- meta_cc$nCount_RNA[ match(score_df_full$cell, rownames(meta_cc))] score_df_full$nFeature_RNA <- meta_cc$nFeature_RNA[match(score_df_full$cell, rownames(meta_cc))] score_df_full$percent.mt <- meta_cc$percent.mt[ match(score_df_full$cell, rownames(meta_cc))] covariates <- c(\"nCount_RNA\", \"nFeature_RNA\", \"percent.mt\", \"Stress\", \"S_score\", \"G2M_score\") cor_mat <- sapply(covariates, function(cov) { sapply(pathway_cols, function(pw) { cor(score_df_full[[pw]], score_df_full[[cov]], method = \"spearman\", use = \"complete.obs\") }) }) rownames(cor_mat) <- pathway_cols colnames(cor_mat) <- covariates print(round(cor_mat, 3)) #> nCount_RNA nFeature_RNA percent.mt Stress S_score G2M_score #> HIF1a 0.315 0.286 -0.148 0.190 -0.031 -0.018 #> Hippo -0.140 -0.140 -0.048 0.028 0.051 0.055 #> TGFb 0.149 0.152 -0.017 0.002 0.016 -0.002 #> Wnt 0.116 0.136 -0.004 0.051 -0.003 0.001 #> Notch 0.181 0.204 0.019 0.161 -0.057 -0.062 pheatmap(cor_mat, color = colorRampPalette(c(\"#185FA5\", \"white\", \"#993C1D\"))(100), breaks = seq(-1, 1, length.out = 101), display_numbers = TRUE, number_format = \"%.2f\", fontsize_number = 10, main = \"Pathway vs. covariate correlations (Spearman)\") # Scatter: each pathway vs. stress score plot_df_long <- pivot_longer( score_df_full[, c(\"Stress\", pathway_cols)], cols = all_of(pathway_cols), names_to = \"Pathway\", values_to = \"Score\" ) cor_df_stress <- plot_df_long %>% group_by(Pathway) %>% summarise(cor = cor(Stress, Score, method = \"spearman\", use = \"complete.obs\"), .groups = \"drop\") ggplot(plot_df_long, aes(x = Stress, y = Score)) + geom_point(alpha = 0.4, size = 1.2) + geom_smooth(method = \"lm\", se = FALSE, linetype = \"dashed\", color = \"#E24B4A\") + facet_wrap(~ Pathway, scales = \"free_y\") + geom_text(data = cor_df_stress, aes(x = Inf, y = Inf, label = paste0(\"\\u03c1 = \", round(cor, 2))), hjust = 1.2, vjust = 1.5, inherit.aes = FALSE) + theme_classic() + labs(title = \"Pathway scores vs. stress score (Spearman)\", x = \"Stress score\", y = \"Pathway score\")"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/TGFB_database_construction.html","id":"overview","dir":"Articles","previous_headings":"","what":"Overview","title":"TGF-β Pathway Database Construction","text":"vignette documents construction TGF-β signaling pathway database used PathwayEmbed downstream pathway activity scoring embedding. construction workflow applied pathway databases package (e.g., WNT, NOTCH, YAP); TGF-β pathway used worked example. database integrates: manually curated pathway gene list organized functional category (KEGG hsa04350 ) Separately curated mouse ortholog lists, attention symbols differ substantially species Differential expression results two independent bulk RNA-seq datasets covering multiple species contexts Per-gene activity coefficients (+1 / −1) derived direction regulation TGF-β stimulation final output formatted Excel workbook (TGFB_Pathway_Database.xlsx) three sheets: human Day 1, human Day 20, mouse. Datasets used:","code":""},{"path":[]},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/TGFB_database_construction.html","id":"human-gene-list","dir":"Articles","previous_headings":"Step 1: Curate the Pathway Gene List","what":"Human Gene List","title":"TGF-β Pathway Database Construction","text":"TGF-β pathway genes curated KEGG hsa04350 organized 20 functional categories spanning canonical SMAD signaling, non-canonical branches (MAPK, PI3K/AKT, RHO), extracellular ligand/antagonist landscape.","code":"tgfb_genes_human <- list( Ligands_TGFB = c(\"TGFB1\", \"TGFB2\", \"TGFB3\"), Ligands_BMP = c(\"BMP2\", \"BMP4\", \"BMP5\", \"BMP6\", \"BMP7\", \"BMP8A\", \"BMP8B\", \"BMP10\", \"BMP15\", \"GDF5\", \"GDF6\", \"GDF7\"), # NOTE: INHBC and INHBE have no mouse orthologs (see mouse section) Ligands_Activin_GDF = c(\"INHBA\", \"INHBB\", \"INHBC\", \"INHBE\", \"GDF1\", \"GDF2\", \"GDF3\", \"GDF8\", \"GDF9\", \"GDF10\", \"GDF11\", \"GDF15\", \"AMH\", \"NODAL\"), Receptors_TypeI = c(\"TGFBR1\", \"ACVR1\", \"ACVR1B\", \"ACVR1C\", \"BMPR1A\", \"BMPR1B\", \"ACVRL1\"), Receptors_TypeII = c(\"TGFBR2\", \"ACVR2A\", \"ACVR2B\", \"BMPR2\", \"AMHR2\"), # Type III receptors act as co-receptors/presenters Receptors_TypeIII = c(\"TGFBR3\", \"ENG\"), # R-SMADs: phosphorylated by type I receptors; SMAD1/5/9 for BMP arm, # SMAD2/3 for TGF-β/Activin arm SMAD_Regulated = c(\"SMAD1\", \"SMAD2\", \"SMAD3\", \"SMAD5\", \"SMAD9\"), SMAD_Common = c(\"SMAD4\"), SMAD_Inhibitory = c(\"SMAD6\", \"SMAD7\"), # SARA (ZFYVE9) anchors SMAD2/3 at the receptor membrane SMAD_Anchors = c(\"SARA\", \"ZFYVE9\"), Coactivators = c(\"CREBBP\", \"EP300\", \"SKI\", \"SKIL\", \"CITED1\", \"CITED2\", \"FOXH1\", \"FOXO1\", \"FOXO3\", \"RUNX1\", \"RUNX2\", \"RUNX3\", \"SP1\", \"JUN\", \"FOS\", \"ATF2\"), Corepressors = c(\"TGIF1\", \"TGIF2\", \"SKI\", \"SKIL\", \"SIN3A\", \"NCOR1\", \"NCOR2\", \"HDAC1\", \"HDAC2\", \"HDAC3\"), E3_Ligases = c(\"SMURF1\", \"SMURF2\", \"NEDD4L\", \"WWP1\", \"WWP2\", \"RNF12\", \"STUB1\", \"TRIM33\"), Transcriptional_Targets = c( \"SERPINE1\", \"SMAD7\", \"CDKN1A\", \"CDKN2B\", \"MYC\", \"SNAI1\", \"SNAI2\", \"TWIST1\", \"ZEB1\", \"ZEB2\", \"VIM\", \"CDH1\", \"CDH2\", \"MMP2\", \"MMP9\", \"COL1A1\", \"COL1A2\", \"COL3A1\", \"FN1\", \"ACTA2\", \"CTGF\", \"TGFB1\", \"ID1\", \"ID2\", \"ID3\" ), Secreted_Antagonists = c( \"FST\", \"FSTL1\", \"FSTL3\", \"CHRD\", \"CHRDL1\", \"CHRDL2\", \"NOG\", \"GREM1\", \"GREM2\", \"NBL1\", \"BAMBI\", \"LTBP1\", \"LTBP2\", \"LTBP3\", \"LTBP4\", \"THBS1\", \"THBS2\", \"DCN\", \"BGN\", \"ASPN\" ), MAPK_Pathway = c( \"MAP3K7\", \"TAB1\", \"TAB2\", \"TAB3\", \"MAP2K3\", \"MAP2K4\", \"MAP2K6\", \"MAP2K7\", \"MAPK1\", \"MAPK3\", \"MAPK8\", \"MAPK9\", \"MAPK10\", \"MAPK11\", \"MAPK12\", \"MAPK13\", \"MAPK14\" ), PI3K_AKT_Pathway = c(\"PIK3CA\", \"PIK3CB\", \"PIK3CD\", \"PIK3R1\", \"PIK3R2\", \"AKT1\", \"AKT2\", \"AKT3\", \"MTOR\", \"RHEB\"), RHO_Pathway = c(\"RHOA\", \"RAC1\", \"CDC42\", \"ROCK1\", \"ROCK2\", \"TGFBR1\", \"PAK1\", \"PAK2\", \"LIMK1\", \"LIMK2\"), Latency_Activation = c( \"LTBP1\", \"LTBP2\", \"LTBP3\", \"LTBP4\", \"LRRC32\", \"LRRC33\", \"THBS1\", \"ITGAV\", \"ITGB1\", \"ITGB3\", \"ITGB5\", \"ITGB6\", \"ITGB8\", \"MMP2\", \"MMP9\" ), Phosphatases = c(\"PPM1A\", \"PPP1CA\", \"PPP1CB\", \"PPP1CC\", \"MTMR4\"), Nuclear_Transport = c(\"IMPORTIN7\", \"IMPORTIN8\", \"XPO1\", \"RAN\"), Other_Regulators = c( \"DAXX\", \"FNTA\", \"FKBP1A\", \"ELF\", \"YAP1\", \"TAZ\", \"PMEPA1\", \"TRIM33\", \"EVI1\", \"BCOR\", \"DRAP1\", \"MAML1\", \"PPP2CA\", \"PPP2R1A\", \"STRAP\", \"CDKN1B\", \"CDKN1C\", \"RBL1\", \"RBL2\", \"E2F4\", \"E2F5\", \"COPS5\" ) ) # Genes per category sapply(tgfb_genes_human, length) #> Ligands_TGFB Ligands_BMP Ligands_Activin_GDF #> 3 12 14 #> Receptors_TypeI Receptors_TypeII Receptors_TypeIII #> 7 5 2 #> SMAD_Regulated SMAD_Common SMAD_Inhibitory #> 5 1 2 #> SMAD_Anchors Coactivators Corepressors #> 2 16 10 #> E3_Ligases Transcriptional_Targets Secreted_Antagonists #> 8 25 20 #> MAPK_Pathway PI3K_AKT_Pathway RHO_Pathway #> 17 10 10 #> Latency_Activation Phosphatases Nuclear_Transport #> 15 5 4 #> Other_Regulators #> 22 cat(\"Total unique human TGF-β genes:\", length(unique(unlist(tgfb_genes_human))), \"\\n\") #> Total unique human TGF-β genes: 202"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/TGFB_database_construction.html","id":"mouse-gene-list","dir":"Articles","previous_headings":"Step 1: Curate the Pathway Gene List","what":"Mouse Gene List","title":"TGF-β Pathway Database Construction","text":"⚠️ Mouse symbols simply lowercased human symbols. mouse list curated manually special attention genes completely different symbols species. Key differences highlighted .","code":"# Critical human → mouse symbol differences: # RNF12 → Rlim (E3_Ligases) # IMPORTIN7 → Ipo7 (Nuclear_Transport) # IMPORTIN8 → Ipo8 (Nuclear_Transport) # TAZ (WWTR1) → Wwtr1 (Other_Regulators) # EVI1 (MECOM)→ Mecom (Other_Regulators) # SARA → removed (protein name, not gene; gene is Zfyve9) # INHBC, INHBE→ removed (no mouse ortholog) # ELF → removed (ambiguous; could be Elf1–5) tgfb_genes_mouse <- list( Ligands_TGFB = c(\"Tgfb1\", \"Tgfb2\", \"Tgfb3\"), Ligands_BMP = c(\"Bmp2\", \"Bmp4\", \"Bmp5\", \"Bmp6\", \"Bmp7\", \"Bmp8a\", \"Bmp8b\", \"Bmp10\", \"Bmp15\", \"Gdf5\", \"Gdf6\", \"Gdf7\"), # INHBC and INHBE have no mouse orthologs and are excluded Ligands_Activin_GDF = c(\"Inhba\", \"Inhbb\", \"Gdf1\", \"Gdf2\", \"Gdf3\", \"Gdf8\", \"Gdf9\", \"Gdf10\", \"Gdf11\", \"Gdf15\", \"Amh\", \"Nodal\"), Receptors_TypeI = c(\"Tgfbr1\", \"Acvr1\", \"Acvr1b\", \"Acvr1c\", \"Bmpr1a\", \"Bmpr1b\", \"Acvrl1\"), Receptors_TypeII = c(\"Tgfbr2\", \"Acvr2a\", \"Acvr2b\", \"Bmpr2\", \"Amhr2\"), Receptors_TypeIII = c(\"Tgfbr3\", \"Eng\"), SMAD_Regulated = c(\"Smad1\", \"Smad2\", \"Smad3\", \"Smad5\", \"Smad9\"), SMAD_Common = c(\"Smad4\"), SMAD_Inhibitory = c(\"Smad6\", \"Smad7\"), # SARA is a protein name for ZFYVE9; only the gene symbol is used SMAD_Anchors = c(\"Zfyve9\"), Coactivators = c(\"Crebbp\", \"Ep300\", \"Ski\", \"Skil\", \"Cited1\", \"Cited2\", \"Foxh1\", \"Foxo1\", \"Foxo3\", \"Runx1\", \"Runx2\", \"Runx3\", \"Sp1\", \"Jun\", \"Fos\", \"Atf2\"), Corepressors = c(\"Tgif1\", \"Tgif2\", \"Ski\", \"Skil\", \"Sin3a\", \"Ncor1\", \"Ncor2\", \"Hdac1\", \"Hdac2\", \"Hdac3\"), # RNF12 (human) = Rlim (mouse) — different symbol! E3_Ligases = c(\"Smurf1\", \"Smurf2\", \"Nedd4l\", \"Wwp1\", \"Wwp2\", \"Rlim\", \"Stub1\", \"Trim33\"), Transcriptional_Targets = c( \"Serpine1\", \"Smad7\", \"Cdkn1a\", \"Cdkn2b\", \"Myc\", \"Snai1\", \"Snai2\", \"Twist1\", \"Zeb1\", \"Zeb2\", \"Vim\", \"Cdh1\", \"Cdh2\", \"Mmp2\", \"Mmp9\", \"Col1a1\", \"Col1a2\", \"Col3a1\", \"Fn1\", \"Acta2\", \"Ctgf\", \"Tgfb1\", \"Id1\", \"Id2\", \"Id3\" ), Secreted_Antagonists = c( \"Fst\", \"Fstl1\", \"Fstl3\", \"Chrd\", \"Chrdl1\", \"Chrdl2\", \"Nog\", \"Grem1\", \"Grem2\", \"Nbl1\", \"Bambi\", \"Ltbp1\", \"Ltbp2\", \"Ltbp3\", \"Ltbp4\", \"Thbs1\", \"Thbs2\", \"Dcn\", \"Bgn\", \"Aspn\" ), MAPK_Pathway = c(\"Map3k7\", \"Tab1\", \"Tab2\", \"Tab3\", \"Map2k3\", \"Map2k4\", \"Map2k6\", \"Map2k7\", \"Mapk1\", \"Mapk3\", \"Mapk8\", \"Mapk9\", \"Mapk10\", \"Mapk11\", \"Mapk12\", \"Mapk13\", \"Mapk14\"), PI3K_AKT_Pathway = c(\"Pik3ca\", \"Pik3cb\", \"Pik3cd\", \"Pik3r1\", \"Pik3r2\", \"Akt1\", \"Akt2\", \"Akt3\", \"Mtor\", \"Rheb\"), RHO_Pathway = c(\"Rhoa\", \"Rac1\", \"Cdc42\", \"Rock1\", \"Rock2\", \"Tgfbr1\", \"Pak1\", \"Pak2\", \"Limk1\", \"Limk2\"), Latency_Activation = c(\"Ltbp1\", \"Ltbp2\", \"Ltbp3\", \"Ltbp4\", \"Lrrc32\", \"Lrrc33\", \"Thbs1\", \"Itgav\", \"Itgb1\", \"Itgb3\", \"Itgb5\", \"Itgb6\", \"Itgb8\", \"Mmp2\", \"Mmp9\"), Phosphatases = c(\"Ppm1a\", \"Ppp1ca\", \"Ppp1cb\", \"Ppp1cc\", \"Mtmr4\"), # IMPORTIN7 = Ipo7, IMPORTIN8 = Ipo8 in mouse Nuclear_Transport = c(\"Ipo7\", \"Ipo8\", \"Xpo1\", \"Ran\"), # TAZ = Wwtr1 (mouse), EVI1 = Mecom (mouse) Other_Regulators = c(\"Daxx\", \"Fnta\", \"Fkbp1a\", \"Yap1\", \"Wwtr1\", \"Pmepa1\", \"Trim33\", \"Mecom\", \"Bcor\", \"Drap1\", \"Maml1\", \"Ppp2ca\", \"Ppp2r1a\", \"Strap\", \"Cdkn1b\", \"Cdkn1c\", \"Rbl1\", \"Rbl2\", \"E2f4\", \"E2f5\", \"Cops5\") ) cat(\"Total unique mouse TGF-β genes:\", length(unique(unlist(tgfb_genes_mouse))), \"\\n\") #> Total unique mouse TGF-β genes: 198"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/TGFB_database_construction.html","id":"flatten-to-data-frames","dir":"Articles","previous_headings":"Step 1: Curate the Pathway Gene List","what":"Flatten to Data Frames","title":"TGF-β Pathway Database Construction","text":"lists converted flat two-column data frames (gene, category) downstream joining operations.","code":"flatten_gene_list <- function(gene_list) { do.call(rbind, lapply(names(gene_list), function(cat) { data.frame(gene = gene_list[[cat]], category = cat, stringsAsFactors = FALSE) })) } tgfb_genes_human_flat <- flatten_gene_list(tgfb_genes_human) tgfb_genes_mouse_flat <- flatten_gene_list(tgfb_genes_mouse) head(tgfb_genes_human_flat) #> gene category #> 1 TGFB1 Ligands_TGFB #> 2 TGFB2 Ligands_TGFB #> 3 TGFB3 Ligands_TGFB #> 4 BMP2 Ligands_BMP #> 5 BMP4 Ligands_BMP #> 6 BMP5 Ligands_BMP"},{"path":[]},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/TGFB_database_construction.html","id":"human-lung-fibroblasts-gse110021","dir":"Articles","previous_headings":"Step 2: Bulk RNA-seq Differential Expression","what":"Human — Lung Fibroblasts (GSE110021)","title":"TGF-β Pathway Database Construction","text":"Human WI-38 fibroblasts treated TGFβ1 profiled Day 1 (acute response) Day 20 (chronic/fibrotic response). dataset provides voom-normalized log-counts, limma applied directly without normalization.","code":"library(limma) # Load voom-normalized expression matrix data_fibroblasts <- read.table( \"GSE110021_counts.voom.annot.txt.gz\", header = TRUE, sep = \"\\t\", row.names = 1 ) # Separate expression values from annotation columns expr <- as.matrix(data_fibroblasts[, -(1:2)]) rownames(expr) <- data_fibroblasts$GeneSymbol # Sample metadata: 24 samples total, 12 per treatment, 6 per timepoint per treatment sample_info <- data.frame( sample = colnames(expr), treatment = rep(c(\"noTGFb\", \"TGFb\"), each = 12), timepoint = rep(c(\"D1\", \"D20\"), each = 6, times = 2) ) # Design matrix with all four groups design <- model.matrix(~ 0 + treatment:timepoint, data = sample_info) colnames(design) <- c(\"D1_noTGFb\", \"D1_TGFb\", \"D20_noTGFb\", \"D20_TGFb\") fit <- lmFit(expr, design) # Contrasts: TGFb vs. control at each timepoint contrast_matrix <- makeContrasts( D1_TGFb_vs_noTGFb = D1_TGFb - D1_noTGFb, D20_TGFb_vs_noTGFb = D20_TGFb - D20_noTGFb, levels = design ) fit2 <- contrasts.fit(fit, contrast_matrix) fit2 <- eBayes(fit2) # Extract full results tables res_D1 <- topTable(fit2, coef = \"D1_TGFb_vs_noTGFb\", number = Inf, sort.by = \"p\") res_D20 <- topTable(fit2, coef = \"D20_TGFb_vs_noTGFb\", number = Inf, sort.by = \"p\") # Add gene descriptions res_D1$Description <- data_fibroblasts$Description[match(rownames(res_D1), data_fibroblasts$GeneSymbol)] res_D20$Description <- data_fibroblasts$Description[match(rownames(res_D20), data_fibroblasts$GeneSymbol)] write.csv(res_D1, \"DEG_D1_TGFb_vs_noTGFb.csv\", row.names = TRUE) write.csv(res_D20, \"DEG_D20_TGFb_vs_noTGFb.csv\", row.names = TRUE)"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/TGFB_database_construction.html","id":"mouse-t-cells-gse246932","dir":"Articles","previous_headings":"Step 2: Bulk RNA-seq Differential Expression","what":"Mouse — T Cells (GSE246932)","title":"TGF-β Pathway Database Construction","text":"Mouse CD8+ T cells treated TGFβ 2 hours. Raw count data required DESeq2 normalization differential testing.","code":"library(DESeq2) library(dplyr) # Load raw counts counts_data <- read.csv( \"GSE246932_220809-P490-1_RawGeneCounts.csv.gz\", header = TRUE, check.names = FALSE ) # Remove SIINFEKL peptide-treated samples (not relevant to TGFb comparison) counts_data <- counts_data[, !grepl(\"SIINFEKL\", colnames(counts_data))] # Separate gene annotation from count columns gene_anno <- counts_data[, 1:4] counts_only <- counts_data[, -(1:4)] # Collapse duplicate gene IDs by summing counts_collapsed <- counts_only %>% mutate(geneId = gene_anno$geneId) %>% group_by(geneId) %>% summarise(across(where(is.numeric), sum), .groups = \"drop\") counts_mat <- as.matrix(counts_collapsed[, -1]) rownames(counts_mat) <- counts_collapsed$geneId # Build DESeq2 object sample_names <- colnames(counts_mat) coldata <- data.frame( treatment = factor( ifelse(grepl(\"TGFb\", sample_names), \"TGFb\", \"none\"), levels = c(\"none\", \"TGFb\") ), row.names = sample_names ) dds <- DESeqDataSetFromMatrix( countData = counts_mat, colData = coldata, design = ~ treatment ) dds <- dds[rowSums(counts(dds)) > 10, ] # low-count filter dds <- DESeq(dds) res <- results(dds, contrast = c(\"treatment\", \"TGFb\", \"none\")) res_df <- as.data.frame(res) # Map gene names back from annotation res_df$geneId <- rownames(res_df) res_df$geneName <- gene_anno$geneName[match(res_df$geneId, gene_anno$geneId)] res_df$description <- gene_anno$description[match(res_df$geneId, gene_anno$geneId)] library(openxlsx) write.xlsx(res_df, file = \"Mus_TGFb_vs_none.xlsx\", rowNames = FALSE)"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/TGFB_database_construction.html","id":"step-3-filter-for-tgf-β-pathway-genes","dir":"Articles","previous_headings":"","what":"Step 3: Filter for TGF-β Pathway Genes","title":"TGF-β Pathway Database Construction","text":"DEG results joined curated gene lists, retaining TGF-β pathway members reach statistical significance (adjusted p < 0.05).","code":"library(readr) library(readxl) library(dplyr) human_d1 <- read_csv(\"DEG_D1_TGFb_vs_noTGFb.csv\") human_d20 <- read_csv(\"DEG_D20_TGFb_vs_noTGFb.csv\") mouse_df <- read_excel(\"Mus_TGFb_vs_none.xlsx\") # Human Day 1 human_d1_results <- human_d1 %>% filter(ID %in% tgfb_genes_human_flat$gene) %>% left_join(tgfb_genes_human_flat, by = c(\"ID\" = \"gene\")) %>% filter(!is.na(adj.P.Val) & adj.P.Val < 0.05) %>% arrange(adj.P.Val) # Human Day 20 human_d20_results <- human_d20 %>% filter(ID %in% tgfb_genes_human_flat$gene) %>% left_join(tgfb_genes_human_flat, by = c(\"ID\" = \"gene\")) %>% filter(!is.na(adj.P.Val) & adj.P.Val < 0.05) %>% arrange(adj.P.Val) # Mouse mouse_df_results <- mouse_df %>% filter(geneName %in% tgfb_genes_mouse_flat$gene) %>% left_join(tgfb_genes_mouse_flat, by = c(\"geneName\" = \"gene\")) %>% filter(!is.na(padj) & padj < 0.05) %>% arrange(padj) cat(\"Human D1 pathway genes (padj<0.05):\", nrow(human_d1_results), \"\\n\") cat(\"Human D20 pathway genes (padj<0.05):\", nrow(human_d20_results), \"\\n\") cat(\"Mouse pathway genes (padj<0.05):\", nrow(mouse_df_results), \"\\n\")"},{"path":[]},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/TGFB_database_construction.html","id":"rationale","dir":"Articles","previous_headings":"Step 4: Assign Activity Coefficients","what":"Rationale","title":"TGF-β Pathway Database Construction","text":"gene receives direction coefficient reflecting behavior TGFβ activation: coefficients used PathwayEmbed compute signed pathway activity score: weighted sum sample’s expression values multiplied coefficients, giving single number reflects net direction magnitude TGF-β activity. function also supports inhibitor experiments via TGFB_activation = FALSE, flips sign logic — gene downregulated inhibitor inferred positively regulated activation. Threshold note: fc_threshold = 0 assigns coefficient non-zero fold-change. stricter databases, use fc_threshold = 0.5 restrict genes |log₂FC| ≥ 0.5, focusing robust responses.","code":"assign_coefficient_tgfb <- function(log2FoldChange, fc_threshold = 0, TGFB_activation = TRUE) { if (is.na(log2FoldChange)) return(0) if (TGFB_activation) { if (log2FoldChange > fc_threshold) return( 1) else if (log2FoldChange < -fc_threshold) return(-1) else return( 0) } else { # Inhibitor data: flip direction if (log2FoldChange < -fc_threshold) return( 1) else if (log2FoldChange > fc_threshold) return(-1) else return( 0) } } human_d1_results <- human_d1_results %>% mutate(coef = sapply(logFC, assign_coefficient_tgfb, fc_threshold = 0)) human_d20_results <- human_d20_results %>% mutate(coef = sapply(logFC, assign_coefficient_tgfb, fc_threshold = 0)) mouse_df_results <- mouse_df_results %>% mutate(coef = sapply(log2FoldChange, assign_coefficient_tgfb, fc_threshold = 0))"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/TGFB_database_construction.html","id":"step-5-export-to-excel","dir":"Articles","previous_headings":"","what":"Step 5: Export to Excel","title":"TGF-β Pathway Database Construction","text":"final database exported formatted .xlsx workbook styled header row, frozen pane, auto-sized columns.","code":"library(openxlsx) # --- Helper: prepare one sheet's data frame --- prepare_sheet <- function(results, gene_col, logfc_col) { results %>% dplyr::select( Gene_Symbol = !!sym(gene_col), Category = category, Coefficient = coef, log2FoldChange = !!sym(logfc_col) ) %>% as.data.frame() } human_d1_sheet <- prepare_sheet(human_d1_results, \"ID\", \"logFC\") human_d20_sheet <- prepare_sheet(human_d20_results, \"ID\", \"logFC\") mouse_df_sheet <- prepare_sheet(mouse_df_results, \"geneName\", \"log2FoldChange\") # --- Helper: write one formatted sheet --- add_pathway_sheet <- function(wb, sheet_name, df) { addWorksheet(wb, sheet_name) writeData(wb, sheet_name, df, headerStyle = createStyle( fontSize = 11, fontColour = \"#FFFFFF\", halign = \"center\", fgFill = \"#4472C4\", border = \"TopBottom\", fontName = \"Arial\", textDecoration = \"bold\" ) ) freezePane(wb, sheet_name, firstRow = TRUE) tryCatch( setColWidths(wb, sheet_name, cols = seq_len(ncol(df)), widths = \"auto\"), error = function(e) setColWidths(wb, sheet_name, cols = seq_len(ncol(df)), widths = 15) ) } # --- Build workbook --- wb <- createWorkbook() add_pathway_sheet(wb, \"TGFB_Human_D1\", human_d1_sheet) add_pathway_sheet(wb, \"TGFB_Human_D20\", human_d20_sheet) add_pathway_sheet(wb, \"TGFB_Mouse\", mouse_df_sheet) saveWorkbook(wb, \"TGFB_Pathway_Database.xlsx\", overwrite = TRUE) cat(\"Saved: TGFB_Pathway_Database.xlsx\\n\")"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/TGFB_database_construction.html","id":"final-database-structure","dir":"Articles","previous_headings":"","what":"Final Database Structure","title":"TGF-β Pathway Database Construction","text":"sheet TGFB_Pathway_Database.xlsx contains: Sheets produced:","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/TGFB_database_construction.html","id":"important-curation-notes","dir":"Articles","previous_headings":"","what":"Important Curation Notes","title":"TGF-β Pathway Database Construction","text":"following caveats kept mind extending modifying database: Genes excluded mouse list due ortholog: INHBC, INHBE — activin subunits primate-specific mouse ortholog. Gene name ambiguities resolved: SARA protein alias gene ZFYVE9 used gene symbol. ELF ambiguous (refer ELF1 ELF5) removed mouse list. Genes completely different human/mouse symbols: Always verify mouse gene symbols MGI adding new genes.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/TGFB_database_construction.html","id":"session-information","dir":"Articles","previous_headings":"","what":"Session Information","title":"TGF-β Pathway Database Construction","text":"","code":"sessionInfo() #> R version 4.4.2 (2024-10-31) #> Platform: aarch64-apple-darwin20 #> Running under: macOS Sonoma 14.6 #> #> Matrix products: default #> BLAS: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRblas.0.dylib #> LAPACK: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.0 #> #> locale: #> [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8 #> #> time zone: America/New_York #> tzcode source: internal #> #> attached base packages: #> [1] stats graphics grDevices utils datasets methods base #> #> loaded via a namespace (and not attached): #> [1] digest_0.6.39 desc_1.4.3 R6_2.6.1 fastmap_1.2.0 #> [5] xfun_0.57 cachem_1.1.0 knitr_1.51 htmltools_0.5.9 #> [9] rmarkdown_2.30 lifecycle_1.0.5 cli_3.6.5 sass_0.4.10 #> [13] pkgdown_2.2.0 textshaping_1.0.5 jquerylib_0.1.4 systemfonts_1.3.2 #> [17] compiler_4.4.2 rstudioapi_0.18.0 tools_4.4.2 ragg_1.5.1 #> [21] bslib_0.10.0 evaluate_1.0.5 yaml_2.3.12 otel_0.2.0 #> [25] jsonlite_2.0.0 htmlwidgets_1.6.4 rlang_1.1.7 fs_1.6.7"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/beta_catenin_ko_updated.html","id":"overview","dir":"Articles","previous_headings":"","what":"Overview","title":"Beta-Catenin Knockout Analysis with PathwayEmbed","text":"vignette demonstrates application PathwayEmbed beta-catenin perturbed system Ctnnb1 upstream enhancer depleted intestinal epithelia. KO genotype known design, dataset provides clean biological ground truth direct AUROC benchmark PROGENy AddModuleScore. Reference: Hua et al., eLife 13: RP98238 (2024). https://doi.org/10.7554/eLife.98238","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/beta_catenin_ko_updated.html","id":"load-packages","dir":"Articles","previous_headings":"","what":"Load Packages","title":"Beta-Catenin Knockout Analysis with PathwayEmbed","text":"","code":"library(PathwayEmbed) library(Seurat) library(ggplot2) library(patchwork) library(pheatmap) library(progeny) library(pROC)"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/beta_catenin_ko_updated.html","id":"helper-annotation-label-builder","dir":"Articles","previous_headings":"","what":"Helper: Annotation Label Builder","title":"Beta-Catenin Knockout Analysis with PathwayEmbed","text":"","code":"make_label <- function(stats, group1, group2) { d <- round(stats$cohens_d[1], 3) p <- formatC(stats$p_value[1], format = \"e\", digits = 2) on1 <- stats$percentage_on[stats$group == group1] off1 <- stats$percentage_off[stats$group == group1] on2 <- stats$percentage_on[stats$group == group2] off2 <- stats$percentage_off[stats$group == group2] paste0( group1, \": ON=\", on1, \"%, OFF=\", off1, \"%\\n\", group2, \": ON=\", on2, \"%, OFF=\", off2, \"%\\n\", \"Cohen's d = \", d, \"\\n\", \"p = \", p ) }"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/beta_catenin_ko_updated.html","id":"download-data","dir":"Articles","previous_headings":"","what":"Download Data","title":"Beta-Catenin Knockout Analysis with PathwayEmbed","text":"","code":"url_ko <- \"https://ftp.ncbi.nlm.nih.gov/geo/series/GSE233nnn/GSE233978/suppl/GSE233978_KO_filtered_feature_bc_matrix.h5\" url_wt <- \"https://ftp.ncbi.nlm.nih.gov/geo/series/GSE233nnn/GSE233978/suppl/GSE233978_WT_filtered_feature_bc_matrix.h5\" download.file(url_ko, destfile = \"GSE233978_KO_filtered_feature_bc_matrix.h5\", mode = \"wb\") download.file(url_wt, destfile = \"GSE233978_WT_filtered_feature_bc_matrix.h5\", mode = \"wb\")"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/beta_catenin_ko_updated.html","id":"data-preparation-and-preprocessing","dir":"Articles","previous_headings":"","what":"Data Preparation and Preprocessing","title":"Beta-Catenin Knockout Analysis with PathwayEmbed","text":"","code":"ko_data <- Read10X_h5(\"GSE233978_KO_filtered_feature_bc_matrix.h5\") wt_data <- Read10X_h5(\"GSE233978_WT_filtered_feature_bc_matrix.h5\") ko <- CreateSeuratObject(counts = ko_data, project = \"KO\", min.cells = 3, min.features = 200) wt <- CreateSeuratObject(counts = wt_data, project = \"WT\", min.cells = 3, min.features = 200) ko$sample <- \"KO\" wt$sample <- \"WT\" merged <- merge(ko, wt) merged[[\"RNA\"]] <- JoinLayers(merged[[\"RNA\"]]) merged <- NormalizeData(merged, normalization.method = \"LogNormalize\", scale.factor = 10000) merged <- FindVariableFeatures(merged, selection.method = \"vst\", nfeatures = 2000) merged <- ScaleData(merged, features = VariableFeatures(merged))"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/beta_catenin_ko_updated.html","id":"wnt-pathway-scoring","dir":"Articles","previous_headings":"","what":"Wnt Pathway Scoring","title":"Beta-Catenin Knockout Analysis with PathwayEmbed","text":"","code":"Wnt_12h <- LoadPathway(\"WNT3A_12H_ACTIVATION\", \"mouse\") Wnt_24h <- LoadPathway(\"WNT3A_24H_ACTIVATION\", \"mouse\") Wnt_48h <- LoadPathway(\"WNT3A_48H_ACTIVATION\", \"mouse\") Wnt_slope <- LoadPathway(\"WNT3A_SLOPE_ACTIVATION\", \"mouse\") matrix_12h <- DataPreProcess(merged, Wnt_12h, Seurat.object = TRUE) matrix_24h <- DataPreProcess(merged, Wnt_24h, Seurat.object = TRUE) matrix_48h <- DataPreProcess(merged, Wnt_48h, Seurat.object = TRUE) matrix_slope <- DataPreProcess(merged, Wnt_slope, Seurat.object = TRUE) pathwaystat_12h <- PathwayMaxMin(matrix_12h, Wnt_12h) pathwaystat_24h <- PathwayMaxMin(matrix_24h, Wnt_24h) pathwaystat_48h <- PathwayMaxMin(matrix_48h, Wnt_48h) pathwaystat_slope <- PathwayMaxMin(matrix_slope, Wnt_slope) score_12h <- ComputeCellData(matrix_12h, pathwaystat_12h) score_24h <- ComputeCellData(matrix_24h, pathwaystat_24h) score_48h <- ComputeCellData(matrix_48h, pathwaystat_48h) score_slope <- ComputeCellData(matrix_slope, pathwaystat_slope)"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/beta_catenin_ko_updated.html","id":"visualization","dir":"Articles","previous_headings":"","what":"Visualization","title":"Beta-Catenin Knockout Analysis with PathwayEmbed","text":"","code":"plot_data_12h <- PreparePlotData(merged, score_12h, \"sample\", Seurat.object = TRUE) plot_data_24h <- PreparePlotData(merged, score_24h, \"sample\", Seurat.object = TRUE) plot_data_48h <- PreparePlotData(merged, score_48h, \"sample\", Seurat.object = TRUE) plot_data_slope <- PreparePlotData(merged, score_slope, \"sample\", Seurat.object = TRUE) pct_12h <- CalculatePercentage(plot_data_12h, \"sample\") pct_24h <- CalculatePercentage(plot_data_24h, \"sample\") pct_48h <- CalculatePercentage(plot_data_48h, \"sample\") pct_slope <- CalculatePercentage(plot_data_slope, \"sample\") pct_12h; pct_24h; pct_48h; pct_slope #> # A tibble: 2 × 5 #> group percentage_on percentage_off cohens_d p_value #> #> 1 KO 50.5 49.5 -0.0728 2.50e-12 #> 2 WT 53.6 46.4 -0.0728 2.50e-12 #> # A tibble: 2 × 5 #> group percentage_on percentage_off cohens_d p_value #> #> 1 KO 57.7 42.3 0.0748 5.27e-12 #> 2 WT 51.4 48.6 0.0748 5.27e-12 #> # A tibble: 2 × 5 #> group percentage_on percentage_off cohens_d p_value #> #> 1 KO 41.7 58.3 -0.136 3.52e-36 #> 2 WT 50.8 49.2 -0.136 3.52e-36 #> # A tibble: 2 × 5 #> group percentage_on percentage_off cohens_d p_value #> #> 1 KO 38.0 62.0 -0.301 6.49e-147 #> 2 WT 52.0 48.0 -0.301 6.49e-147 p_12h <- PlotPathway(plot_data_12h, \"Wnt 12h\", \"sample\", c(\"#ae282c\", \"#2066a8\")) + annotate(\"text\", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, label = make_label(pct_12h, \"KO\", \"WT\"), size = 3.5, color = \"black\") p_24h <- PlotPathway(plot_data_24h, \"Wnt 24h\", \"sample\", c(\"#ae282c\", \"#2066a8\")) + annotate(\"text\", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, label = make_label(pct_24h, \"KO\", \"WT\"), size = 3.5, color = \"black\") p_48h <- PlotPathway(plot_data_48h, \"Wnt 48h\", \"sample\", c(\"#ae282c\", \"#2066a8\")) + annotate(\"text\", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, label = make_label(pct_48h, \"KO\", \"WT\"), size = 3.5, color = \"black\") p_slope <- PlotPathway(plot_data_slope, \"Wnt (slope)\", \"sample\", c(\"#ae282c\", \"#2066a8\")) + annotate(\"text\", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, label = make_label(pct_slope, \"KO\", \"WT\"), size = 3.5, color = \"black\") p_12h; p_24h; p_48h; p_slope"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/beta_catenin_ko_updated.html","id":"technical-confounders","dir":"Articles","previous_headings":"","what":"Technical Confounders","title":"Beta-Catenin Knockout Analysis with PathwayEmbed","text":"","code":"merged[[\"percent.mt\"]] <- PercentageFeatureSet(merged, pattern = \"^mt-\") seurat_meta <- merged@meta.data make_scatter <- function(df, x_col, x_label) { r <- cor(df$embed_score, df[[x_col]], method = \"spearman\", use = \"complete.obs\") ggplot(df, aes(x = .data[[x_col]], y = embed_score)) + geom_point(alpha = 0.3, size = 0.8, color = \"#534AB7\") + geom_smooth(method = \"lm\", color = \"#E24B4A\", linewidth = 0.8, se = TRUE) + labs(title = sprintf(\"%s (rho = %.3f)\", x_label, r), x = x_label, y = \"PathwayEmbed score\") + theme_minimal() } confounder_df <- data.frame( cell = names(score_slope), embed_score = as.numeric(score_slope), nCount_RNA = seurat_meta[names(score_slope), \"nCount_RNA\"], nFeature_RNA = seurat_meta[names(score_slope), \"nFeature_RNA\"], percent_mt = seurat_meta[names(score_slope), \"percent.mt\"] ) for (cov in c(\"nCount_RNA\", \"nFeature_RNA\", \"percent_mt\")) { r <- cor(confounder_df$embed_score, confounder_df[[cov]], method = \"spearman\", use = \"complete.obs\") cat(sprintf(\"Spearman vs %-15s : %.3f\\n\", cov, r)) } #> Spearman vs nCount_RNA : 0.188 #> Spearman vs nFeature_RNA : 0.262 #> Spearman vs percent_mt : -0.119 (make_scatter(confounder_df, \"nCount_RNA\", \"nCount_RNA\") + make_scatter(confounder_df, \"nFeature_RNA\", \"nFeature_RNA\") + make_scatter(confounder_df, \"percent_mt\", \"percent.mt\"))"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/beta_catenin_ko_updated.html","id":"benchmark-against-progeny-and-addmodulescore","dir":"Articles","previous_headings":"","what":"Benchmark Against PROGENy and AddModuleScore","title":"Beta-Catenin Knockout Analysis with PathwayEmbed","text":"","code":"normalized_mat <- GetAssayData(merged, assay = \"RNA\", layer = \"data\") normalized_mat_dense <- as.matrix(normalized_mat) common_genes <- intersect(rownames(normalized_mat_dense), Wnt_slope$Gene_Symbol) gene_matrix <- normalized_mat_dense[common_genes, ] mean_expr <- colMeans(gene_matrix, na.rm = TRUE) zscore_mean_per_cell <- colMeans(t(scale(t(gene_matrix))), na.rm = TRUE) progeny_scores <- progeny( normalized_mat_dense, scale = TRUE, organism = \"Mouse\", top = 100, perm = 1 ) progeny_wnt <- setNames(as.numeric(progeny_scores[, \"WNT\"]), rownames(progeny_scores)) wnt_features <- rownames(matrix_slope) merged <- AddModuleScore( object = merged, features = list(wnt_features), name = \"WNT_ModuleScore\", ctrl = 5, nbin = 10 ) module_score <- setNames( merged@meta.data$WNT_ModuleScore1, rownames(merged@meta.data) ) cells <- names(score_slope) benchmark_df <- data.frame( PathwayEmbed = as.numeric(score_slope), PROGENy = as.numeric(progeny_wnt[cells]), AddModuleScore = as.numeric(module_score[cells]), mean_expr = as.numeric(mean_expr[cells]), zscore_expr = as.numeric(zscore_mean_per_cell[cells]), row.names = cells ) benchmark_cor <- cor(benchmark_df, method = \"spearman\", use = \"pairwise.complete.obs\") print(round(benchmark_cor, 3)) #> PathwayEmbed PROGENy AddModuleScore mean_expr zscore_expr #> PathwayEmbed 1.000 0.095 0.106 0.359 0.356 #> PROGENy 0.095 1.000 -0.180 0.367 0.362 #> AddModuleScore 0.106 -0.180 1.000 0.146 0.139 #> mean_expr 0.359 0.367 0.146 1.000 0.972 #> zscore_expr 0.356 0.362 0.139 0.972 1.000 p_cor <- pheatmap( benchmark_cor, color = colorRampPalette(c(\"#185FA5\", \"white\", \"#993C1D\"))(100), breaks = seq(-1, 1, length.out = 101), display_numbers = TRUE, number_format = \"%.2f\", fontsize_number = 9, main = \"Method Benchmark — Spearman Correlation (Ctnnb1 KO dataset)\" ) p_cor ko_label <- ifelse(merged@meta.data[cells, \"sample\"] == \"KO\", 1L, 0L) compute_auroc <- function(scores, labels) { r <- roc(labels, scores, quiet = TRUE) auc_val <- as.numeric(auc(r)) if (auc_val < 0.5) auc_val <- 1 - auc_val auc_val } auroc_results <- data.frame( Method = colnames(benchmark_df), AUROC = sapply(benchmark_df, compute_auroc, labels = ko_label) ) auroc_results <- auroc_results[order(-auroc_results$AUROC), ] print(auroc_results) #> Method AUROC #> AddModuleScore AddModuleScore 0.6827026 #> mean_expr mean_expr 0.6482098 #> zscore_expr zscore_expr 0.6425566 #> PathwayEmbed PathwayEmbed 0.5897700 #> PROGENy PROGENy 0.5106677 compute_cohens_d_method <- function(scores_vec, seurat_obj, group_col) { pd <- PreparePlotData(seurat_obj, scores_vec, group_col, Seurat.object = TRUE) pct <- CalculatePercentage(pd, group_var = group_col) abs(pct$cohens_d[1]) } cohens_d_results <- data.frame( Method = colnames(benchmark_df), Cohens_d = sapply( colnames(benchmark_df), function(m) { sv <- setNames(benchmark_df[[m]], rownames(benchmark_df)) compute_cohens_d_method(sv, merged, \"sample\") } ) ) cohens_d_results <- cohens_d_results[order(-cohens_d_results$Cohens_d), ] print(cohens_d_results) #> Method Cohens_d #> AddModuleScore AddModuleScore 0.64575350 #> mean_expr mean_expr 0.54020251 #> zscore_expr zscore_expr 0.51565732 #> PathwayEmbed PathwayEmbed 0.30056596 #> PROGENy PROGENy 0.03129493 method_colors <- c( \"PathwayEmbed\" = \"#534AB7\", \"PROGENy\" = \"#E24B4A\", \"AddModuleScore\" = \"#EF9F27\", \"mean_expr\" = \"#888780\", \"zscore_expr\" = \"#B4B2A9\" ) p_cd <- ggplot(cohens_d_results, aes(x = reorder(Method, Cohens_d), y = Cohens_d, fill = Method)) + geom_bar(stat = \"identity\", width = 0.6) + coord_flip() + scale_fill_manual(values = method_colors) + labs(title = \"Effect size (Cohen's d): KO vs. WT\", x = NULL, y = \"Cohen's d (absolute)\") + theme_classic() + theme(legend.position = \"none\") p_cd p_auroc <- ggplot(auroc_results, aes(x = reorder(Method, AUROC), y = AUROC, fill = Method)) + geom_bar(stat = \"identity\", width = 0.6) + geom_hline(yintercept = 0.5, linetype = \"dashed\", color = \"black\") + coord_flip() + scale_fill_manual(values = method_colors) + labs(title = \"AUROC: KO vs. WT separation (Ctnnb1 KO dataset)\", x = NULL, y = \"AUROC\") + ylim(0, 1) + theme_classic() + theme(legend.position = \"none\") p_auroc roc_list <- lapply(colnames(benchmark_df), function(m) { roc(ko_label, benchmark_df[[m]], quiet = TRUE) }) names(roc_list) <- colnames(benchmark_df) roc_df <- do.call(rbind, lapply(names(roc_list), function(m) { r <- roc_list[[m]] data.frame(Method = m, FPR = 1 - r$specificities, TPR = r$sensitivities) })) p_roc <- ggplot(roc_df, aes(x = FPR, y = TPR, color = Method)) + geom_line(linewidth = 0.9) + geom_abline(intercept = 0, slope = 1, linetype = \"dashed\", color = \"grey60\") + scale_color_manual(values = method_colors) + labs(title = \"ROC curves: KO vs. WT (Ctnnb1 KO dataset)\", x = \"False positive rate\", y = \"True positive rate\") + theme_classic() p_roc"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"overview","dir":"Articles","previous_headings":"","what":"Overview","title":"Toy Set","text":"vignette demonstrates use PathwayEmbed package compute visualize pathway activation using single-cell transcriptomic data. use example dataset synthetic_test_object_100 included package.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"load-packages-and-data","dir":"Articles","previous_headings":"","what":"Load Packages and Data","title":"Toy Set","text":"","code":"library(PathwayEmbed) library(Seurat) library(dplyr) library(tidyr) library(ggplot2) library(ggridges) library(patchwork) library(pheatmap) library(progeny) library(pROC) data(\"synthetic_test_object_100\") data(\"synthetic_test_metadata\")"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"helper-annotation-label-builder","dir":"Articles","previous_headings":"","what":"Helper: Annotation Label Builder","title":"Toy Set","text":"","code":"make_label <- function(stats, group1, group2) { d <- round(stats$cohens_d[1], 3) p <- formatC(stats$p_value[1], format = \"e\", digits = 2) on1 <- stats$percentage_on[stats$group == group1] off1 <- stats$percentage_off[stats$group == group1] on2 <- stats$percentage_on[stats$group == group2] off2 <- stats$percentage_off[stats$group == group2] paste0( group1, \": ON=\", on1, \"%, OFF=\", off1, \"%\\n\", group2, \": ON=\", on2, \"%, OFF=\", off2, \"%\\n\", \"Cohen's d = \", d, \"\\n\", \"p = \", p ) }"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"load-pathway-databases","dir":"Articles","previous_headings":"","what":"Load Pathway Databases","title":"Toy Set","text":"","code":"ListPathway() #> # A tibble: 17 × 8 #> Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes #> #> 1 HIF1A Hypoxia_6hr GSE227502 Hypoxia … Primary hu… Human 21 #> 2 HIF1A Hypoxia_24hr GSE227502 Hypoxia … Primary hu… Human 18 #> 3 HIF1A Hypoxia_5Day GSE227502 Hypoxia … Primary hu… Human 10 #> 4 HIPPO HIPPO_heat GSE133251 Heat str… B16-OVA me… Mouse 40 #> 5 NOTCH NOTCH_JAG1 GSE223734 rJAG1 li… Mouse embr… Mouse 5 #> 6 NOTCH NOTCH_CB103_IN… GSE221577 CB-103 N… RPMI-8402 … Human 46 #> 7 NOTCH NOTCH_LY_INHIB… GSE221577 LY411575… RPMI-8402 … Human 46 #> 8 NOTCH NOTCH_JAG1_2H GSE235637 JAG1 sti… SVG-A cells Human 11 #> 9 NOTCH NOTCH_JAG1_4H GSE235637 JAG1 sti… SVG-A cells Human 11 #> 10 NOTCH NOTCH_JAG1_24H GSE235637 JAG1 sti… SVG-A cells Human 11 #> 11 TGFB TGFB_Human_D1 GSE110021 TGF-β1 t… WI-38 fibr… Human 35 #> 12 TGFB TGFB_Human_D20 GSE110021 TGF-β1 t… WI-38 fibr… Human 39 #> 13 TGFB TGFB_Mouse GSE246932 TGF-β1 t… T Cells Mouse 9 #> 14 WNT WNT3A_12H_ACTI… GSE103175 WNT3A tr… Human Embr… Human 90 #> 15 WNT WNT3A_24H_ACTI… GSE103175 WNT3A tr… Human Embr… Human 88 #> 16 WNT WNT3A_48H_ACTI… GSE103175 WNT3A tr… Human Embr… Human 90 #> 17 WNT WNT3A_SLOPE_AC… GSE103175 WNT3A tr… Human Embr… Human 90 #> # ℹ 1 more variable: Notes ListPathway(\"Pathway\") #> [1] \"HIF1A\" \"HIPPO\" \"NOTCH\" \"TGFB\" \"WNT\" ListPathway(\"WNT\") #> # A tibble: 4 × 8 #> Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes #> #> 1 WNT WNT3A_12H… GSE103175 WNT3A tr… Human Embr… Human 90 NA #> 2 WNT WNT3A_24H… GSE103175 WNT3A tr… Human Embr… Human 88 NA #> 3 WNT WNT3A_48H… GSE103175 WNT3A tr… Human Embr… Human 90 NA #> 4 WNT WNT3A_SLO… GSE103175 WNT3A tr… Human Embr… Human 90 NA Wnt_12h <- LoadPathway(\"WNT3A_12H_ACTIVATION\", \"mouse\") Wnt_24h <- LoadPathway(\"WNT3A_24H_ACTIVATION\", \"mouse\") Wnt_48h <- LoadPathway(\"WNT3A_48H_ACTIVATION\", \"mouse\") Wnt_slope <- LoadPathway(\"WNT3A_SLOPE_ACTIVATION\", \"mouse\")"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"preprocessing-and-pathway-reference-states","dir":"Articles","previous_headings":"","what":"Preprocessing and Pathway Reference States","title":"Toy Set","text":"","code":"matrix_12h <- DataPreProcess(synthetic_test_object_100, Wnt_12h, Seurat.object = TRUE) matrix_24h <- DataPreProcess(synthetic_test_object_100, Wnt_24h, Seurat.object = TRUE) matrix_48h <- DataPreProcess(synthetic_test_object_100, Wnt_48h, Seurat.object = TRUE) matrix_slope <- DataPreProcess(synthetic_test_object_100, Wnt_slope, Seurat.object = TRUE) pathwaystat_12h <- PathwayMaxMin(matrix_12h, Wnt_12h) pathwaystat_24h <- PathwayMaxMin(matrix_24h, Wnt_24h) pathwaystat_48h <- PathwayMaxMin(matrix_48h, Wnt_48h) pathwaystat_slope <- PathwayMaxMin(matrix_slope, Wnt_slope)"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"compute-pathway-scores","dir":"Articles","previous_headings":"","what":"Compute Pathway Scores","title":"Toy Set","text":"","code":"score_12h <- ComputeCellData(matrix_12h, pathwaystat_12h) score_24h <- ComputeCellData(matrix_24h, pathwaystat_24h) score_48h <- ComputeCellData(matrix_48h, pathwaystat_48h) score_slope <- ComputeCellData(matrix_slope, pathwaystat_slope)"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"prepare-plot-data-and-calculate-group-statistics","dir":"Articles","previous_headings":"","what":"Prepare Plot Data and Calculate Group Statistics","title":"Toy Set","text":"","code":"plot_data_12h <- PreparePlotData(synthetic_test_metadata, score_12h, group = \"genotype\") plot_data_24h <- PreparePlotData(synthetic_test_metadata, score_24h, group = \"genotype\") plot_data_48h <- PreparePlotData(synthetic_test_metadata, score_48h, group = \"genotype\") plot_data_slope <- PreparePlotData(synthetic_test_metadata, score_slope, group = \"genotype\") pct_12h <- CalculatePercentage(to.plot = plot_data_12h, group_var = \"genotype\") pct_24h <- CalculatePercentage(to.plot = plot_data_24h, group_var = \"genotype\") pct_48h <- CalculatePercentage(to.plot = plot_data_48h, group_var = \"genotype\") pct_slope <- CalculatePercentage(to.plot = plot_data_slope, group_var = \"genotype\") pct_12h; pct_24h; pct_48h; pct_slope #> # A tibble: 2 × 5 #> group percentage_on percentage_off cohens_d p_value #> #> 1 WT 41.5 58.5 -0.431 5.08e-25 #> 2 Mutant 61.7 38.3 -0.431 5.08e-25 #> # A tibble: 2 × 5 #> group percentage_on percentage_off cohens_d p_value #> #> 1 WT 40.3 59.7 -0.379 2.48e-20 #> 2 Mutant 58.7 41.3 -0.379 2.48e-20 #> # A tibble: 2 × 5 #> group percentage_on percentage_off cohens_d p_value #> #> 1 WT 46 54 -0.187 0.00000376 #> 2 Mutant 53.9 46.1 -0.187 0.00000376 #> # A tibble: 2 × 5 #> group percentage_on percentage_off cohens_d p_value #> #> 1 WT 45.2 54.8 -0.149 0.000119 #> 2 Mutant 52 48 -0.149 0.000119"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"visualization-1-density-plots","dir":"Articles","previous_headings":"","what":"Visualization 1 — Density Plots","title":"Toy Set","text":"","code":"p1 <- PlotPathway(plot_data_12h, \"12hr Wnt\", \"genotype\", c(\"#ae282c\", \"#2066a8\")) + annotate(\"text\", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, label = make_label(pct_12h, \"WT\", \"Mutant\"), size = 3.5, color = \"black\") p2 <- PlotPathway(plot_data_24h, \"24hr Wnt\", \"genotype\", c(\"#ae282c\", \"#2066a8\")) + annotate(\"text\", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, label = make_label(pct_24h, \"WT\", \"Mutant\"), size = 3.5, color = \"black\") p3 <- PlotPathway(plot_data_48h, \"48hr Wnt\", \"genotype\", c(\"#ae282c\", \"#2066a8\")) + annotate(\"text\", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, label = make_label(pct_48h, \"WT\", \"Mutant\"), size = 3.5, color = \"black\") p4 <- PlotPathway(plot_data_slope, \"Wnt (slope)\", \"genotype\", c(\"#ae282c\", \"#2066a8\")) + annotate(\"text\", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, label = make_label(pct_slope, \"WT\", \"Mutant\"), size = 3.5, color = \"black\") p1; p2; p3; p4"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"visualization-2-violin-jitter-plot","dir":"Articles","previous_headings":"","what":"Visualization 2 — Violin + Jitter Plot","title":"Toy Set","text":"","code":"p5 <- ggplot(plot_data_12h, aes(x = genotype, y = scale, fill = genotype, color = genotype)) + geom_violin(alpha = 0.5, trim = FALSE) + geom_jitter(width = 0.15, size = 0.6, alpha = 0.3) + geom_hline(yintercept = 0, linetype = \"dotted\", color = \"black\", linewidth = 0.5) + scale_fill_manual(values = c(\"#ae282c\", \"#2066a8\")) + scale_color_manual(values = c(\"#ae282c\", \"#2066a8\")) + annotate(\"text\", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, label = make_label(pct_12h, \"WT\", \"Mutant\"), size = 3.5, color = \"black\") + labs(title = \"12hr WNT Pathway Activation\", x = NULL, y = \"Relative Transduction State (z-score)\") + theme_classic() + theme(legend.position = \"none\") p5"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"visualization-3-waterfall-plot","dir":"Articles","previous_headings":"","what":"Visualization 3 — Waterfall Plot","title":"Toy Set","text":"","code":"waterfall_data <- plot_data_12h %>% group_by(genotype) %>% arrange(scale, .by_group = TRUE) %>% mutate(rank = row_number(), state = ifelse(scale >= 0, \"ON\", \"OFF\")) %>% ungroup() annotation_df <- pct_12h %>% mutate( label = paste0(\"Cohen's d = \", round(cohens_d, 3), \"\\n\", \"p = \", formatC(p_value, format = \"e\", digits = 2), \"\\n\", \"ON = \", percentage_on, \"%\\n\", \"OFF = \", percentage_off, \"%\"), genotype = group ) p6 <- ggplot(waterfall_data, aes(x = rank, y = scale, fill = state)) + geom_bar(stat = \"identity\", width = 1) + facet_wrap(~ genotype, scales = \"free_x\") + scale_fill_manual(values = c(\"ON\" = \"#ae282c\", \"OFF\" = \"#2066a8\")) + geom_hline(yintercept = 0, color = \"black\", linewidth = 0.4) + geom_text(data = annotation_df, aes(x = Inf, y = Inf, label = label), hjust = 1.1, vjust = 1.5, size = 3, color = \"black\", inherit.aes = FALSE) + labs(title = \"Waterfall Plot of Cell Activation\", x = \"Cells (ranked by activation)\", y = \"Relative Transduction State (z-score)\", fill = \"State\") + theme_classic() + theme(axis.text.x = element_blank(), axis.ticks.x = element_blank(), strip.background = element_rect(fill = \"grey90\", color = NA)) p6"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"customize-pathway-input","dir":"Articles","previous_headings":"","what":"Customize Pathway Input","title":"Toy Set","text":"","code":"# Customize the wnt pathway using coefficients defined by us Wnt.molecules <- c('Lgr5','Rnf43','Lrp5', 'Lrp6','Fzd6','Ctnnb1', 'Gsk3b','Ccnd1','Axin2', 'Myc','Lef1','Tcf7', 'Tcf7l1','Tcf7l2','Tle1', 'Apc','Csnk1a1','Dvl1') Wnt.cof <- c(1,1,-1,-1,-1,-1, 1,1,1, 1,1,1, 1,1,1, -1,-1,-1) Wnt_df <- data.frame( Gene_Symbol = Wnt.molecules, Coefficient = Wnt.cof) print(Wnt_df) #> Gene_Symbol Coefficient #> 1 Lgr5 1 #> 2 Rnf43 1 #> 3 Lrp5 -1 #> 4 Lrp6 -1 #> 5 Fzd6 -1 #> 6 Ctnnb1 -1 #> 7 Gsk3b 1 #> 8 Ccnd1 1 #> 9 Axin2 1 #> 10 Myc 1 #> 11 Lef1 1 #> 12 Tcf7 1 #> 13 Tcf7l1 1 #> 14 Tcf7l2 1 #> 15 Tle1 1 #> 16 Apc -1 #> 17 Csnk1a1 -1 #> 18 Dvl1 -1 # Calculate score using customized pathway data matrix_df <- DataPreProcess(synthetic_test_object_100, Wnt_df, Seurat.object = TRUE) pathwaystat_df <- PathwayMaxMin(matrix_df, Wnt_df) score_df <- ComputeCellData(matrix_df, pathwaystat_df) plot_data_df <- PreparePlotData(synthetic_test_metadata, score_df, group = \"genotype\") pct_df <- CalculatePercentage(to.plot = plot_data_df, group_var = \"genotype\") PlotPathway(plot_data_df, \"Customized Wnt\", \"genotype\", c(\"#ae282c\", \"#2066a8\")) + annotate(\"text\", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, label = make_label(pct_df, \"WT\", \"Mutant\"), size = 3.5, color = \"black\")"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"null-distribution-random-gene-sets","dir":"Articles","previous_headings":"","what":"Null Distribution — Random Gene Sets","title":"Toy Set","text":"","code":"set.seed(123) real_n_genes <- nrow(matrix_12h) real_cohens_d <- pct_12h$cohens_d[1] n_reps <- 20 # Sparse size grid covering the relevant range, always including real n size_grid <- sort(unique(c( seq(5, 50, by = 5), seq(60, 200, by = 20), real_n_genes ))) all_genes_pool <- rownames( GetAssayData(synthetic_test_object_100, assay = \"RNA\", layer = \"data\") ) size_grid <- size_grid[size_grid <= length(all_genes_pool)] cohens_d_random <- data.frame() for (i in size_grid) { for (rep in seq_len(n_reps)) { sampled_genes <- sample(all_genes_pool, i) fake_pathway <- data.frame( Gene_Symbol = sampled_genes, Coefficient = sample(c(-1L, 1L), i, replace = TRUE) ) expr_matrix <- DataPreProcess(synthetic_test_object_100, fake_pathway, Seurat.object = TRUE) pathwaystat_rand <- PathwayMaxMin(expr_matrix, fake_pathway) score_rand <- ComputeCellData(expr_matrix, pathwaystat_rand) plot_data_rand <- PreparePlotData(synthetic_test_metadata, score_rand, group = \"genotype\") outcome_rand <- CalculatePercentage(plot_data_rand, group_var = \"genotype\") cohens_d_random <- rbind(cohens_d_random, data.frame( n_genes = i, rep = rep, cohens_d = outcome_rand$cohens_d[1] )) } } cohens_d_summary_rand <- cohens_d_random %>% group_by(n_genes) %>% summarise(mean_d = mean(cohens_d, na.rm = TRUE), sd_d = sd(cohens_d, na.rm = TRUE), .groups = \"drop\") null_at_real_n <- cohens_d_random %>% filter(n_genes == real_n_genes) emp_p <- mean(abs(null_at_real_n$cohens_d) >= abs(real_cohens_d), na.rm = TRUE) cat(\"Real pathway Cohen's d: \", round(real_cohens_d, 3), \"\\n\") #> Real pathway Cohen's d: -0.431 cat(\"Null mean at same n genes: \", round(mean(null_at_real_n$cohens_d, na.rm = TRUE), 3), \"\\n\") #> Null mean at same n genes: -0.082 cat(\"Null SD at same n genes: \", round(sd(null_at_real_n$cohens_d, na.rm = TRUE), 3), \"\\n\") #> Null SD at same n genes: 0.328 cat(\"Empirical p-value: \", round(emp_p, 3), \"\\n\") #> Empirical p-value: 0.25 p7 <- ggplot() + geom_hline(yintercept = 0, linetype = \"solid\", color = \"#888780\", linewidth = 0.4) + geom_hline(yintercept = 0.8, linetype = \"dashed\", color = \"#E24B4A\", linewidth = 0.5) + geom_hline(yintercept = -0.8, linetype = \"dashed\", color = \"#E24B4A\", linewidth = 0.5) + geom_hline(yintercept = 0.5, linetype = \"dashed\", color = \"#EF9F27\", linewidth = 0.5) + geom_hline(yintercept = -0.5, linetype = \"dashed\", color = \"#EF9F27\", linewidth = 0.5) + geom_point(data = cohens_d_random, aes(x = n_genes, y = cohens_d), color = \"#534AB7\", alpha = 0.25, size = 1.2) + geom_ribbon(data = cohens_d_summary_rand, aes(x = n_genes, ymin = mean_d - sd_d, ymax = mean_d + sd_d), fill = \"#534AB7\", alpha = 0.15) + geom_line(data = cohens_d_summary_rand, aes(x = n_genes, y = mean_d), color = \"#534AB7\", linewidth = 0.9) + geom_point(aes(x = real_n_genes, y = real_cohens_d), color = \"#E24B4A\", size = 3, shape = 18) + geom_vline(xintercept = real_n_genes, color = \"#E24B4A\", linetype = \"dashed\", linewidth = 0.5) + annotate(\"text\", x = real_n_genes, y = Inf, label = paste0(\"Real pathway\\nn = \", real_n_genes, \"\\nd = \", round(real_cohens_d, 3), \"\\nemp. p = \", round(emp_p, 3)), hjust = -0.1, vjust = 1.5, size = 3, color = \"#E24B4A\") + annotate(\"text\", x = max(cohens_d_summary_rand$n_genes), y = 0.82, label = \"large (+0.8)\", hjust = 1, size = 3, color = \"#E24B4A\") + annotate(\"text\", x = max(cohens_d_summary_rand$n_genes), y = -0.82, label = \"large (-0.8)\", hjust = 1, size = 3, color = \"#E24B4A\") + annotate(\"text\", x = max(cohens_d_summary_rand$n_genes), y = 0.52, label = \"medium (+0.5)\", hjust = 1, size = 3, color = \"#EF9F27\") + annotate(\"text\", x = max(cohens_d_summary_rand$n_genes), y = -0.52, label = \"medium (-0.5)\", hjust = 1, size = 3, color = \"#EF9F27\") + labs(title = \"Null Distribution — Cohen's d by Gene Set Size\", x = \"Number of genes\", y = \"Cohen's d\") + theme_minimal() p7"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"null-distribution-within-pathway-gene-pool","dir":"Articles","previous_headings":"","what":"Null Distribution — Within Pathway Gene Pool","title":"Toy Set","text":"","code":"set.seed(123) all_genes <- rownames(matrix_12h) n_genes <- length(all_genes) n_reps <- 10 cohens_d_pathway <- data.frame() for (i in 2:n_genes) { for (rep in seq_len(n_reps)) { sampled_genes <- sample(all_genes, i) expr_matrix <- matrix_12h[sampled_genes, , drop = FALSE] pathwaystat_rand <- PathwayMaxMin(expr_matrix, Wnt_12h) score_rand <- ComputeCellData(expr_matrix, pathwaystat_rand) plot_data_rand <- PreparePlotData(synthetic_test_metadata, score_rand, group = \"genotype\") outcome_rand <- CalculatePercentage(to.plot = plot_data_rand, group_var = \"genotype\") cohens_d_pathway <- rbind(cohens_d_pathway, data.frame( n_genes = i, rep = rep, cohens_d = outcome_rand$cohens_d[1] )) } } cohens_d_summary_pw <- cohens_d_pathway %>% group_by(n_genes) %>% summarise(mean_d = mean(cohens_d, na.rm = TRUE), sd_d = sd(cohens_d, na.rm = TRUE), .groups = \"drop\") null_at_real_n_pw <- cohens_d_pathway %>% filter(n_genes == real_n_genes) emp_p_pw <- mean(abs(null_at_real_n_pw$cohens_d) >= abs(real_cohens_d), na.rm = TRUE) cat(\"Real pathway Cohen's d: \", round(real_cohens_d, 3), \"\\n\") #> Real pathway Cohen's d: -0.431 cat(\"Null mean at same n genes: \", round(mean(null_at_real_n_pw$cohens_d, na.rm = TRUE), 3), \"\\n\") #> Null mean at same n genes: -0.431 cat(\"Null SD at same n genes: \", round(sd(null_at_real_n_pw$cohens_d, na.rm = TRUE), 3), \"\\n\") #> Null SD at same n genes: 0 cat(\"Empirical p-value: \", round(emp_p_pw, 3), \"\\n\") #> Empirical p-value: 0.6 p_null <- ggplot() + geom_hline(yintercept = 0, linetype = \"solid\", color = \"#888780\", linewidth = 0.4) + geom_hline(yintercept = 0.8, linetype = \"dashed\", color = \"#E24B4A\", linewidth = 0.5) + geom_hline(yintercept = -0.8, linetype = \"dashed\", color = \"#E24B4A\", linewidth = 0.5) + geom_hline(yintercept = 0.5, linetype = \"dashed\", color = \"#EF9F27\", linewidth = 0.5) + geom_hline(yintercept = -0.5, linetype = \"dashed\", color = \"#EF9F27\", linewidth = 0.5) + geom_point(data = cohens_d_pathway, aes(x = n_genes, y = cohens_d), color = \"#534AB7\", alpha = 0.25, size = 1.2) + geom_ribbon(data = cohens_d_summary_pw, aes(x = n_genes, ymin = mean_d - sd_d, ymax = mean_d + sd_d), fill = \"#534AB7\", alpha = 0.15) + geom_line(data = cohens_d_summary_pw, aes(x = n_genes, y = mean_d), color = \"#534AB7\", linewidth = 0.9) + geom_point(aes(x = real_n_genes, y = real_cohens_d), color = \"#E24B4A\", size = 3, shape = 18) + geom_vline(xintercept = real_n_genes, color = \"#E24B4A\", linetype = \"dashed\", linewidth = 0.5) + annotate(\"text\", x = real_n_genes, y = Inf, label = paste0(\"Real pathway\\nn = \", real_n_genes, \"\\nd = \", round(real_cohens_d, 3)), hjust = -0.1, vjust = 1.5, size = 3, color = \"#E24B4A\") + labs(title = \"Null Distribution — Cohen's d by Gene Set Size (10 reps each)\", x = \"Number of genes\", y = \"Cohen's d\") + theme_minimal() p_null"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"sensitivity-analysis-1-effect-of-input-matrix-type","dir":"Articles","previous_headings":"","what":"Sensitivity Analysis 1 — Effect of Input Matrix Type","title":"Toy Set","text":"","code":"data(\"synthetic_test_matrix_100\") matrix_raw <- synthetic_test_matrix_100 lib_size <- colSums(synthetic_test_matrix_100) matrix_lognorm <- log1p(sweep(synthetic_test_matrix_100, 2, lib_size, \"/\") * 1e4) matrix_norm <- sweep(synthetic_test_matrix_100, 2, lib_size, \"/\") * 1e4 gene_var <- apply(matrix_lognorm, 1, var) hvg_genes <- names(sort(gene_var, decreasing = TRUE))[ 1:ceiling(nrow(matrix_lognorm) * 0.5)] matrix_hvg <- matrix_lognorm[hvg_genes, ] run_pipeline <- function(expr_mat, pathwaydata, metadata, group, scale.data = TRUE) { mat <- DataPreProcess(expr_mat, pathwaydata, scale.data = scale.data) pstat <- PathwayMaxMin(mat, pathwaydata) score <- ComputeCellData(mat, pstat) plotdata <- PreparePlotData(metadata, score, group = group) outcome <- CalculatePercentage(plotdata, group_var = group) list(score = score, plotdata = plotdata, outcome = outcome) } result_raw <- run_pipeline(matrix_raw, Wnt_12h, synthetic_test_metadata, \"genotype\") result_lognorm <- run_pipeline(matrix_lognorm, Wnt_12h, synthetic_test_metadata, \"genotype\") result_norm <- run_pipeline(matrix_norm, Wnt_12h, synthetic_test_metadata, \"genotype\") result_hvg <- run_pipeline(matrix_hvg, Wnt_12h, synthetic_test_metadata, \"genotype\") result_raw_noscale <- run_pipeline(matrix_raw, Wnt_12h, synthetic_test_metadata, \"genotype\", scale.data = FALSE) result_lognorm_noscale <- run_pipeline(matrix_lognorm, Wnt_12h, synthetic_test_metadata, \"genotype\", scale.data = FALSE) result_norm_noscale <- run_pipeline(matrix_norm, Wnt_12h, synthetic_test_metadata, \"genotype\", scale.data = FALSE) result_hvg_noscale <- run_pipeline(matrix_hvg, Wnt_12h, synthetic_test_metadata, \"genotype\", scale.data = FALSE) input_labels <- c(\"Raw\", \"Log-norm\", \"Norm\", \"HVG\", \"Raw (noscale)\", \"Log-norm (noscale)\", \"Norm (noscale)\", \"HVG (noscale)\") results_list <- list(result_raw, result_lognorm, result_norm, result_hvg, result_raw_noscale, result_lognorm_noscale, result_norm_noscale, result_hvg_noscale) cohens_d_input <- data.frame( input_type = input_labels, cohens_d = sapply(results_list, function(r) r$outcome$cohens_d[1]), p_value = sapply(results_list, function(r) r$outcome$p_value[1]) ) print(cohens_d_input) #> input_type cohens_d p_value #> 1 Raw -0.80105995 1.120664e-65 #> 2 Log-norm -0.43058889 5.083976e-25 #> 3 Norm -0.38149058 2.648944e-18 #> 4 HVG -0.02940827 5.222419e-01 #> 5 Raw (noscale) -0.99496812 9.932645e-94 #> 6 Log-norm (noscale) -0.22648846 5.743074e-07 #> 7 Norm (noscale) -0.42743835 2.281451e-22 #> 8 HVG (noscale) -0.02943217 5.259599e-01 score_df_sens <- as.data.frame( setNames(lapply(results_list, function(r) as.numeric(r$score)), input_labels), row.names = names(results_list[[1]]$score) ) score_cor <- cor(score_df_sens, method = \"spearman\", use = \"pairwise.complete.obs\") p12 <- pheatmap(score_cor, color = colorRampPalette(c(\"#185FA5\", \"white\", \"#993C1D\"))(100), breaks = seq(-1, 1, length.out = 101), display_numbers = TRUE, number_format = \"%.2f\", fontsize_number = 9, main = \"Score Correlation Across Input Matrix Types — Spearman\") named_results <- list(Raw = result_raw, `Log-norm` = result_lognorm, Norm = result_norm, HVG = result_hvg) density_plots <- lapply( names(named_results), function(nm) PlotPathway(named_results[[nm]]$plotdata, paste(\"Wnt 12h —\", nm), \"genotype\", c(\"#ae282c\", \"#2066a8\")) ) p13 <- wrap_plots(density_plots, ncol = 2) + plot_annotation(title = \"Pathway Activation by Input Matrix Type\") p12; p13"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"correlation-with-technical-confounders","dir":"Articles","previous_headings":"","what":"Correlation with Technical Confounders","title":"Toy Set","text":"","code":"normalized_mat <- GetAssayData(synthetic_test_object_100, assay = \"RNA\", layer = \"data\") common_genes <- intersect(rownames(normalized_mat), Wnt_12h$Gene_Symbol) gene_matrix <- as.matrix(normalized_mat[common_genes, ]) mean_expr <- colMeans(gene_matrix, na.rm = TRUE) zscore_mean_per_cell <- colMeans(t(scale(t(gene_matrix))), na.rm = TRUE) seurat_meta <- synthetic_test_object_100@meta.data make_scatter <- function(df, x_col, x_label) { r <- cor(df$embed_score, df[[x_col]], method = \"spearman\", use = \"complete.obs\") ggplot(df, aes(x = .data[[x_col]], y = embed_score)) + geom_point(alpha = 0.4, size = 1.2, color = \"#534AB7\") + geom_smooth(method = \"lm\", color = \"#E24B4A\", linewidth = 0.8, se = TRUE) + labs(title = sprintf(\"%s (rho = %.3f)\", x_label, r), x = x_label, y = \"PathwayEmbed score\") + theme_minimal() } confounder_df_norm <- data.frame( cell = names(score_12h), embed_score = as.numeric(score_12h), mean_expr = mean_expr[names(score_12h)], zscore_expr = zscore_mean_per_cell[names(score_12h)], nCount_RNA = seurat_meta[names(score_12h), \"nCount_RNA\"], nFeature_RNA = seurat_meta[names(score_12h), \"nFeature_RNA\"] ) for (cov in c(\"mean_expr\", \"zscore_expr\", \"nCount_RNA\", \"nFeature_RNA\")) { r <- cor(confounder_df_norm$embed_score, confounder_df_norm[[cov]], method = \"spearman\", use = \"complete.obs\") cat(sprintf(\"Spearman vs %-20s : %.3f\\n\", cov, r)) } #> Spearman vs mean_expr : 0.163 #> Spearman vs zscore_expr : 0.280 #> Spearman vs nCount_RNA : 0.089 #> Spearman vs nFeature_RNA : -0.145 p_nor <- (make_scatter(confounder_df_norm, \"mean_expr\", \"Mean expression\") + make_scatter(confounder_df_norm, \"zscore_expr\", \"Z-score mean\")) / (make_scatter(confounder_df_norm, \"nCount_RNA\", \"nCount_RNA\") + make_scatter(confounder_df_norm, \"nFeature_RNA\", \"nFeature_RNA\")) p_nor"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"correlation-with-technical-confounders-raw-counts","dir":"Articles","previous_headings":"","what":"Correlation with Technical Confounders — Raw Counts","title":"Toy Set","text":"","code":"common_genes_raw <- intersect(rownames(matrix_raw), Wnt_12h$Gene_Symbol) gene_matrix_raw <- as.matrix(matrix_raw[common_genes_raw, ]) mean_expr_raw <- colMeans(gene_matrix_raw, na.rm = TRUE) zscore_mean_per_cell_raw <- colMeans(t(scale(t(gene_matrix_raw))), na.rm = TRUE) score_raw_12h <- result_raw$score confounder_df_raw <- data.frame( cell = names(score_raw_12h), embed_score = as.numeric(score_raw_12h), mean_expr = mean_expr_raw[names(score_raw_12h)], zscore_expr = zscore_mean_per_cell_raw[names(score_raw_12h)], nCount_RNA = seurat_meta[names(score_raw_12h), \"nCount_RNA\"], nFeature_RNA = seurat_meta[names(score_raw_12h), \"nFeature_RNA\"] ) for (cov in c(\"mean_expr\", \"zscore_expr\", \"nCount_RNA\", \"nFeature_RNA\")) { r <- cor(confounder_df_raw$embed_score, confounder_df_raw[[cov]], method = \"spearman\", use = \"complete.obs\") cat(sprintf(\"Spearman vs %-20s : %.3f\\n\", cov, r)) } #> Spearman vs mean_expr : 0.411 #> Spearman vs zscore_expr : 0.406 #> Spearman vs nCount_RNA : 0.335 #> Spearman vs nFeature_RNA : -0.024 p_raw <- (make_scatter(confounder_df_raw, \"mean_expr\", \"Mean expression\") + make_scatter(confounder_df_raw, \"zscore_expr\", \"Z-score mean\")) / (make_scatter(confounder_df_raw, \"nCount_RNA\", \"nCount_RNA\") + make_scatter(confounder_df_raw, \"nFeature_RNA\", \"nFeature_RNA\")) p_raw"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"benchmark-against-progeny-and-addmodulescore","dir":"Articles","previous_headings":"","what":"Benchmark Against PROGENy and AddModuleScore","title":"Toy Set","text":"","code":"normalized_mat_dense <- as.matrix(normalized_mat) progeny_scores <- progeny( normalized_mat_dense, scale = TRUE, organism = \"Mouse\", top = 100, perm = 1 ) progeny_wnt <- setNames(as.numeric(progeny_scores[, \"WNT\"]), rownames(progeny_scores)) wnt_features <- rownames(matrix_24h) synthetic_test_object_100 <- AddModuleScore( object = synthetic_test_object_100, features = list(wnt_features), name = \"WNT_ModuleScore\", ctrl = 5, nbin = 10 ) module_score <- setNames( synthetic_test_object_100@meta.data$WNT_ModuleScore1, rownames(synthetic_test_object_100@meta.data) ) cells <- names(score_24h) benchmark_df <- data.frame( PathwayEmbed = as.numeric(score_24h), PROGENy = as.numeric(progeny_wnt[cells]), AddModuleScore = as.numeric(module_score[cells]), mean_expr = as.numeric(mean_expr[cells]), zscore_expr = as.numeric(zscore_mean_per_cell[cells]), row.names = cells ) benchmark_cor <- cor(benchmark_df, method = \"spearman\", use = \"pairwise.complete.obs\") print(round(benchmark_cor, 3)) #> PathwayEmbed PROGENy AddModuleScore mean_expr zscore_expr #> PathwayEmbed 1.000 0.042 -0.049 -0.078 -0.082 #> PROGENy 0.042 1.000 0.028 0.046 0.137 #> AddModuleScore -0.049 0.028 1.000 0.625 0.440 #> mean_expr -0.078 0.046 0.625 1.000 0.807 #> zscore_expr -0.082 0.137 0.440 0.807 1.000 p9 <- pheatmap( benchmark_cor, color = colorRampPalette(c(\"#185FA5\", \"white\", \"#993C1D\"))(100), breaks = seq(-1, 1, length.out = 101), display_numbers = TRUE, number_format = \"%.2f\", fontsize_number = 9, main = \"Method Benchmark — Spearman Correlation\" ) p9 genotype_label <- ifelse( synthetic_test_metadata[cells, \"genotype\"] == \"Mutant\", 1L, 0L ) compute_auroc <- function(scores, labels) { r <- roc(labels, scores, quiet = TRUE) auc_val <- as.numeric(auc(r)) if (auc_val < 0.5) auc_val <- 1 - auc_val auc_val } auroc_results <- data.frame( Method = colnames(benchmark_df), AUROC = sapply(benchmark_df, compute_auroc, labels = genotype_label) ) auroc_results <- auroc_results[order(-auroc_results$AUROC), ] print(auroc_results) #> Method AUROC #> zscore_expr zscore_expr 0.755310 #> PROGENy PROGENy 0.656320 #> mean_expr mean_expr 0.626260 #> PathwayEmbed PathwayEmbed 0.619310 #> AddModuleScore AddModuleScore 0.526651 compute_cohens_d_method <- function(scores, metadata, group_col) { scores <- setNames(as.numeric(scores), names(scores)) pd <- PreparePlotData(metadata, scores, group = group_col) pct <- CalculatePercentage(pd, group_var = group_col) abs(pct$cohens_d[1]) } cohens_d_results <- data.frame( Method = colnames(benchmark_df), Cohens_d = sapply( colnames(benchmark_df), function(m) compute_cohens_d_method( setNames(benchmark_df[[m]], rownames(benchmark_df)), synthetic_test_metadata, \"genotype\" ) ) ) cohens_d_results <- cohens_d_results[order(-cohens_d_results$Cohens_d), ] print(cohens_d_results) #> Method Cohens_d #> zscore_expr zscore_expr 0.94892009 #> mean_expr mean_expr 0.44722384 #> PathwayEmbed PathwayEmbed 0.37911019 #> AddModuleScore AddModuleScore 0.07942301 #> PROGENy PROGENy 0.07087977 method_colors <- c( \"PathwayEmbed\" = \"#534AB7\", \"PROGENy\" = \"#E24B4A\", \"AddModuleScore\" = \"#EF9F27\", \"mean_expr\" = \"#888780\", \"zscore_expr\" = \"#B4B2A9\" ) p10 <- ggplot(auroc_results, aes(x = reorder(Method, AUROC), y = AUROC, fill = Method)) + geom_bar(stat = \"identity\", width = 0.6) + geom_hline(yintercept = 0.5, linetype = \"dashed\", color = \"black\") + coord_flip() + scale_fill_manual(values = method_colors) + labs(title = \"AUROC: Mutant vs WT separation by scoring method\", x = NULL, y = \"AUROC\") + ylim(0, 1) + theme_classic() + theme(legend.position = \"none\", axis.text.y = element_text(size = 12), axis.text.x = element_text(size = 11), axis.title.x = element_text(size = 12), plot.title = element_text(size = 13, face = \"bold\")) p11 <- ggplot(cohens_d_results, aes(x = reorder(Method, Cohens_d), y = Cohens_d, fill = Method)) + geom_bar(stat = \"identity\", width = 0.6) + geom_hline(yintercept = 0.5, linetype = \"dashed\", color = \"black\") + coord_flip() + scale_fill_manual(values = method_colors) + labs(title = \"Cohen's d: Mutant vs WT separation by scoring method\", x = NULL, y = \"Cohen's d\") + ylim(0, 1) + theme_classic() + theme(legend.position = \"none\", axis.text.y = element_text(size = 12), axis.text.x = element_text(size = 11), axis.title.x = element_text(size = 12), plot.title = element_text(size = 13, face = \"bold\")) p10; p11"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html","id":"sensitivity-analysis-2-effect-of-distance-method","dir":"Articles","previous_headings":"","what":"Sensitivity Analysis 2 — Effect of Distance Method","title":"Toy Set","text":"","code":"score_manhattan <- ComputeCellData(matrix_24h, pathwaystat_24h, distance.method = \"manhattan\") score_euclidean <- ComputeCellData(matrix_24h, pathwaystat_24h, distance.method = \"euclidean\") cor_dist <- cor(score_manhattan, score_euclidean, method = \"spearman\") cat(\"Spearman correlation (manhattan vs euclidean):\", round(cor_dist, 3), \"\\n\") #> Spearman correlation (manhattan vs euclidean): 0.942 plotdata_manhattan <- PreparePlotData(synthetic_test_metadata, score_manhattan, group = \"genotype\") plotdata_euclidean <- PreparePlotData(synthetic_test_metadata, score_euclidean, group = \"genotype\") pct_manhattan <- CalculatePercentage(plotdata_manhattan, group_var = \"genotype\") pct_euclidean <- CalculatePercentage(plotdata_euclidean, group_var = \"genotype\") distance_comparison <- data.frame( method = c(\"Manhattan\", \"Euclidean\"), cohens_d = c(pct_manhattan$cohens_d[1], pct_euclidean$cohens_d[1]), p_value = c(pct_manhattan$p_value[1], pct_euclidean$p_value[1]), pct_on_wt = c(pct_manhattan$percentage_on[pct_manhattan$group == \"WT\"], pct_euclidean$percentage_on[pct_euclidean$group == \"WT\"]), pct_on_mut = c(pct_manhattan$percentage_on[pct_manhattan$group == \"Mutant\"], pct_euclidean$percentage_on[pct_euclidean$group == \"Mutant\"]) ) print(distance_comparison) #> method cohens_d p_value pct_on_wt pct_on_mut #> 1 Manhattan -0.3791102 2.479654e-20 40.3 58.7 #> 2 Euclidean -0.4669349 3.968028e-32 38.5 63.9 dist_df <- data.frame(manhattan = as.numeric(score_manhattan), euclidean = as.numeric(score_euclidean), row.names = names(score_manhattan)) p_scatter <- ggplot(dist_df, aes(x = manhattan, y = euclidean)) + geom_point(alpha = 0.4, size = 1.2, color = \"#534AB7\") + geom_smooth(method = \"lm\", color = \"#E24B4A\", linewidth = 0.8, se = TRUE) + labs(title = sprintf(\"Manhattan vs Euclidean (rho = %.3f)\", cor_dist), x = \"Manhattan score\", y = \"Euclidean score\") + theme_minimal() p_man_plot <- PlotPathway(plotdata_manhattan, \"Wnt 24h — Manhattan\", \"genotype\", c(\"#ae282c\", \"#2066a8\")) p_euc_plot <- PlotPathway(plotdata_euclidean, \"Wnt 24h — Euclidean\", \"genotype\", c(\"#ae282c\", \"#2066a8\")) p_scatter / (p_man_plot + p_euc_plot) + plot_annotation(title = \"Sensitivity to Distance Method\")"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/spatial_pathway_updated.html","id":"overview","dir":"Articles","previous_headings":"","what":"Overview","title":"Spatial Pathway Visualization","text":"vignette demonstrates application PathwayEmbed mouse embryo spatial data (E9.5 - E12.5). curated pathway database, examined compared Wnt, Notch, TGFb, Hippo, HIF-1a signaling transduction states across spatial temporal development. Reference initial data: Chen et al. Spatiotemporal transcriptomic atlas mouse organogenesis using DNA nanoball-patterned arrays, Cell, Volume 185, Issue 10, 2022, Pages 1777-1792.e21.","code":"knitr::opts_chunk$set( echo = TRUE, collapse = TRUE, warning = FALSE, message = FALSE, comment = \"#>\", fig.width = 8, fig.height = 6 ) # load library library(PathwayEmbed) library(Seurat) ## Warning: package 'Seurat' was built under R version 4.4.3 ## Loading required package: SeuratObject ## Warning: package 'SeuratObject' was built under R version 4.4.3 ## Loading required package: sp ## Warning: package 'sp' was built under R version 4.4.3 ## ## Attaching package: 'SeuratObject' ## The following objects are masked from 'package:base': ## ## intersect, t library(ggplot2) ## Warning: package 'ggplot2' was built under R version 4.4.3 library(viridis) ## Loading required package: viridisLite ## Warning: package 'viridisLite' was built under R version 4.4.3 library(cowplot) library(dplyr) ## Warning: package 'dplyr' was built under R version 4.4.3 ## ## Attaching package: 'dplyr' ## The following objects are masked from 'package:stats': ## ## filter, lag ## The following objects are masked from 'package:base': ## ## intersect, setdiff, setequal, union library(Hmisc) ## Warning: package 'Hmisc' was built under R version 4.4.3 ## ## Attaching package: 'Hmisc' ## The following objects are masked from 'package:dplyr': ## ## src, summarize ## The following object is masked from 'package:Seurat': ## ## Key ## The following object is masked from 'package:SeuratObject': ## ## Key ## The following objects are masked from 'package:base': ## ## format.pval, units library(corrplot) ## corrplot 0.95 loaded library(tibble) ## Warning: package 'tibble' was built under R version 4.4.3 library(tidyr) ## Warning: package 'tidyr' was built under R version 4.4.3"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/spatial_pathway_updated.html","id":"spatial-data-load-and-process","dir":"Articles","previous_headings":"","what":"Spatial data load and process","title":"Spatial Pathway Visualization","text":"files can downloaded figshare via link: Huang, Yaqing (2025). dat3..niches.norm.Robj. figshare. Dataset. https://doi.org/10.6084/m9.figshare.29649995.v1 Huang, Yaqing (2025). dat4..niches.norm.Robj. figshare. Dataset. https://doi.org/10.6084/m9.figshare.29649989.v1 Huang, Yaqing (2025). dat1..niches.norm.Robj. figshare. Dataset. https://doi.org/10.6084/m9.figshare.29649992.v1 Huang, Yaqing (2025). dat2..niches.norm.Robj. figshare. Dataset. https://doi.org/10.6084/m9.figshare.29649986.v1","code":"# load data load(\"dat1.with.niches.norm.Robj\") load(\"dat2.with.niches.norm.Robj\") load(\"dat3.with.niches.norm.Robj\") load(\"dat4.with.niches.norm.Robj\") # Merge together merged_spatial <- merge( dat1, y = c(dat2, dat3, dat4)) # Set Default Assay to be \"RNA\" DefaultAssay(merged_spatial) <- \"RNA\" # Get genes x cell matrix merged_spatial_matrix <- as.matrix(GetAssayData(merged_spatial, assay = \"RNA\", layer = \"data\")) # Get metadata matrix merged_spatial_metadata <- merged_spatial@meta.data"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/spatial_pathway_updated.html","id":"get-pathway-data-for-each-pathway-first","dir":"Articles","previous_headings":"","what":"Get Pathway Data for Each Pathway first","title":"Spatial Pathway Visualization","text":"","code":"# All Pathways ListPathway(\"Pathway\") #> [1] \"HIF1A\" \"HIPPO\" \"NOTCH\" \"TGFB\" \"WNT\" ListPathway(\"HIF1A\") # Pick Hypoxia_24hr #> # A tibble: 3 × 8 #> Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes #> #> 1 HIF1A Hypoxia_6… GSE227502 Hypoxia … Primary hu… Human 21 NA #> 2 HIF1A Hypoxia_2… GSE227502 Hypoxia … Primary hu… Human 18 NA #> 3 HIF1A Hypoxia_5… GSE227502 Hypoxia … Primary hu… Human 10 NA ListPathway(\"HIPPO\") # Only one: HIPPO_heat #> # A tibble: 1 × 8 #> Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes #> #> 1 HIPPO HIPPO_heat GSE133251 Heat str… B16-OVA me… Mouse 40 NA ListPathway(\"NOTCH\") # Use NOTCH_JAG1_24H -> validated in another datasets #> # A tibble: 6 × 8 #> Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes #> #> 1 NOTCH NOTCH_JAG1 GSE223734 rJAG1 li… Mouse embr… Mouse 5 NA #> 2 NOTCH NOTCH_CB1… GSE221577 CB-103 N… RPMI-8402 … Human 46 NA #> 3 NOTCH NOTCH_LY_… GSE221577 LY411575… RPMI-8402 … Human 46 NA #> 4 NOTCH NOTCH_JAG… GSE235637 JAG1 sti… SVG-A cells Human 11 NA #> 5 NOTCH NOTCH_JAG… GSE235637 JAG1 sti… SVG-A cells Human 11 NA #> 6 NOTCH NOTCH_JAG… GSE235637 JAG1 sti… SVG-A cells Human 11 NA ListPathway(\"TGFB\") # Use TGFB_Mouse since this is the only Ms dataset #> # A tibble: 3 × 8 #> Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes #> #> 1 TGFB TGFB_Huma… GSE110021 TGF-β1 t… WI-38 fibr… Human 35 NA #> 2 TGFB TGFB_Huma… GSE110021 TGF-β1 t… WI-38 fibr… Human 39 NA #> 3 TGFB TGFB_Mouse GSE246932 TGF-β1 t… T Cells Mouse 9 NA ListPathway(\"WNT\") # Use WNT3A_SLOPE_ACTIVATION #> # A tibble: 4 × 8 #> Pathway Sheet.Name GEO.Accession Condition Cell.Source Species No..Genes Notes #> #> 1 WNT WNT3A_12H… GSE103175 WNT3A tr… Human Embr… Human 90 NA #> 2 WNT WNT3A_24H… GSE103175 WNT3A tr… Human Embr… Human 88 NA #> 3 WNT WNT3A_48H… GSE103175 WNT3A tr… Human Embr… Human 90 NA #> 4 WNT WNT3A_SLO… GSE103175 WNT3A tr… Human Embr… Human 90 NA # Load Each Pathwaydatabase HIf1a_pathwaydata <- LoadPathway(\"Hypoxia_24hr\", \"mouse\") Hippo_pathwaydata <- LoadPathway(\"HIPPO_heat\", \"mouse\") Notch_pathwaydata <- LoadPathway(\"NOTCH_JAG1_24H\", \"mouse\") TGFb_pathwaydata <- LoadPathway(\"TGFB_Mouse\", \"mouse\") Wnt_pathwaydata <- LoadPathway(\"WNT3A_SLOPE_ACTIVATION\", \"mouse\")"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/spatial_pathway_updated.html","id":"calculation","dir":"Articles","previous_headings":"","what":"Calculation","title":"Spatial Pathway Visualization","text":"Using Matrix extracted avoid large size data object, compute score Wnt, Notch, Hippo, Tgfb, HIF-1a pathways merged subject using ‘ComputeCellData’ PathwayEmbed","code":"# DataPreProcess matrix_HIf1a <- DataPreProcess(merged_spatial_matrix, HIf1a_pathwaydata, Seurat.object = FALSE) matrix_Hippo <- DataPreProcess(merged_spatial_matrix, Hippo_pathwaydata, Seurat.object = FALSE) matrix_Notch <- DataPreProcess(merged_spatial_matrix, Notch_pathwaydata, Seurat.object = FALSE) matrix_TGFb <- DataPreProcess(merged_spatial_matrix, TGFb_pathwaydata, Seurat.object = FALSE) matrix_Wnt <- DataPreProcess(merged_spatial_matrix, Wnt_pathwaydata, Seurat.object = FALSE) # PathwayMaxMin pathwaystat_HIf1a <- PathwayMaxMin(matrix_HIf1a, HIf1a_pathwaydata) pathwaystat_Hippo <- PathwayMaxMin(matrix_Hippo, Hippo_pathwaydata) pathwaystat_Notch <- PathwayMaxMin(matrix_Notch, Notch_pathwaydata) pathwaystat_TGFb <- PathwayMaxMin(matrix_TGFb, TGFb_pathwaydata) pathwaystat_Wnt <- PathwayMaxMin(matrix_Wnt, Wnt_pathwaydata) # Computing Score HIf1a_score <- ComputeCellData(matrix_HIf1a, pathwaystat_HIf1a) Hippo_score <- ComputeCellData(matrix_Hippo, pathwaystat_Hippo) Notch_score <- ComputeCellData(matrix_Notch, pathwaystat_Notch) TGFb_score <- ComputeCellData(matrix_TGFb, pathwaystat_TGFb) Wnt_score <- ComputeCellData(matrix_Wnt, pathwaystat_Wnt)"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/spatial_pathway_updated.html","id":"prepare-plot-data","dir":"Articles","previous_headings":"","what":"Prepare plot data","title":"Spatial Pathway Visualization","text":"Map Timepoints back data","code":"# Compute the score for each pathway Wnt_to.plot <- PreparePlotData(merged_spatial_metadata, Wnt_score, \"timepoint\", Seurat.object = FALSE) Notch_to.plot <- PreparePlotData(merged_spatial_metadata, Notch_score, \"timepoint\", Seurat.object = FALSE) Hippo_to.plot <- PreparePlotData(merged_spatial_metadata, Hippo_score, \"timepoint\", Seurat.object = FALSE) Tgfb_to.plot <- PreparePlotData(merged_spatial_metadata, TGFb_score, \"timepoint\", Seurat.object = FALSE) HIF1a_to.plot <- PreparePlotData(merged_spatial_metadata, HIf1a_score,\"timepoint\", Seurat.object = FALSE) # Combine to list pathway_timepoint <- list( Wnt = Wnt_to.plot, Notch = Notch_to.plot, Hippo = Hippo_to.plot, Tgfb = Tgfb_to.plot, HIF1a = HIF1a_to.plot )"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/spatial_pathway_updated.html","id":"preparation-for-groups","dir":"Articles","previous_headings":"","what":"Preparation for groups","title":"Spatial Pathway Visualization","text":"","code":"#> /private/var/folders/dy/dxff9z6j5cdd5sqsvz2l5ngc0000gn/T/RtmpAOrgi8/temp_libpath3ff17d773dd5/PathwayEmbed/extdata/pathway_list_timepoint.rds #> /private/var/folders/dy/dxff9z6j5cdd5sqsvz2l5ngc0000gn/T/RtmpAOrgi8/temp_libpath3ff17d773dd5 /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/library # Color set-up magma_colors <- c(\"#000004FF\", \"#721F81FF\", \"#F1605DFF\", \"#5A90E6\") # Desired timepoint order ordered_timepoints <- c(\"E9.5\", \"E10.5\", \"E11.5\", \"E12.5\") # Reorder timepoint levels for (name in names(pathway_timepoint)) { pathway_timepoint[[name]]$timepoint <- factor(pathway_timepoint[[name]]$timepoint, levels = ordered_timepoints) }"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/spatial_pathway_updated.html","id":"plot-across-different-timepoints","dir":"Articles","previous_headings":"","what":"Plot across different timepoints","title":"Spatial Pathway Visualization","text":"","code":"# Calculation stats <- list() # Loop through each pathway and generate/save the plot for (i in seq_along(pathway_timepoint)) { stats[[i]] <- CalculatePercentage(pathway_timepoint[[i]], \"timepoint\") df_stats <- stats[[i]] df_stats <- stats[[i]] %>% dplyr::distinct(group, .keep_all = TRUE) %>% dplyr::rename(timepoint = group) p <- PlotPathway( pathway_timepoint[[i]], names(pathway_timepoint)[i], \"timepoint\", magma_colors ) + facet_wrap(~factor(timepoint, levels = ordered_timepoints), ncol = 1) + geom_text( data = df_stats %>% mutate(timepoint = factor(timepoint, levels = ordered_timepoints)), aes( x = Inf, y = Inf, label = sprintf( \"ON: %.1f%%\\nOFF: %.1f%%\\np = %.2g\", percentage_on, percentage_off, kruskal_p ) ), hjust = 1.1, vjust = 1.1, size = 3, inherit.aes = FALSE ) print(p) # ggsave( # filename = paste0(names(pathway_timepoint)[i], \"_timepoint_plot.png\"), # plot = p, # width = 6, # height = 8, # dpi = 300 # ) }"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/spatial_pathway_updated.html","id":"merge-score-with-original-metadata","dir":"Articles","previous_headings":"","what":"Merge score with original metadata","title":"Spatial Pathway Visualization","text":"","code":"# Step 1: Create named score vectors for each pathway score_list <- lapply(pathway_list, function(df) { s <- df$scale names(s) <- rownames(df) return(s) }) # Step 2: Add each pathway score to dat1–dat4 for (i in 1:4) { dat <- get(paste0(\"dat\", i)) # get dat1, dat2, ... for (pathway_name in names(score_list)) { score_vec <- score_list[[pathway_name]] dat[[paste0(pathway_name, \"_score\")]] <- score_vec[colnames(dat)] } assign(paste0(\"dat\", i), dat) # assign back to dat1, dat2, etc. } # List of Seurat objects dat_list <- list(dat1, dat2, dat3, dat4) names(dat_list) <- paste0(\"dat\", 1:4) # List of pathways pathways <- names(pathway_list) # e.g., \"Wnt\", \"Notch\", etc."},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/spatial_pathway_updated.html","id":"extract-the-coordinates","dir":"Articles","previous_headings":"","what":"Extract the coordinates","title":"Spatial Pathway Visualization","text":"","code":"# Function to extract extract_pathway_df <- function(seu, pathway, sample_name = \"sample\") { coords <- as.data.frame(Embeddings(seu[[\"spatial\"]])) colnames(coords) <- c(\"x\", \"y\") coords$score <- seu[[paste0(pathway, \"_score\")]][rownames(coords), 1] coords$sample <- sample_name return(coords) } # Set list to save the coordinates combined_df_lists <- list() # For loop for all pathways for (pathway in pathways) { pathway_df_list <- mapply( FUN = extract_pathway_df, seu = dat_list, sample_name = names(dat_list), MoreArgs = list(pathway = pathway), SIMPLIFY = FALSE ) combined_df <- do.call(rbind, pathway_df_list) combined_df_lists[[pathway]] <- combined_df }"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/spatial_pathway_updated.html","id":"plot-the-spatial-data","dir":"Articles","previous_headings":"","what":"Plot the spatial data","title":"Spatial Pathway Visualization","text":"## Spatial Correlation Analysis using Moran’s ","code":"# Compute global symmetric limits (recommended) all_values <- unlist(lapply(combined_df_lists, function(df) df$scale)) q <- quantile(all_values, c(0.02, 0.98), na.rm = TRUE) max_abs <- max(abs(q)) global_limits <- c(-max_abs, max_abs) for (pathway in names(combined_df_lists)) { combined_df <- combined_df_lists[[pathway]] # randomize the plot combined_df <- combined_df[sample(nrow(combined_df)), ] p <- ggplot(combined_df, aes(x = x, y = y, color = scale)) + geom_point(size = 0.01) + scale_color_viridis_c( option = \"magma\", limits = global_limits, # symmetric across all pathways oob = scales::squish, name = paste0(pathway, \"_score\") ) + scale_y_reverse() + coord_fixed() + theme_void() + theme( legend.position = \"right\", plot.title = element_text(hjust = 0.5, face = \"bold\") ) + ggtitle(pathway) print(p) } library(spdep) # Global Moran's I compute_morans_I <- function(df, k = 6) { coords <- as.matrix(df[, c(\"x\", \"y\")]) # k-nearest neighbors graph knn <- knearneigh(coords, k = k) nb <- knn2nb(knn) lw <- nb2listw(nb, style = \"W\") # Moran’s I test moran.test(df$scale, lw) } moran_results <- lapply(names(combined_df_lists), function(pw) { df <- combined_df_lists[[pw]] res <- compute_morans_I(df) data.frame( pathway = pw, morans_I = res$estimate[[\"Moran I statistic\"]], p_value = res$p.value ) }) moran_results <- do.call(rbind, moran_results) print(moran_results) #> pathway morans_I p_value #> 1 Wnt 0.08640729 0 #> 2 Notch 0.21093640 0 #> 3 Hippo 0.09334557 0 #> 4 Tgfb 0.12592755 0 #> 5 HIF1a 0.25478622 0 # compute neighbor Moran's I for pathways with high spatial autocorrelation compute_local_moran <- function(df, lw, pathway_name) { local <- localmoran(df$scale, lw) transform( df, local_I = local[, 1], z_score = local[, 4], p_value = local[, 5], pathway = pathway_name ) } # Apply to selected pathways selected_pathways <- c(\"Notch\", \"HIF1a\") df_plot <- do.call(rbind, lapply(selected_pathways, function(pw) { compute_local_moran(combined_df_lists_updated[[pw]], lw, pw) })) library(ggplot2) library(viridis) # 🔀 Randomize plotting order df_plot <- df_plot[sample(nrow(df_plot)), ] df_plot$cluster <- \"Not significant\" df_plot$cluster[df_plot$p_value < 0.05 & df_plot$local_I > 0] <- \"High-High\" df_plot$cluster[df_plot$p_value < 0.05 & df_plot$local_I < 0] <- \"Low-Low\" df_plot$cluster <- factor(df_plot$cluster, levels = c(\"High-High\", \"Low-Low\", \"Not significant\")) df_plot <- df_plot[sample(nrow(df_plot)), ] p_cluster <- ggplot(df_plot, aes(x = x, y = y, color = cluster)) + geom_point(size = 0.001) + scale_color_manual(values = c( \"High-High\" = \"#d73027\", # red = hotspot \"Low-Low\" = \"#4575b4\", # blue = coldspot \"Not significant\" = \"grey80\" )) + scale_y_reverse() + coord_fixed() + facet_wrap(~ pathway) + theme_void() + labs(title = \"Local Moran’s I Clusters\", color = \"Cluster\") print(p_cluster)"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/spatial_pathway_updated.html","id":"benchmark-towards-progeny","dir":"Articles","previous_headings":"","what":"Benchmark towards Progeny","title":"Spatial Pathway Visualization","text":"Benchmark + Technical Confounding Factors","code":"set.seed(123) # Load all required libraries library(progeny) library(ggplot2) library(dplyr) library(tidyr) library(patchwork) library(corrplot) library(Hmisc) library(Matrix) library(tibble) library(tidyr) # Explicitly import pipe in case dplyr loaded partially `%>%` <- dplyr::`%>%` # ----Progeny----- merged_spatial_matrix <- readRDS(\"merged_spatial_matrix.rds\") progeny_scores <- progeny( merged_spatial_matrix, scale = TRUE, organism = \"Mouse\", top = 100, perm = 1 ) # Extract pathways — check column names exist first print(colnames(progeny_scores)) #> [1] \"Androgen\" \"EGFR\" \"Estrogen\" \"Hypoxia\" \"JAK-STAT\" \"MAPK\" #> [7] \"NFkB\" \"p53\" \"PI3K\" \"TGFb\" \"TNFa\" \"Trail\" #> [13] \"VEGF\" \"WNT\" # Extract existed pathways progeny_wnt <- progeny_scores[, \"WNT\"] progeny_hypoxia <- progeny_scores[, \"Hypoxia\"] progeny_tgfb <- progeny_scores[, \"TGFb\"] # correlation with Progeny score cor_wnt <- cor(Wnt_score, progeny_wnt, use = \"complete.obs\", method = \"spearman\") cor_tgfb <- cor(TGFb_score, progeny_tgfb, use = \"complete.obs\", method = \"spearman\") cor_hif <- cor(HIf1a_score, progeny_hypoxia, use = \"complete.obs\", method = \"spearman\") cor_results <- data.frame( comparison = c(\"Wnt vs PROGENy WNT\", \"TGFb vs PROGENy TGFb\", \"HIf1a vs PROGENy Hypoxia\"), spearman_r = round(c(cor_wnt, cor_tgfb, cor_hif), 4), pathway_our = c(\"Wnt_score\", \"TGFb_score\", \"HIf1a_score\"), pathway_ref = c(\"WNT\", \"TGFb\", \"Hypoxia\") ) df_all <- rbind( data.frame(our = Wnt_score, progeny = progeny_wnt, pathway = \"WNT\"), data.frame(our = TGFb_score, progeny = progeny_tgfb, pathway = \"TGFb\"), data.frame(our = HIf1a_score, progeny = progeny_hypoxia, pathway = \"Hypoxia\") ) label_df <- cor_results %>% mutate(pathway = c(\"WNT\", \"TGFb\", \"Hypoxia\"), label = paste0(\"r = \", round(spearman_r, 3))) p_benchmark <- ggplot(df_all, aes(x = our, y = progeny)) + geom_point(alpha = 0.3, size = 0.8, color = \"grey30\") + geom_smooth(method = \"lm\", se = TRUE, color = \"#E24B4A\", fill = \"#FAD4D4\", linewidth = 0.8) + geom_text( data = label_df, aes(label = label), x = -Inf, y = Inf, hjust = -0.1, vjust = 1.2, size = 5, fontface = \"bold\", inherit.aes = FALSE ) + facet_wrap(~ pathway, ncol = 1, scales = \"free_x\") + labs( title = \"Benchmark: Our Scores vs PROGENy\", x = \"Our pathway score\", y = \"PROGENy score\" ) + theme_classic(base_size = 15) + theme( strip.background = element_rect(fill = \"grey95\", color = NA), strip.text = element_text(face = \"bold\"), plot.title = element_text(hjust = 0.5, face = \"bold\"), axis.title = element_text(face = \"bold\") ) p_benchmark"},{"path":[]},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/spatial_pathway_updated.html","id":"cross-pathway-spearman-correlation-matrix","dir":"Articles","previous_headings":"","what":"Cross-pathway Spearman Correlation matrix","title":"Spatial Pathway Visualization","text":"","code":"score_df <- data.frame( HIf1a = HIf1a_score, Hippo = Hippo_score, Notch = Notch_score, TGFb = TGFb_score, Wnt = Wnt_score ) cor_matrix <- cor(score_df, method = \"spearman\", use = \"complete.obs\") cor_test <- Hmisc::rcorr(as.matrix(score_df), type = \"spearman\") p_matrix <- cor_test$P diag(p_matrix) <- 0 # rcorr sets diagonal to NA; corrplot requires numeric diagonal print(round(cor_matrix, 3)) #> HIf1a Hippo Notch TGFb Wnt #> HIf1a 1.000 -0.088 0.118 0.078 0.033 #> Hippo -0.088 1.000 -0.041 -0.093 -0.036 #> Notch 0.118 -0.041 1.000 0.099 0.041 #> TGFb 0.078 -0.093 0.099 1.000 0.031 #> Wnt 0.033 -0.036 0.041 0.031 1.000 # Correlation heatmap corrplot::corrplot(cor_matrix, method = \"color\", type = \"upper\", addCoef.col = \"black\", number.cex = 0.8, tl.col = \"black\", tl.srt = 45, p.mat = p_matrix, sig.level = 0.05, insig = \"blank\", title = \"Pathway Spearman Correlations\", mar = c(0, 0, 2, 0))"},{"path":"https://raredonlab.github.io/PathwayEmbed/articles/spatial_pathway_updated.html","id":"technical-cofounders","dir":"Articles","previous_headings":"","what":"Technical Cofounders","title":"Spatial Pathway Visualization","text":"","code":"#---Basic QC metrics from the raw count matrix ---- # merged_spatial_matrix is genes x spots (dense or sparse both work here) nCount <- Matrix::colSums(merged_spatial_matrix) nFeature <- Matrix::colSums(merged_spatial_matrix > 0) # Mitochondrial genes — mouse mt genes start with \"mt-\" (lowercase) mt_genes <- grep(\"^mt-\", rownames(merged_spatial_matrix), value = TRUE, ignore.case = TRUE) if (length(mt_genes) == 0) { warning(\"No mitochondrial genes found. Check rowname format (expected 'mt-*').\") pct_mt <- rep(NA_real_, ncol(merged_spatial_matrix)) } else { mt_counts <- Matrix::colSums(merged_spatial_matrix[mt_genes, , drop = FALSE]) pct_mt <- 100 * mt_counts / nCount } #---Cell Cycle Scoring---- # Strategy: compute the mean z-scored expression of S-phase genes and G2M # genes per spot as module scores, then correlate with pathway scores. # This is equivalent to Seurat's AddModuleScore but works on a plain matrix. # Mouse cell cycle gene sets (Tirosh et al. 2015, mouse-converted) s_genes_mouse <- c( \"Mcm5\", \"Pcna\", \"Tyms\", \"Fen1\", \"Mcm7\", \"Mcm4\", \"Rrm1\", \"Ung\", \"Gins2\", \"Mcm6\", \"Cdca7\", \"Dtl\", \"Prim1\", \"Uhrf1\", \"Cenpu\", \"Hells\", \"Rfc2\", \"Rad51ap1\", \"Gmnn\", \"Wdc\", \"Slbp\", \"Ccne2\", \"Ubr7\", \"Pold3\", \"Msh2\", \"Atad2\", \"Rad51\", \"Rrm2\", \"Cdc45\", \"Cdc6\", \"Exo1\", \"Tipin\", \"Dscc1\", \"Blm\", \"Casp8ap2\", \"Usp1\", \"Clspn\", \"Pola1\", \"Chaf1b\", \"Brip1\", \"E2f8\" ) g2m_genes_mouse <- c( \"Hmgb2\", \"Cdk1\", \"Nusap1\", \"Ube2c\", \"Birc5\", \"Tpx2\", \"Top2a\", \"Ndc80\", \"Cks2\", \"Nuf2\", \"Cks1b\", \"Mki67\", \"Ckap2l\", \"Ckap2\", \"Aurkb\", \"Bub1\", \"Kif11\", \"Anp32e\", \"Tubb4b\", \"Gtse1\", \"Kif20b\", \"Hjurp\", \"Cdca3\", \"Hn1\", \"Cdc20\", \"Ttk\", \"Cdc25c\", \"Kif2c\", \"Rangap1\", \"Ncapd2\", \"Dlgap5\", \"Cdca2\", \"Cdca8\", \"Ect2\", \"Kif23\", \"Hmmr\", \"Aurka\", \"Psrc1\", \"Anln\", \"Lbr\", \"Ckap5\", \"Cenpe\", \"Ctcf\", \"Nek2\", \"G2e3\", \"Gas2l3\", \"Cbx5\", \"Cenpa\" ) # Helper: compute mean z-scored module score per spot for a gene set. # Works on a genes x spots matrix (dense or sparse). # Returns a named numeric vector of length = ncol(mat). compute_module_score <- function(mat, gene_set) { genes_present <- intersect(gene_set, rownames(mat)) if (length(genes_present) == 0) { warning(\"No genes from gene set found in matrix.\") return(rep(NA_real_, ncol(mat))) } if (length(genes_present) < length(gene_set)) { message(\" Using \", length(genes_present), \" / \", length(gene_set), \" genes from gene set.\") } sub_mat <- as.matrix(mat[genes_present, , drop = FALSE]) # Row-wise z-score (across spots), then average per spot sub_z <- t(scale(t(sub_mat))) sub_z[is.nan(sub_z)] <- 0 # genes with zero variance -> score 0 colMeans(sub_z, na.rm = TRUE) } s_score <- compute_module_score(merged_spatial_matrix, s_genes_mouse) g2m_score <- compute_module_score(merged_spatial_matrix, g2m_genes_mouse) cc_score <- s_score - g2m_score # signed cell-cycle activity index # ---- Stress / Immediate-Early Gene Score--- # Immediate-early response genes (Fos, Jun family, Hsps, Atf3, Ddit3) are # strongly induced by dissociation stress and ambient RNA contamination. # A high correlation between a pathway score and this module raises a red flag. stress_genes_mouse <- c( # IEG \"Fos\",\"Jun\",\"Junb\",\"Atf3\",\"Egr1\", # ER stress / UPR \"Ddit3\",\"Atf4\",\"Xbp1\",\"Hspa5\", # heat shock \"Hspa1a\",\"Hspa1b\",\"Hsp90aa1\", # oxidative \"Gadd45a\",\"Gadd45b\",\"Gadd45g\" ) stress_score <- compute_module_score(merged_spatial_matrix, stress_genes_mouse) # --Assemble confounder data frame--- spot_names <- names(Wnt_score) # canonical spot order from PathwayEmbed scores confounder_df <- data.frame( spot = spot_names, # PathwayEmbed scores Wnt = Wnt_score[spot_names], TGFb = TGFb_score[spot_names], HIf1a = HIf1a_score[spot_names], Hippo = Hippo_score[spot_names], Notch = Notch_score[spot_names], # QC metrics nCount = nCount[spot_names], nFeature = nFeature[spot_names], pct_mt = pct_mt[spot_names], # Module scores S_score = s_score[spot_names], G2M_score = g2m_score[spot_names], CC_score = cc_score[spot_names], Stress = stress_score[spot_names], row.names = spot_names, stringsAsFactors = FALSE) pathway_cols <- c(\"Wnt\", \"TGFb\", \"HIf1a\", \"Hippo\", \"Notch\") confounder_cols <- c(\"nCount\", \"nFeature\", \"pct_mt\", \"S_score\", \"G2M_score\", \"CC_score\", \"Stress\") # Build a long-form correlation table cor_rows <- lapply(pathway_cols, function(pw) { lapply(confounder_cols, function(cov) { complete_idx <- complete.cases(confounder_df[[pw]], confounder_df[[cov]]) r <- cor(confounder_df[[pw]][complete_idx], confounder_df[[cov]][complete_idx], method = \"spearman\") # Two-sided p-value via t-approximation (valid for large n) n <- sum(complete_idx) t_stat <- r * sqrt((n - 2) / (1 - r^2)) pv <- 2 * pt(-abs(t_stat), df = n - 2) data.frame(pathway = pw, covariate = cov, spearman_r = round(r, 4), p_value = pv, n_spots = n, stringsAsFactors = FALSE) }) }) cor_table <- do.call(rbind, do.call(c, cor_rows)) # FDR correction across all pathway-covariate pairs cor_table$p_adj_BH <- p.adjust(cor_table$p_value, method = \"BH\") cor_table$significant <- cor_table$p_adj_BH < 0.05 print(cor_table[, c(\"pathway\", \"covariate\", \"spearman_r\", \"p_adj_BH\", \"significant\")]) #> pathway covariate spearman_r p_adj_BH significant #> 1 Wnt nCount 0.0433 4.415180e-45 TRUE #> 2 Wnt nFeature 0.0426 1.536189e-43 TRUE #> 3 Wnt pct_mt 0.0125 5.228341e-05 TRUE #> 4 Wnt S_score 0.0735 1.130319e-126 TRUE #> 5 Wnt G2M_score 0.0871 6.075138e-177 TRUE #> 6 Wnt CC_score -0.0199 9.980877e-11 TRUE #> 7 Wnt Stress 0.0684 8.929403e-110 TRUE #> 8 TGFb nCount 0.2328 0.000000e+00 TRUE #> 9 TGFb nFeature 0.2108 0.000000e+00 TRUE #> 10 TGFb pct_mt -0.0755 1.735223e-133 TRUE #> 11 TGFb S_score 0.2074 0.000000e+00 TRUE #> 12 TGFb G2M_score 0.2050 0.000000e+00 TRUE #> 13 TGFb CC_score 0.0002 9.384768e-01 FALSE #> 14 TGFb Stress 0.0996 2.252103e-231 TRUE #> 15 HIf1a nCount 0.4212 0.000000e+00 TRUE #> 16 HIf1a nFeature 0.3167 0.000000e+00 TRUE #> 17 HIf1a pct_mt -0.3226 0.000000e+00 TRUE #> 18 HIf1a S_score 0.3803 0.000000e+00 TRUE #> 19 HIf1a G2M_score 0.3572 0.000000e+00 TRUE #> 20 HIf1a CC_score 0.0261 2.706127e-17 TRUE #> 21 HIf1a Stress 0.2466 0.000000e+00 TRUE #> 22 Hippo nCount -0.1506 0.000000e+00 TRUE #> 23 Hippo nFeature -0.1228 0.000000e+00 TRUE #> 24 Hippo pct_mt 0.1003 2.944881e-234 TRUE #> 25 Hippo S_score -0.1268 0.000000e+00 TRUE #> 26 Hippo G2M_score -0.1192 0.000000e+00 TRUE #> 27 Hippo CC_score 0.0047 1.274208e-01 FALSE #> 28 Hippo Stress -0.0960 8.909423e-215 TRUE #> 29 Notch nCount 0.3083 0.000000e+00 TRUE #> 30 Notch nFeature 0.2871 0.000000e+00 TRUE #> 31 Notch pct_mt -0.2177 0.000000e+00 TRUE #> 32 Notch S_score 0.2753 0.000000e+00 TRUE #> 33 Notch G2M_score 0.2975 0.000000e+00 TRUE #> 34 Notch CC_score -0.0247 9.902323e-16 TRUE #> 35 Notch Stress 0.1689 0.000000e+00 TRUE cor_wide <- cor_table %>% select(pathway, covariate, spearman_r) %>% tidyr::pivot_wider(names_from = covariate, values_from = spearman_r) %>% tibble::column_to_rownames(\"pathway\") %>% as.matrix() sig_wide <- cor_table %>% select(pathway, covariate, significant) %>% tidyr::pivot_wider(names_from = covariate, values_from = significant) %>% tibble::column_to_rownames(\"pathway\") %>% as.matrix() # Build asterisk annotation matrix: * = FDR < 0.05, blank otherwise annot_wide <- ifelse(sig_wide, \"*\", \"\") # Use corrplot for the heatmap (consistent with cross-pathway section) corrplot::corrplot( cor_wide, method = \"color\", is.corr = FALSE, # raw values, not a correlation matrix col = colorRampPalette(c(\"#2066a8\", \"white\", \"#ae282c\"))(200), cl.lim = c(-1, 1), addCoef.col = \"black\", number.cex = 0.7, tl.col = \"black\", tl.srt = 45, title = \"Pathway scores vs technical confounders (Spearman rho)\", mar = c(0, 0, 2, 0) )"},{"path":"https://raredonlab.github.io/PathwayEmbed/authors.html","id":null,"dir":"","previous_headings":"","what":"Authors","title":"Authors and Citation","text":"Yaqing Huang. Author, maintainer.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/authors.html","id":"citation","dir":"","previous_headings":"","what":"Citation","title":"Authors and Citation","text":"Huang Y (2026). PathwayEmbed: Tools Pathway-Level Embedding Visualization Single-Cell Data. R package version 0.0.0.9000, https://raredonlab.github.io/PathwayEmbed.","code":"@Manual{, title = {PathwayEmbed: Tools for Pathway-Level Embedding and Visualization in Single-Cell Data}, author = {Yaqing Huang}, year = {2026}, note = {R package version 0.0.0.9000}, url = {https://raredonlab.github.io/PathwayEmbed}, }"},{"path":[]},{"path":[]},{"path":"https://raredonlab.github.io/PathwayEmbed/index.html","id":"pathwayembed-1","dir":"","previous_headings":"","what":"PathwayEmbed","title":"PathwayEmbed","text":"PathwayEmbed R package quantifying visualizing intracellular signaling pathway activation transcriptomic data, integrating pathway topology gene expression data.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/index.html","id":"installation","dir":"","previous_headings":"","what":"Installation","title":"PathwayEmbed","text":"can install released version PathwayEmbed GitHub using:","code":"# Install remotes if you haven't already if (!requireNamespace(\"remotes\", quietly = TRUE)) { install.packages(\"remotes\") } remotes::install_github(\"RaredonLab/PathwayEmbed\")"},{"path":"https://raredonlab.github.io/PathwayEmbed/index.html","id":"usage","dir":"","previous_headings":"","what":"Usage","title":"PathwayEmbed","text":"","code":"library(PathwayEmbed) # Load example data included with the package data(\"synthetic_test_object_100\") data(\"synthetic_test_metadata\") # Check what pathways are availabel in the pre-constructed table ListPathway() # summary page ListPathway(\"Pathway\") # what pathways are available ListPathway(\"WNT\") # what coefficient tables are available # Load pre-constructed pathway coefficient tables Wnt_12h <- LoadPathway(\"WNT3A_12H_ACTIVATION\", \"mouse\") # Input data preprocess matrix_12h <- DataPreProcess(synthetic_test_object_100, Wnt_12h, Seurat.object = TRUE) # Determine the global reference (ON and OFF) pathwaystat_12h <- PathwayMaxMin(matrix_12h, Wnt_12h) # Compute pathway data score_12h <- ComputeCellData(matrix_12h, pathwaystat_12h) # Prepare data for plotting plot_data_12h <- PreparePlotData(synthetic_test_metadata, score_12h, group = \"genotype\") # Plot pathway activation PlotPathway(plot_data_12h, \"12hr Wnt\", \"genotype\", c(\"#ae282c\", \"#2066a8\")) # Calculate percentage and do comparison between two groups (optional) CalculatePercentage(to.plot = plot_data_12h, group_var = \"genotype\")"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/CalculatePercentage.html","id":null,"dir":"Reference","previous_headings":"","what":"CalculatePercentage — CalculatePercentage","title":"CalculatePercentage — CalculatePercentage","text":"Calculates percentage cells (scale > 0) (scale < 0) activation states within group defined group_var.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/CalculatePercentage.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"CalculatePercentage — CalculatePercentage","text":"","code":"CalculatePercentage(to.plot, group_var)"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/CalculatePercentage.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"CalculatePercentage — CalculatePercentage","text":".plot data frame PreparePlotData(), containing least scale column grouping column specified group_var. group_var character string specifying grouping column .plot (e.g. \"genotype\", \"treatment\").","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/CalculatePercentage.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"CalculatePercentage — CalculatePercentage","text":"data frame columns: group Group label. percentage_on Percentage cells scale > 0. percentage_off Percentage cells scale < 0. cohens_d (2-group ) Cohen's d effect size. Repeated group rows single pairwise estimate. p_value (2-group ) Wilcoxon rank-sum p-value. kruskal_p (3+ groups ) Kruskal-Wallis p-value. 3+ groups, Bonferroni-corrected pairwise Wilcoxon p-values attached via attr(result, \"pairwise_wilcox\").","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/CalculatePercentage.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"CalculatePercentage — CalculatePercentage","text":"exactly two groups provided, Cohen's d effect size Wilcoxon rank-sum p-value computed two groups. two groups provided, Kruskal-Wallis p-value computed across groups, pairwise Wilcoxon p-values (Bonferroni-corrected) attached attribute.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/CalculatePercentage.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"CalculatePercentage — CalculatePercentage","text":"","code":"if (FALSE) { # \\dontrun{ data(fake_to_plot) CalculatePercentage(fake_to_plot, \"genotype\") } # }"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/ComputeCellData.html","id":null,"dir":"Reference","previous_headings":"","what":"ComputeCellData — ComputeCellData","title":"ComputeCellData — ComputeCellData","text":"Computes per-cell pathway activation score measuring cell's distance pathway reference states PathwayMaxMin(). Scores normalized [0, 1]\\, 1 indicates proximity state 0 indicates proximity state.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/ComputeCellData.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"ComputeCellData — ComputeCellData","text":"","code":"ComputeCellData(expr_data, pathway.stat, distance.method = \"manhattan\")"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/ComputeCellData.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"ComputeCellData — ComputeCellData","text":"expr_data z-scored gene--cell numeric matrix, e.g. DataPreProcess(). pathway.stat data frame PathwayMaxMin() columns pathway.pathway.. Rownames must gene symbols. distance.method Character string specifying distance metric. One \"manhattan\" (default) \"euclidean\".","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/ComputeCellData.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"ComputeCellData — ComputeCellData","text":"named numeric vector length equal number cells, scores [0, 1]. score near 1 indicates cell close state; score near 0 indicates proximity state. Cells distances 0 return NaN warning.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/ComputeCellData.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"ComputeCellData — ComputeCellData","text":"","code":"if (FALSE) { # \\dontrun{ pathwaydata <- LoadPathway(\"Hypoxia_6hr\", \"human\") expr_filtered <- DataPreProcess(norm_matrix, pathwaydata) pathway_stat <- PathwayMaxMin(expr_filtered, pathwaydata) scores <- ComputeCellData(expr_filtered, pathway_stat) } # }"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/DataPreProcess.html","id":null,"dir":"Reference","previous_headings":"","what":"DataPreProcess — DataPreProcess","title":"DataPreProcess — DataPreProcess","text":"Preprocess expression data pathway analysis.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/DataPreProcess.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"DataPreProcess — DataPreProcess","text":"","code":"DataPreProcess( x, pathwaydata, Seurat.object = FALSE, assay = \"RNA\", slot = \"data\", scale.data = TRUE )"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/DataPreProcess.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"DataPreProcess — DataPreProcess","text":"x Seurat object gene--cell normalized expression matrix pathwaydata Pathway data output LoadPathway() Seurat.object Logical; whether x Seurat object assay Assay use x Seurat object (default = \"RNA\") slot Slot extract Seurat object (default = \"data\") scale.data Logical; whether apply row-wise z-score scaling (default = TRUE). FALSE, filtered expression matrix returned -without scaling.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/DataPreProcess.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"DataPreProcess — DataPreProcess","text":"gene--cell expression matrix pathway genes. scale.data = TRUE (default), values row-wise z-scored; scale.data = FALSE, raw input filtered values returned.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/DataPreProcess.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"DataPreProcess — DataPreProcess","text":"","code":"if (FALSE) { # \\dontrun{ DataPreProcess(seurat_obj, pathwaydata, Seurat.object = TRUE) DataPreProcess(norm_matrix, pathwaydata) DataPreProcess(norm_matrix, pathwaydata, scale.data = FALSE) } # }"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/ListPathway.html","id":null,"dir":"Reference","previous_headings":"","what":"ListPathway List available pathways or pathway metadata — ListPathway","title":"ListPathway List available pathways or pathway metadata — ListPathway","text":"Reads \"SUMMARY\" sheet Pathway_Database_Combined.xlsx. Behaviour depends query argument: NULL: returns full summary table tibble. \"Pathway\": returns sorted character vector unique pathway names. valid pathway name (e.g. \"WNT\", \"NOTCH\"): returns subset rows pathway tibble.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/ListPathway.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"ListPathway List available pathways or pathway metadata — ListPathway","text":"","code":"ListPathway(query = NULL, drop_empty = TRUE)"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/ListPathway.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"ListPathway List available pathways or pathway metadata — ListPathway","text":"query Optional character string. One NULL, \"Pathway\", valid pathway name. Default NULL. drop_empty Logical; TRUE, removes entries 0 genes. Default TRUE.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/ListPathway.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"ListPathway List available pathways or pathway metadata — ListPathway","text":"tibble (full table pathway subset) character vector (query = \"Pathway\").","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/ListPathway.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"ListPathway List available pathways or pathway metadata — ListPathway","text":"","code":"if (FALSE) { # \\dontrun{ ListPathway() ListPathway(\"Pathway\") ListPathway(\"WNT\") } # }"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/LoadPathway.html","id":null,"dir":"Reference","previous_headings":"","what":"LoadPathway — LoadPathway","title":"LoadPathway — LoadPathway","text":"Reads pathway gene data package's built-Excel database returns two-column data frame gene symbols coefficients requested species.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/LoadPathway.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"LoadPathway — LoadPathway","text":"","code":"LoadPathway(Sheet.name, species = \"human\")"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/LoadPathway.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"LoadPathway — LoadPathway","text":"Sheet.name character string specifying sheet name (e.g. \"Hypoxia_6hr\", \"HIPPO_heat\"). Use ListPathway() see available sheets. species character string specifying species: either \"human\" \"mouse\". Determines gene symbol column used. Default \"human\".","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/LoadPathway.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"LoadPathway — LoadPathway","text":"data frame two columns: Gene_Symbol Gene symbols requested species. Coefficient Numeric pathway coefficients. Rows NA gene symbols dropped.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/LoadPathway.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"LoadPathway — LoadPathway","text":"","code":"if (FALSE) { # \\dontrun{ LoadPathway(\"Hypoxia_6hr\", \"human\") LoadPathway(\"HIPPO_heat\", \"mouse\") } # }"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/PathwayMaxMin.html","id":null,"dir":"Reference","previous_headings":"","what":"PathwayMaxMin — PathwayMaxMin","title":"PathwayMaxMin — PathwayMaxMin","text":"function obtain hypothetical max min activation status selected pathway given scRNA seq data set","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/PathwayMaxMin.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"PathwayMaxMin — PathwayMaxMin","text":"","code":"PathwayMaxMin(expr_data, pathwaydata)"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/PathwayMaxMin.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"PathwayMaxMin — PathwayMaxMin","text":"expr_data Pre-processed gene--cell matrix (z-scored, pathway-filtered) pathwaydata Pathway data outcome LoadPathway()","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/PathwayMaxMin.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"PathwayMaxMin — PathwayMaxMin","text":"data.frame pathway.pathway.values per gene","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/PathwayMaxMin.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"PathwayMaxMin — PathwayMaxMin","text":"","code":"if (FALSE) { # \\dontrun{ pathwaydata <- LoadPathway(\"Hypoxia_6hr\", \"human\") matrix_filtered <- DataPreProcess(expr_data, pathwaydata) PathwayMaxMin(matrix_filtered, pathwaydata) } # }"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/PlotPathway.html","id":null,"dir":"Reference","previous_headings":"","what":"PlotPathway — PlotPathway","title":"PlotPathway — PlotPathway","text":"Plot activation status pathway across cell populations. Creates density plot pathway activation (z-scored) group.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/PlotPathway.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"PlotPathway — PlotPathway","text":"","code":"PlotPathway(to.plot, pathway, group, color)"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/PlotPathway.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"PlotPathway — PlotPathway","text":".plot dataframe returned PreparePlotData, containing least: scale Z-scored pathway activation values. group Grouping variable coloring (e.g., genotype). pathway Character string indicating pathway name (used plot title). group Column name .plot group color plot (e.g., \"genotype\"). color Character vector colors group (fill outline). Length must match number unique groups.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/PlotPathway.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"PlotPathway — PlotPathway","text":"ggplot2 object showing density distributions pathway activity per group.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/PlotPathway.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"PlotPathway — PlotPathway","text":"","code":"if (FALSE) { # \\dontrun{ data(fake_to_plot) PlotPathway(to.plot = fake_to_plot, pathway = \"Wnt\", group = \"genotype\", color = c(\"#ae282c\", \"#2066a8\")) } # }"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/PreparePlotData.html","id":null,"dir":"Reference","previous_headings":"","what":"PreparePlotData — PreparePlotData","title":"PreparePlotData — PreparePlotData","text":"Prepares tidy data frame pathway activity scores per cell downstream plotting PlotPathway() CalculatePercentage(). Accepts either plain metadata data frame Seurat object.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/PreparePlotData.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"PreparePlotData — PreparePlotData","text":"","code":"PreparePlotData(x, score, group, Seurat.object = FALSE)"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/PreparePlotData.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"PreparePlotData — PreparePlotData","text":"x metadata data frame (rows = cells, columns = metadata fields) Seurat object. Must contain column specified group. score named numeric vector per-cell scores ComputeCellData(). Names must cell IDs matching rownames x. group character string giving column name x metadata use grouping (e.g. \"genotype\", \"Age\"). Seurat.object Logical; set TRUE x Seurat object. Default FALSE.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/PreparePlotData.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"PreparePlotData — PreparePlotData","text":"data frame one row per cell three columns: normalized Normalized pathway activity score [0, 1]\\ ComputeCellData(). scale Z-scored pathway activity across cells. grouping variable, named group argument.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/PreparePlotData.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"PreparePlotData — PreparePlotData","text":"","code":"if (FALSE) { # \\dontrun{ # Using a plain metadata data frame plotdata <- PreparePlotData(metadata_df, scores, \"genotype\") # Using a Seurat object plotdata <- PreparePlotData(seurat_obj, scores, \"orig.ident\", Seurat.object = TRUE) } # }"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_matrix.html","id":null,"dir":"Reference","previous_headings":"","what":"Example Matrix for Testing — synthetic_test_matrix","title":"Example Matrix for Testing — synthetic_test_matrix","text":"numeric matrix containing single-cell gene expression data demonstration purposes PathwayEmbed package. Rows correspond genes columns correspond individual cells.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_matrix.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Example Matrix for Testing — synthetic_test_matrix","text":"","code":"synthetic_test_matrix"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_matrix.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Example Matrix for Testing — synthetic_test_matrix","text":"numeric matrix genes (rows) cells (columns). Rows 18 genes (e.g. \"Lgr5\", \"Rnf43\", \"Lrp5\", \"Fzd6\" ...) Columns 2000 cells (named \"Cell1\", \"Cell2\", ...) Values 35830 nonzero entries, representing expression values (numeric)","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_matrix.html","id":"source","dir":"Reference","previous_headings":"","what":"Source","title":"Example Matrix for Testing — synthetic_test_matrix","text":"Simulated demonstration purposes.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_matrix.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Example Matrix for Testing — synthetic_test_matrix","text":"synthetic dataset created testing demonstration purposes. mimics structure gene--cell expression matrix used single-cell RNA sequencing analysis.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_matrix.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Example Matrix for Testing — synthetic_test_matrix","text":"","code":"data(synthetic_test_matrix)"},{"path":[]},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_matrix_100.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Expanded Example Matrix for Testing (100 genes) — synthetic_test_matrix_100","text":"numeric matrix 100 rows (genes) 2000 columns (cells): Rows 100 genes. Rows 1–18 original Wnt pathway genes original expression values unchanged. Rows 19–100 randomly expressed genes housekeeping, cell-cycle, TF, Notch, MAPK/ERK, TGF-β/BMP, adhesion panels. Columns 2000 cells named \"Cell1\" \"Cell2000\", matching synthetic_test_matrix. Values Non-negative integer expression counts. Rows 1–18 taken directly synthetic_test_matrix. Rows 19–100 simulated via zero-inflated negative-binomial distribution (mu = 2.5, size = 0.8, ~35 \\ Simulated demonstration purposes, expanded synthetic_test_object. synthetic_test_matrix_100 numeric matrix containing single-cell gene expression data demonstration testing PathwayEmbed package. expanded version contains 100 genes: original 18 Wnt-pathway genes synthetic_test_matrix (rows 1–18, values preserved exactly) plus 82 additional randomly expressed genes drawn housekeeping, cell-cycle, transcription-factor, Notch, MAPK/ERK, TGF-β/BMP, adhesion gene sets. first 18 rows byte--byte identical synthetic_test_matrix, existing code subsets Wnt gene panel return results . 82 extra genes carry planted biological signal; intended testing functions operate larger multi-pathway gene panels, dimensionality reduction, clustering, multi-pathway scoring. data(synthetic_test_matrix_100) dim(synthetic_test_matrix_100) # 100 x 2000 rownames(synthetic_test_matrix_100)[1:18] # original Wnt genes mean(synthetic_test_matrix_100 > 0) # ~0.35 non-zero density synthetic_test_matrix, synthetic_test_object_100 datasets","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_metadata.html","id":null,"dir":"Reference","previous_headings":"","what":"synthetic metadata for test cells — synthetic_test_metadata","title":"synthetic metadata for test cells — synthetic_test_metadata","text":"toy metadata table corresponding columns synthetic_test_matrix. row represents single cell associated metadata.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_metadata.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"synthetic metadata for test cells — synthetic_test_metadata","text":"","code":"synthetic_test_metadata"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_metadata.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"synthetic metadata for test cells — synthetic_test_metadata","text":"data frame 2000 rows 4 variables: orig.ident Character, project identifier nCount_RNA Integer, total RNA counts per cell nFeature_RNA Integer, number detected features (genes) per cell genotype Factor/character, cell genotype (e.g., \"WT\", \"Mutant\")","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_metadata.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"synthetic metadata for test cells — synthetic_test_metadata","text":"dataset provides toy cell-level metadata designed accompany synthetic_test_matrix. mimics structure single-cell experiment metadata used analysis frameworks Seurat.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_metadata.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"synthetic metadata for test cells — synthetic_test_metadata","text":"","code":"data(synthetic_test_metadata)"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_metadata_100.html","id":null,"dir":"Reference","previous_headings":"","what":"Expanded Synthetic Metadata for Test Cells (100-gene dataset) — synthetic_test_metadata_100","title":"Expanded Synthetic Metadata for Test Cells (100-gene dataset) — synthetic_test_metadata_100","text":"metadata table corresponding 2000 columns synthetic_test_matrix_100. Derived directly synthetic_test_object@meta.data nCount_RNA nFeature_RNA recalculated reflect expanded 100-gene matrix. genotype assignments (WT / Mutant) orig.ident unchanged original object.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_metadata_100.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Expanded Synthetic Metadata for Test Cells (100-gene dataset) — synthetic_test_metadata_100","text":"","code":"synthetic_test_metadata_100"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_metadata_100.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Expanded Synthetic Metadata for Test Cells (100-gene dataset) — synthetic_test_metadata_100","text":"data frame 2000 rows 4 variables: orig.ident Character. Project identifier (\"SyntheticProject\" cells). nCount_RNA Integer. Total UMI counts per cell computed synthetic_test_matrix_100 (column sums). nFeature_RNA Integer. Number detected genes per cell (number non-zero entries per column synthetic_test_matrix_100). genotype Factor levels c(\"WT\", \"Mutant\"). Cells 1–1000 \"WT\"; cells 1001–2000 \"Mutant\", matching original object.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_metadata_100.html","id":"source","dir":"Reference","previous_headings":"","what":"Source","title":"Expanded Synthetic Metadata for Test Cells (100-gene dataset) — synthetic_test_metadata_100","text":"Derived synthetic_test_object@meta.data.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_metadata_100.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Expanded Synthetic Metadata for Test Cells (100-gene dataset) — synthetic_test_metadata_100","text":"Row names match column names synthetic_test_matrix_100 (\"Cell1\" … \"Cell2000\"). nCount_RNA nFeature_RNA recalculated internally consistent 100-gene matrix rather original 18-gene matrix.","code":""},{"path":[]},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_metadata_100.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Expanded Synthetic Metadata for Test Cells (100-gene dataset) — synthetic_test_metadata_100","text":"","code":"data(synthetic_test_metadata_100) head(synthetic_test_metadata_100) #> orig.ident nCount_RNA nFeature_RNA genotype #> Cell1 SeuratProject 202 41 WT #> Cell2 SeuratProject 156 32 WT #> Cell3 SeuratProject 115 34 WT #> Cell4 SeuratProject 197 43 WT #> Cell5 SeuratProject 169 36 WT #> Cell6 SeuratProject 167 36 WT table(synthetic_test_metadata_100$genotype) # 1000 WT, 1000 Mutant #> #> Mutant WT #> 1000 1000"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object.html","id":null,"dir":"Reference","previous_headings":"","what":"Example Seurat Object for Testing — synthetic_test_object","title":"Example Seurat Object for Testing — synthetic_test_object","text":"simulated Seurat object synthetic gene expression data Wnt signaling pathway. Seurat object contains gene expression data simulated cells Wnt positive negative gene expression values.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Example Seurat Object for Testing — synthetic_test_object","text":"","code":"data(synthetic_test_object)"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Example Seurat Object for Testing — synthetic_test_object","text":"Seurat object. object contains: assays List assays used data storage. Includes RNA expression data. meta.data Metadata associated cells. Contains information groups (e.g., WT vs. Mutant). features Gene features (including Wnt pathway genes) used analysis. cells Cell names, labeled Cell1, Cell2, ..., CellN.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object.html","id":"source","dir":"Reference","previous_headings":"","what":"Source","title":"Example Seurat Object for Testing — synthetic_test_object","text":"Simulated demonstration purposes.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object_100.html","id":null,"dir":"Reference","previous_headings":"","what":"Expanded Example Seurat Object for Testing (100 genes) — synthetic_test_object_100","title":"Expanded Example Seurat Object for Testing (100 genes) — synthetic_test_object_100","text":"simulated Seurat object built synthetic_test_matrix_100 synthetic_test_metadata. 100-gene counterpart synthetic_test_object structurally identical except larger gene panel. original 18 Wnt genes expression values fully preserved.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object_100.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Expanded Example Seurat Object for Testing (100 genes) — synthetic_test_object_100","text":"","code":"synthetic_test_object_100"},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object_100.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Expanded Example Seurat Object for Testing (100 genes) — synthetic_test_object_100","text":"Seurat object containing: assays single RNA assay storing 100 × 2000 count matrix (synthetic_test_matrix_100). meta.data Cell-level metadata four columns: orig.ident, nCount_RNA, nFeature_RNA, genotype (WT vs. Mutant). See synthetic_test_metadata. features 100 genes: 18 original Wnt genes (rows 1–18) plus 82 randomly expressed genes housekeeping, cell-cycle, TF, Notch, MAPK/ERK, TGF-β/BMP, adhesion panels (rows 19–100). cells 2000 cells named \"Cell1\" … \"Cell2000\".","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object_100.html","id":"source","dir":"Reference","previous_headings":"","what":"Source","title":"Expanded Example Seurat Object for Testing (100 genes) — synthetic_test_object_100","text":"Expanded synthetic_test_object demonstration purposes.","code":""},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object_100.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Expanded Example Seurat Object for Testing (100 genes) — synthetic_test_object_100","text":"Created CreateSeuratObject(min.cells = 0, min.features = 0) every gene cell underlying matrix retained. Compatible Seurat v4 v5 (SeuratObject >= 4.1).","code":""},{"path":[]},{"path":"https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object_100.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Expanded Example Seurat Object for Testing (100 genes) — synthetic_test_object_100","text":"","code":"data(synthetic_test_object_100) synthetic_test_object_100 #> Loading required package: SeuratObject #> Warning: package ‘SeuratObject’ was built under R version 4.4.3 #> Loading required package: sp #> Warning: package ‘sp’ was built under R version 4.4.3 #> #> Attaching package: ‘SeuratObject’ #> The following objects are masked from ‘package:base’: #> #> intersect, t #> An object of class Seurat #> 100 features across 2000 samples within 1 assay #> Active assay: RNA (100 features, 0 variable features) #> 3 layers present: counts, data, scale.data Seurat::Idents(synthetic_test_object_100) <- \"genotype\" table(Seurat::Idents(synthetic_test_object_100)) # 1000 WT, 1000 Mutant #> #> WT Mutant #> 1000 1000"}] diff --git a/docs/sitemap.xml b/docs/sitemap.xml index a72da63..6281fa4 100644 --- a/docs/sitemap.xml +++ b/docs/sitemap.xml @@ -1,22 +1,29 @@ -/404.html -/LICENSE-text.html -/LICENSE.html -/articles/beta_catenin_ko.html -/articles/examples.html -/articles/index.html -/articles/spatial_pathway.html -/authors.html -/index.html -/reference/CalculatePercentage.html -/reference/ComputeCellData.html -/reference/LoadPathway.html -/reference/PathwayMaxMin.html -/reference/PlotPathway.html -/reference/PreparePlotData.html -/reference/fake_final_mds.html -/reference/fake_test_object.html -/reference/fake_to_plot.html -/reference/index.html +https://raredonlab.github.io/PathwayEmbed/404.html +https://raredonlab.github.io/PathwayEmbed/LICENSE-text.html +https://raredonlab.github.io/PathwayEmbed/LICENSE.html +https://raredonlab.github.io/PathwayEmbed/articles/Notch_Analysis_updated.html +https://raredonlab.github.io/PathwayEmbed/articles/TGFB_database_construction.html +https://raredonlab.github.io/PathwayEmbed/articles/beta_catenin_ko_updated.html +https://raredonlab.github.io/PathwayEmbed/articles/examples_updated.html +https://raredonlab.github.io/PathwayEmbed/articles/index.html +https://raredonlab.github.io/PathwayEmbed/articles/spatial_pathway_updated.html +https://raredonlab.github.io/PathwayEmbed/authors.html +https://raredonlab.github.io/PathwayEmbed/index.html +https://raredonlab.github.io/PathwayEmbed/reference/CalculatePercentage.html +https://raredonlab.github.io/PathwayEmbed/reference/ComputeCellData.html +https://raredonlab.github.io/PathwayEmbed/reference/DataPreProcess.html +https://raredonlab.github.io/PathwayEmbed/reference/ListPathway.html +https://raredonlab.github.io/PathwayEmbed/reference/LoadPathway.html +https://raredonlab.github.io/PathwayEmbed/reference/PathwayMaxMin.html +https://raredonlab.github.io/PathwayEmbed/reference/PlotPathway.html +https://raredonlab.github.io/PathwayEmbed/reference/PreparePlotData.html +https://raredonlab.github.io/PathwayEmbed/reference/index.html +https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_matrix.html +https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_matrix_100.html +https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_metadata.html +https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_metadata_100.html +https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object.html +https://raredonlab.github.io/PathwayEmbed/reference/synthetic_test_object_100.html diff --git a/inst/extdata/COI_2.rds b/inst/extdata/COI_2.rds new file mode 100644 index 0000000..b4facac Binary files /dev/null and b/inst/extdata/COI_2.rds differ diff --git a/inst/extdata/HIf1a_score.rds b/inst/extdata/HIf1a_score.rds new file mode 100644 index 0000000..aa215f1 Binary files /dev/null and b/inst/extdata/HIf1a_score.rds differ diff --git a/inst/extdata/Hippo_score.rds b/inst/extdata/Hippo_score.rds new file mode 100644 index 0000000..40ce3ec Binary files /dev/null and b/inst/extdata/Hippo_score.rds differ diff --git a/inst/extdata/Notch_score.rds b/inst/extdata/Notch_score.rds new file mode 100644 index 0000000..fc663ad Binary files /dev/null and b/inst/extdata/Notch_score.rds differ diff --git a/inst/extdata/Pathway_Database_Combined.xlsx b/inst/extdata/Pathway_Database_Combined.xlsx new file mode 100644 index 0000000..b43389c Binary files /dev/null and b/inst/extdata/Pathway_Database_Combined.xlsx differ diff --git a/inst/extdata/Pathway_Embedding.xlsx b/inst/extdata/Pathway_Embedding.xlsx index 4ad26c8..6a7738e 100644 Binary files a/inst/extdata/Pathway_Embedding.xlsx and b/inst/extdata/Pathway_Embedding.xlsx differ diff --git a/inst/extdata/TGFb_score.rds b/inst/extdata/TGFb_score.rds new file mode 100644 index 0000000..020fb2f Binary files /dev/null and b/inst/extdata/TGFb_score.rds differ diff --git a/inst/extdata/Wnt_score.rds b/inst/extdata/Wnt_score.rds new file mode 100644 index 0000000..0cb52f6 Binary files /dev/null and b/inst/extdata/Wnt_score.rds differ diff --git a/inst/extdata/cluster_of_interest.rds b/inst/extdata/cluster_of_interest.rds new file mode 100644 index 0000000..8c46996 Binary files /dev/null and b/inst/extdata/cluster_of_interest.rds differ diff --git a/inst/extdata/pathway_list.rds b/inst/extdata/combined_df_lists_updated.rds similarity index 57% rename from inst/extdata/pathway_list.rds rename to inst/extdata/combined_df_lists_updated.rds index bc843cb..c4fd2f8 100644 Binary files a/inst/extdata/pathway_list.rds and b/inst/extdata/combined_df_lists_updated.rds differ diff --git a/inst/extdata/combined_df_lists.rds b/inst/extdata/confounder_df.rds similarity index 51% rename from inst/extdata/combined_df_lists.rds rename to inst/extdata/confounder_df.rds index e0c5641..0085908 100644 Binary files a/inst/extdata/combined_df_lists.rds and b/inst/extdata/confounder_df.rds differ diff --git a/inst/extdata/moran_df_plot.rds b/inst/extdata/moran_df_plot.rds new file mode 100644 index 0000000..670e7d1 Binary files /dev/null and b/inst/extdata/moran_df_plot.rds differ diff --git a/inst/extdata/moran_results.rds b/inst/extdata/moran_results.rds new file mode 100644 index 0000000..f4e24bf Binary files /dev/null and b/inst/extdata/moran_results.rds differ diff --git a/inst/extdata/pathway_list_timepoint.rds b/inst/extdata/pathway_list_timepoint.rds new file mode 100644 index 0000000..c946d48 Binary files /dev/null and b/inst/extdata/pathway_list_timepoint.rds differ diff --git a/inst/extdata/progeny_scores.rds b/inst/extdata/progeny_scores.rds new file mode 100644 index 0000000..5b6c337 Binary files /dev/null and b/inst/extdata/progeny_scores.rds differ diff --git a/man/CalculatePercentage.Rd b/man/CalculatePercentage.Rd index d0df29c..8e413c4 100644 --- a/man/CalculatePercentage.Rd +++ b/man/CalculatePercentage.Rd @@ -7,19 +7,44 @@ CalculatePercentage(to.plot, group_var) } \arguments{ -\item{to.plot}{A data frame containing at least a \code{scale} column and a grouping column.} +\item{to.plot}{A data frame from \code{PreparePlotData()}, containing at +least a \code{scale} column and the grouping column specified by +\code{group_var}.} -\item{group_var}{A string specifying the grouping variable (e.g., "genotype", "treatment").} +\item{group_var}{A character string specifying the grouping column in +\code{to.plot} (e.g. \code{"genotype"}, \code{"treatment"}).} } \value{ -A data frame with the percentage of ON/OFF cells and Cohen's d (if applicable). +A data frame with columns: +\describe{ +\item{group}{Group label.} +\item{percentage_on}{Percentage of cells with \code{scale > 0}.} +\item{percentage_off}{Percentage of cells with \code{scale < 0}.} +\item{cohens_d}{(2-group only) Cohen's d effect size. Repeated for +both group rows as it is a single pairwise estimate.} +\item{p_value}{(2-group only) Wilcoxon rank-sum p-value.} +\item{kruskal_p}{(3+ groups only) Kruskal-Wallis p-value.} +} +For 3+ groups, Bonferroni-corrected pairwise Wilcoxon p-values are +attached via \code{attr(result, "pairwise_wilcox")}. } \description{ -This function calculates the percentage of cells in ON (scale > 0) and OFF (scale < 0) -activation states within each group defined by \code{group_var}. If exactly two groups -are provided, it also computes Cohen's d effect size between their activation values. +Calculates the percentage of cells in ON (\code{scale > 0}) and OFF +(\code{scale < 0}) activation states within each group defined by +\code{group_var}. +} +\details{ +If exactly two groups are provided, Cohen's d effect size and a Wilcoxon +rank-sum p-value are computed between the two groups. + +If more than two groups are provided, a Kruskal-Wallis p-value is computed +across all groups, and pairwise Wilcoxon p-values (Bonferroni-corrected) are +attached as an attribute. } \examples{ +\dontrun{ data(fake_to_plot) CalculatePercentage(fake_to_plot, "genotype") } + +} diff --git a/man/ComputeCellData.Rd b/man/ComputeCellData.Rd index c5e25d6..9363a19 100644 --- a/man/ComputeCellData.Rd +++ b/man/ComputeCellData.Rd @@ -4,37 +4,36 @@ \alias{ComputeCellData} \title{ComputeCellData} \usage{ -ComputeCellData( - x, - pathway, - distance.method, - batch.size = batch.size, - scale.data = TRUE -) +ComputeCellData(expr_data, pathway.stat, distance.method = "manhattan") } \arguments{ -\item{x}{A \code{Seurat} object containing single-cell RNA sequencing data.} +\item{expr_data}{A z-scored gene-by-cell numeric matrix, e.g. from +\code{DataPreProcess()}.} -\item{pathway}{A \code{character} string specifying the pathway name. This should match a pathway used by \code{LoadPathway()}.} +\item{pathway.stat}{A data frame from \code{PathwayMaxMin()} with columns +\code{pathway.on} and \code{pathway.off}. Rownames must be gene symbols.} -\item{distance.method}{A \code{character} string specifying the distance metric to use.Default is "manhattan". -Options include: \code{"manhattan"}, \code{"euclidean"}, \code{"canberra"}, \code{"binary"}, \code{"minkowski"}} - -\item{batch.size}{An \code{integer} specifying the number of cells to process per batch. Default is 1000.} - -\item{scale.data}{A \code{logical} indicating whether to use scaled data (\code{scale.data = TRUE}) or normalized data. Default is \code{TRUE}.} +\item{distance.method}{Character string specifying the distance metric. +One of \code{"manhattan"} (default) or \code{"euclidean"}.} } \value{ -A data frame of MDS results with normalized values per cell, suitable for thresholding or visualization. +A named numeric vector of length equal to the number of cells, +with scores in [0, 1]. A score near 1 indicates the cell is close to +the ON state; a score near 0 indicates proximity to the OFF state. +Cells where both distances are 0 return \code{NaN} with a warning. } \description{ -A function computes cell status for a given pathway in single-cell RNA-seq data, -based on the distance between genes in a specified pathway. The distance is computed -for each batch of cells, and classical multidimensional scaling (MDS) is used to -visualize the pathway expression across cells. +Computes a per-cell pathway activation score by measuring each cell's +distance to the pathway ON and OFF reference states from +\code{PathwayMaxMin()}. Scores are normalized to [0, 1]\, where 1 indicates +proximity to the ON state and 0 indicates proximity to the OFF state. } \examples{ -data(fake_test_object) -ComputeCellData(fake_test_object, pathway = "Wnt", distance.method = "manhattan", batch.size = 2000) +\dontrun{ +pathwaydata <- LoadPathway("Hypoxia_6hr", "human") +expr_filtered <- DataPreProcess(norm_matrix, pathwaydata) +pathway_stat <- PathwayMaxMin(expr_filtered, pathwaydata) +scores <- ComputeCellData(expr_filtered, pathway_stat) +} } diff --git a/man/DataPreProcess.Rd b/man/DataPreProcess.Rd new file mode 100644 index 0000000..791e8ca --- /dev/null +++ b/man/DataPreProcess.Rd @@ -0,0 +1,46 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/DataPreProcess.R +\name{DataPreProcess} +\alias{DataPreProcess} +\title{DataPreProcess} +\usage{ +DataPreProcess( + x, + pathwaydata, + Seurat.object = FALSE, + assay = "RNA", + slot = "data", + scale.data = TRUE +) +} +\arguments{ +\item{x}{A Seurat object OR a gene-by-cell normalized expression matrix} + +\item{pathwaydata}{Pathway data from the output of LoadPathway()} + +\item{Seurat.object}{Logical; whether x is a Seurat object} + +\item{assay}{Assay to use if x is a Seurat object (default = "RNA")} + +\item{slot}{Slot to extract from Seurat object (default = "data")} + +\item{scale.data}{Logical; whether to apply row-wise z-score scaling +(default = TRUE). If FALSE, the filtered expression matrix is returned +as-is without any scaling.} +} +\value{ +A gene-by-cell expression matrix of pathway genes. If +\code{scale.data = TRUE} (default), values are row-wise z-scored; +if \code{scale.data = FALSE}, raw input filtered values are returned. +} +\description{ +Preprocess expression data for pathway analysis. +} +\examples{ +\dontrun{ +DataPreProcess(seurat_obj, pathwaydata, Seurat.object = TRUE) +DataPreProcess(norm_matrix, pathwaydata) +DataPreProcess(norm_matrix, pathwaydata, scale.data = FALSE) +} + +} diff --git a/man/ListPathway.Rd b/man/ListPathway.Rd new file mode 100644 index 0000000..6508d9d --- /dev/null +++ b/man/ListPathway.Rd @@ -0,0 +1,38 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ListPathway.R +\name{ListPathway} +\alias{ListPathway} +\title{ListPathway +List available pathways or pathway metadata} +\usage{ +ListPathway(query = NULL, drop_empty = TRUE) +} +\arguments{ +\item{query}{Optional character string. One of \code{NULL}, \code{"Pathway"}, +or a valid pathway name. Default \code{NULL}.} + +\item{drop_empty}{Logical; if \code{TRUE}, removes entries with 0 genes. +Default \code{TRUE}.} +} +\value{ +A tibble (full table or pathway subset) or a character vector +(when \code{query = "Pathway"}). +} +\description{ +Reads the "SUMMARY" sheet from Pathway_Database_Combined.xlsx. +Behaviour depends on the \code{query} argument: +\itemize{ +\item \code{NULL}: returns the full summary table as a tibble. +\item \code{"Pathway"}: returns a sorted character vector of unique pathway names. +\item A valid pathway name (e.g. \code{"WNT"}, \code{"NOTCH"}): returns the +subset of rows for that pathway as a tibble. +} +} +\examples{ +\dontrun{ +ListPathway() +ListPathway("Pathway") +ListPathway("WNT") +} + +} diff --git a/man/LoadPathway.Rd b/man/LoadPathway.Rd index 53554a1..b1bee70 100644 --- a/man/LoadPathway.Rd +++ b/man/LoadPathway.Rd @@ -4,17 +4,34 @@ \alias{LoadPathway} \title{LoadPathway} \usage{ -LoadPathway(pathway) +LoadPathway(Sheet.name, species = "human") } \arguments{ -\item{pathway}{A \code{character} string specifying the pathway name.} +\item{Sheet.name}{A character string specifying the sheet name +(e.g. \code{"Hypoxia_6hr"}, \code{"HIPPO_heat"}). Use \code{ListPathway()} +to see available sheets.} + +\item{species}{A character string specifying the species: either +\code{"human"} or \code{"mouse"}. Determines which gene symbol column is +used. Default \code{"human"}.} } \value{ -A data frame with pathway data. +A data frame with two columns: +\describe{ +\item{Gene_Symbol}{Gene symbols for the requested species.} +\item{Coefficient}{Numeric pathway coefficients.} +} +Rows with \code{NA} gene symbols are dropped. } \description{ -This function reads pathway data from the package's built-in Excel file. +Reads pathway gene data from the package's built-in Excel database and +returns a two-column data frame with gene symbols and their coefficients +for the requested species. } \examples{ -LoadPathway("Wnt") +\dontrun{ +LoadPathway("Hypoxia_6hr", "human") +LoadPathway("HIPPO_heat", "mouse") +} + } diff --git a/man/PathwayMaxMin.Rd b/man/PathwayMaxMin.Rd index d473aa9..8e47448 100644 --- a/man/PathwayMaxMin.Rd +++ b/man/PathwayMaxMin.Rd @@ -4,22 +4,23 @@ \alias{PathwayMaxMin} \title{PathwayMaxMin} \usage{ -PathwayMaxMin(x, pathway, scale.data = TRUE) +PathwayMaxMin(expr_data, pathwaydata) } \arguments{ -\item{x}{A Seurat Object.} +\item{expr_data}{Pre-processed gene-by-cell matrix (z-scored, pathway-filtered)} -\item{pathway}{A \code{character} string specifying the pathway name.} - -\item{scale.data}{A \code{logical} indicating whether to use scaled data (\code{scale.data = TRUE}) or normalized data. Default is \code{TRUE}.} +\item{pathwaydata}{Pathway data outcome from LoadPathway()} } \value{ -The hypothetical value for Pathway on and off (max and min value for features) +A data.frame with pathway.on and pathway.off values per gene } \description{ A function to obtain the hypothetical max and min activation status of selected pathway for a given scRNA seq data set } \examples{ -data(fake_test_object) # load the fake test data -PathwayMaxMin(fake_test_object, "Wnt") +\dontrun{ +pathwaydata <- LoadPathway("Hypoxia_6hr", "human") +matrix_filtered <- DataPreProcess(expr_data, pathwaydata) +PathwayMaxMin(matrix_filtered, pathwaydata) +} } diff --git a/man/PlotPathway.Rd b/man/PlotPathway.Rd index 4f7ed94..caab22a 100644 --- a/man/PlotPathway.Rd +++ b/man/PlotPathway.Rd @@ -7,21 +7,31 @@ PlotPathway(to.plot, pathway, group, color) } \arguments{ -\item{to.plot}{A data frame with pathway activation values genereated by PreparePlotData} +\item{to.plot}{A dataframe returned by PreparePlotData, containing at least: +\describe{ +\item{scale}{Z-scored pathway activation values.} +\item{group}{Grouping variable for coloring (e.g., genotype).} +}} -\item{pathway}{A character string indicating the pathway name.} +\item{pathway}{Character string indicating the pathway name (used in plot title).} -\item{group}{Column name to group and color by (e.g., genotype).} +\item{group}{Column name in \code{to.plot} to group and color the plot by (e.g., "genotype").} -\item{color}{A character vector of colors to use for fill and outline.} +\item{color}{Character vector of colors for each group (fill and outline). Length must match number of unique groups.} } \value{ -A ggplot object. +A ggplot2 object showing density distributions of pathway activity per group. } \description{ -A function to plot the Pathway activation status +Plot the activation status of a pathway across cell populations. +Creates a density plot of pathway activation (z-scored) for each group. } \examples{ +\dontrun{ data(fake_to_plot) -PlotPathway(to.plot = fake_to_plot,"Wnt","genotype",color = c("#ae282c", "#2066a8")) +PlotPathway(to.plot = fake_to_plot, + pathway = "Wnt", + group = "genotype", + color = c("#ae282c", "#2066a8")) +} } diff --git a/man/PreparePlotData.Rd b/man/PreparePlotData.Rd index b480950..0a3fc3d 100644 --- a/man/PreparePlotData.Rd +++ b/man/PreparePlotData.Rd @@ -2,25 +2,44 @@ % Please edit documentation in R/PreparePlotData.R \name{PreparePlotData} \alias{PreparePlotData} -\title{A function to prepare the signal transduction dataframe for plotting} +\title{PreparePlotData} \usage{ -PreparePlotData(x, final_mds, group) +PreparePlotData(x, score, group, Seurat.object = FALSE) } \arguments{ -\item{x}{A \code{Seurat} object containing single-cell RNA sequencing data.} +\item{x}{A metadata data frame (rows = cells, columns = metadata fields) +or a Seurat object. Must contain the column specified by \code{group}.} -\item{final_mds}{A 'dataframe' output from ComputeCellData.} +\item{score}{A named numeric vector of per-cell scores from +\code{ComputeCellData()}. Names must be cell IDs matching rownames of \code{x}.} -\item{group}{group for the comparision} +\item{group}{A character string giving the column name in \code{x} metadata +to use for grouping (e.g. \code{"genotype"}, \code{"Age"}).} + +\item{Seurat.object}{Logical; set \code{TRUE} if \code{x} is a Seurat object. +Default \code{FALSE}.} } \value{ -data for plotting +A data frame with one row per cell and three columns: +\describe{ +\item{normalized}{Normalized pathway activity score in [0, 1]\ from +\code{ComputeCellData()}.} +\item{scale}{Z-scored pathway activity across all cells.} +\item{\if{html}{\out{}}}{The grouping variable, named after the \code{group} argument.} +} } \description{ -A function to prepare the signal transduction dataframe for plotting +Prepares a tidy data frame of pathway activity scores per cell for +downstream plotting with \code{PlotPathway()} or \code{CalculatePercentage()}. +Accepts either a plain metadata data frame or a Seurat object. } \examples{ -data(fake_test_object) -data(fake_final_mds) -PreparePlotData(fake_test_object, fake_final_mds, "genotype") +\dontrun{ +# Using a plain metadata data frame +plotdata <- PreparePlotData(metadata_df, scores, "genotype") + +# Using a Seurat object +plotdata <- PreparePlotData(seurat_obj, scores, "orig.ident", Seurat.object = TRUE) +} + } diff --git a/man/fake_final_mds.Rd b/man/fake_final_mds.Rd deleted file mode 100644 index 4dff275..0000000 --- a/man/fake_final_mds.Rd +++ /dev/null @@ -1,25 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/data_documentation.R -\docType{data} -\name{fake_final_mds} -\alias{fake_final_mds} -\title{Example Cell Status and Normalized Data} -\format{ -A data frame with the following columns: -\describe{ -\item{V1}{A numerical value presenting the status of the cell} -\item{normalized}{Numerical value representing normalized data} -} -} -\usage{ -data(fake_final_mds) -} -\description{ -A dataset generated by \code{ComputeCellData} applied to \code{fake_test_object}. -Contains cell status and normalized values. -} -\examples{ -data(fake_final_mds) -head(fake_final_mds) -} -\keyword{datasets} diff --git a/man/fake_to_plot.Rd b/man/fake_to_plot.Rd deleted file mode 100644 index 59a4c55..0000000 --- a/man/fake_to_plot.Rd +++ /dev/null @@ -1,27 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/data_documentation.R -\docType{data} -\name{fake_to_plot} -\alias{fake_to_plot} -\title{Example Processed Data for Plotting} -\format{ -A data frame with the following columns: -\describe{ -\item{V1}{A numerical or categorical value depending on the specific analysis} -\item{normalized}{Normalized numerical value representing the cell's data} -\item{genotype}{Group classification of the cell (e.g., "WT", "Mutant")} -\item{scale}{Scaled data for visualization purposes} -} -} -\usage{ -data(fake_to_plot) -} -\description{ -A dataset generated by running \code{PreparePlotData} on \code{fake_test_object} and \code{fake_final_mds}. -Contains processed data ready for visualization, with the following features: -} -\examples{ -data(fake_to_plot) -head(fake_to_plot) -} -\keyword{datasets} diff --git a/man/synthetic_test_matrix.Rd b/man/synthetic_test_matrix.Rd new file mode 100644 index 0000000..3964761 --- /dev/null +++ b/man/synthetic_test_matrix.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data_documentation.R +\docType{data} +\name{synthetic_test_matrix} +\alias{synthetic_test_matrix} +\title{Example Matrix for Testing} +\format{ +A numeric matrix with genes (rows) and cells (columns). +\describe{ +\item{Rows}{18 genes (e.g. "Lgr5", "Rnf43", "Lrp5", "Fzd6" ...)} +\item{Columns}{2000 cells (named "Cell1", "Cell2", ...)} +\item{Values}{35830 nonzero entries, representing expression values (numeric)} +} +} +\source{ +Simulated for demonstration purposes. +} +\usage{ +synthetic_test_matrix +} +\description{ +A numeric matrix containing single-cell gene expression data for demonstration purposes in the PathwayEmbed package. +Rows correspond to genes and columns correspond to individual cells. +} +\details{ +This is a synthetic dataset created for testing and demonstration purposes. +It mimics the structure of a gene-by-cell expression matrix used in single-cell +RNA sequencing analysis. +} +\examples{ +data(synthetic_test_matrix) +} +\keyword{datasets} diff --git a/man/synthetic_test_matrix_100.Rd b/man/synthetic_test_matrix_100.Rd new file mode 100644 index 0000000..e02d634 --- /dev/null +++ b/man/synthetic_test_matrix_100.Rd @@ -0,0 +1,56 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data_documentation.R +\docType{data} +\name{synthetic_test_matrix_100} +\alias{synthetic_test_matrix_100} +\title{Expanded Example Matrix for Testing (100 genes)} +\format{ +A numeric matrix with 100 rows (genes) and 2000 columns (cells): +\describe{ +\item{Rows}{100 genes. Rows 1–18 are the original Wnt pathway genes +with their original expression values unchanged. Rows 19–100 are randomly expressed genes from +housekeeping, cell-cycle, TF, Notch, MAPK/ERK, TGF-β/BMP, and +adhesion panels.} +\item{Columns}{2000 cells named \code{"Cell1"} through +\code{"Cell2000"}, matching \code{synthetic_test_matrix}.} +\item{Values}{Non-negative integer expression counts. Rows 1–18 are +taken directly from \code{synthetic_test_matrix}. Rows 19–100 are +simulated via a zero-inflated negative-binomial distribution +(mu = 2.5, size = 0.8, ~35 \\% non-zero density).} +} +} +\source{ +Simulated for demonstration purposes, expanded from +\code{synthetic_test_object}. +} +\usage{ +synthetic_test_matrix_100 +} +\description{ +A numeric matrix containing single-cell gene expression data for +demonstration and testing in the PathwayEmbed package. +This expanded version contains 100 genes: the original 18 Wnt-pathway +genes from \code{synthetic_test_matrix} (rows 1–18, values preserved +exactly) plus 82 additional randomly expressed genes drawn from +housekeeping, cell-cycle, transcription-factor, Notch, MAPK/ERK, +TGF-β/BMP, and adhesion gene sets. +} +\details{ +Because the first 18 rows are byte-for-byte identical to +\code{synthetic_test_matrix}, any existing code that subsets to the +Wnt gene panel will return the same results as before. The 82 extra +genes carry no planted biological signal; they are intended for +testing functions that operate on larger or multi-pathway gene panels, +such as dimensionality reduction, clustering, or multi-pathway scoring. +} +\examples{ +data(synthetic_test_matrix_100) +dim(synthetic_test_matrix_100) # 100 x 2000 +rownames(synthetic_test_matrix_100)[1:18] # original Wnt genes +mean(synthetic_test_matrix_100 > 0) # ~0.35 non-zero density +} +\seealso{ +\code{\link{synthetic_test_matrix}}, +\code{\link{synthetic_test_object_100}} +} +\keyword{datasets} diff --git a/man/synthetic_test_metadata.Rd b/man/synthetic_test_metadata.Rd new file mode 100644 index 0000000..4c99139 --- /dev/null +++ b/man/synthetic_test_metadata.Rd @@ -0,0 +1,31 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data_documentation.R +\docType{data} +\name{synthetic_test_metadata} +\alias{synthetic_test_metadata} +\title{synthetic metadata for test cells} +\format{ +A data frame with 2000 rows and 4 variables: +\describe{ +\item{orig.ident}{Character, project identifier} +\item{nCount_RNA}{Integer, total RNA counts per cell} +\item{nFeature_RNA}{Integer, number of detected features (genes) per cell} +\item{genotype}{Factor/character, cell genotype (e.g., "WT", "Mutant")} +} +} +\usage{ +synthetic_test_metadata +} +\description{ +A toy metadata table corresponding to the columns of \code{synthetic_test_matrix}. +Each row represents a single cell with associated metadata. +} +\details{ +This dataset provides toy cell-level metadata designed to accompany +\code{synthetic_test_matrix}. It mimics the structure of single-cell +experiment metadata used in analysis frameworks such as Seurat. +} +\examples{ +data(synthetic_test_metadata) +} +\keyword{datasets} diff --git a/man/fake_test_object.Rd b/man/synthetic_test_object.Rd similarity index 81% rename from man/fake_test_object.Rd rename to man/synthetic_test_object.Rd index 5879575..e635618 100644 --- a/man/fake_test_object.Rd +++ b/man/synthetic_test_object.Rd @@ -1,8 +1,8 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/data_documentation.R \docType{data} -\name{fake_test_object} -\alias{fake_test_object} +\name{synthetic_test_object} +\alias{synthetic_test_object} \title{Example Seurat Object for Testing} \format{ A Seurat object. The object contains: @@ -17,10 +17,10 @@ A Seurat object. The object contains: Simulated for demonstration purposes. } \usage{ -data(fake_test_object) +data(synthetic_test_object) } \description{ -A simulated Seurat object with fake gene expression data for the Wnt signaling pathway. +A simulated Seurat object with synthetic gene expression data for the Wnt signaling pathway. This Seurat object contains gene expression data from simulated cells with Wnt positive and negative gene expression values. } diff --git a/man/synthetic_test_object_100.Rd b/man/synthetic_test_object_100.Rd new file mode 100644 index 0000000..1695b15 --- /dev/null +++ b/man/synthetic_test_object_100.Rd @@ -0,0 +1,51 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data_documentation.R +\docType{data} +\name{synthetic_test_object_100} +\alias{synthetic_test_object_100} +\title{Expanded Example Seurat Object for Testing (100 genes)} +\format{ +A Seurat object containing: +\describe{ +\item{assays}{A single \code{RNA} assay storing the 100 × 2000 +count matrix (\code{synthetic_test_matrix_100}).} +\item{meta.data}{Cell-level metadata with four columns: +\code{orig.ident}, \code{nCount_RNA}, \code{nFeature_RNA}, and +\code{genotype} (WT vs. Mutant). See +\code{\link{synthetic_test_metadata}}.} +\item{features}{100 genes: 18 original Wnt genes (rows 1–18) plus +82 randomly expressed genes from housekeeping, cell-cycle, TF, +Notch, MAPK/ERK, TGF-β/BMP, and adhesion panels (rows 19–100).} +\item{cells}{2000 cells named \code{"Cell1"} … \code{"Cell2000"}.} +} +} +\source{ +Expanded from \code{synthetic_test_object} for demonstration +purposes. +} +\usage{ +synthetic_test_object_100 +} +\description{ +A simulated Seurat object built from \code{synthetic_test_matrix_100} +and \code{synthetic_test_metadata}. It is the 100-gene counterpart +of \code{synthetic_test_object} and is structurally identical except +for the larger gene panel. The original 18 Wnt genes and their +expression values are fully preserved. +} +\details{ +Created with \code{CreateSeuratObject(min.cells = 0, min.features = 0)} +so every gene and cell in the underlying matrix is retained. +Compatible with Seurat v4 and v5 (\code{SeuratObject} >= 4.1). +} +\examples{ +data(synthetic_test_object_100) +synthetic_test_object_100 +Seurat::Idents(synthetic_test_object_100) <- "genotype" +table(Seurat::Idents(synthetic_test_object_100)) # 1000 WT, 1000 Mutant +} +\seealso{ +\code{\link{synthetic_test_object}}, +\code{\link{synthetic_test_matrix_100}}, +} +\keyword{datasets} diff --git a/pkgdown.yml b/pkgdown.yml index 3f4aa35..ed6acbf 100644 --- a/pkgdown.yml +++ b/pkgdown.yml @@ -3,15 +3,25 @@ template: bootswatch: flatly build: - vignettes: false + vignettes: false # we are using pkgdown articles, so disable automatic vignette building articles: - title: "Beta-Catenin Knockout Analysis" contents: - - beta_catenin_ko + - beta_catenin_ko_updated + - title: "Toy Set" contents: - - examples + - examples_updated + - title: "Spatial PathwayEmbed Demonstration" contents: - - spatial_pathway + - spatial_pathway_updated + + - title: "Notch Pathway Analysis" + contents: + - Notch_Analysis_updated + + - title: "TGFb Database Construction" + contents: + - TGFB_database_construction diff --git a/plots_ncstn/ncstn_auroc_barplot.png b/plots_ncstn/ncstn_auroc_barplot.png new file mode 100644 index 0000000..27092db Binary files /dev/null and b/plots_ncstn/ncstn_auroc_barplot.png differ diff --git a/plots_ncstn/ncstn_cohens_d_barplot.png b/plots_ncstn/ncstn_cohens_d_barplot.png new file mode 100644 index 0000000..aef9f06 Binary files /dev/null and b/plots_ncstn/ncstn_cohens_d_barplot.png differ diff --git a/plots_ncstn/ncstn_correlation_heatmap.png b/plots_ncstn/ncstn_correlation_heatmap.png new file mode 100644 index 0000000..efdcdfe Binary files /dev/null and b/plots_ncstn/ncstn_correlation_heatmap.png differ diff --git a/plots_ncstn/ncstn_roc_curves.png b/plots_ncstn/ncstn_roc_curves.png new file mode 100644 index 0000000..02bbd38 Binary files /dev/null and b/plots_ncstn/ncstn_roc_curves.png differ diff --git a/vignettes/Figs/AUROC_barplot.tiff b/vignettes/Figs/AUROC_barplot.tiff new file mode 100644 index 0000000..f88c8ad Binary files /dev/null and b/vignettes/Figs/AUROC_barplot.tiff differ diff --git a/vignettes/Figs/CohensD_barplot.tiff b/vignettes/Figs/CohensD_barplot.tiff new file mode 100644 index 0000000..cc52b6b Binary files /dev/null and b/vignettes/Figs/CohensD_barplot.tiff differ diff --git a/vignettes/Figs/Correlation_1.tiff b/vignettes/Figs/Correlation_1.tiff new file mode 100644 index 0000000..858776a Binary files /dev/null and b/vignettes/Figs/Correlation_1.tiff differ diff --git a/vignettes/Figs/HIF1a_age.png b/vignettes/Figs/HIF1a_age.png new file mode 100644 index 0000000..8609009 Binary files /dev/null and b/vignettes/Figs/HIF1a_age.png differ diff --git a/vignettes/Figs/HIF1a_timepoint_plot.png b/vignettes/Figs/HIF1a_timepoint_plot.png new file mode 100644 index 0000000..2897de1 Binary files /dev/null and b/vignettes/Figs/HIF1a_timepoint_plot.png differ diff --git a/vignettes/Figs/HIF1aage.png b/vignettes/Figs/HIF1aage.png new file mode 100644 index 0000000..8609009 Binary files /dev/null and b/vignettes/Figs/HIF1aage.png differ diff --git a/vignettes/Figs/Hippo_age.png b/vignettes/Figs/Hippo_age.png new file mode 100644 index 0000000..6a8b845 Binary files /dev/null and b/vignettes/Figs/Hippo_age.png differ diff --git a/vignettes/Figs/Hippo_timepoint_plot.png b/vignettes/Figs/Hippo_timepoint_plot.png new file mode 100644 index 0000000..653004a Binary files /dev/null and b/vignettes/Figs/Hippo_timepoint_plot.png differ diff --git a/vignettes/Figs/Hippoage.png b/vignettes/Figs/Hippoage.png new file mode 100644 index 0000000..6a8b845 Binary files /dev/null and b/vignettes/Figs/Hippoage.png differ diff --git a/vignettes/Figs/Notch_timepoint_plot.png b/vignettes/Figs/Notch_timepoint_plot.png new file mode 100644 index 0000000..55ab44d Binary files /dev/null and b/vignettes/Figs/Notch_timepoint_plot.png differ diff --git a/vignettes/Figs/Pathway_activation_by_input.tiff b/vignettes/Figs/Pathway_activation_by_input.tiff new file mode 100644 index 0000000..9d48d79 Binary files /dev/null and b/vignettes/Figs/Pathway_activation_by_input.tiff differ diff --git a/vignettes/Figs/Score_correlation_heatmap.tiff b/vignettes/Figs/Score_correlation_heatmap.tiff new file mode 100644 index 0000000..df275a1 Binary files /dev/null and b/vignettes/Figs/Score_correlation_heatmap.tiff differ diff --git a/vignettes/Figs/TGFb_age.png b/vignettes/Figs/TGFb_age.png new file mode 100644 index 0000000..f40d5c3 Binary files /dev/null and b/vignettes/Figs/TGFb_age.png differ diff --git a/vignettes/Figs/TGFbage.png b/vignettes/Figs/TGFbage.png new file mode 100644 index 0000000..f40d5c3 Binary files /dev/null and b/vignettes/Figs/TGFbage.png differ diff --git a/vignettes/Figs/Tgfb_timepoint_plot.png b/vignettes/Figs/Tgfb_timepoint_plot.png new file mode 100644 index 0000000..c30103a Binary files /dev/null and b/vignettes/Figs/Tgfb_timepoint_plot.png differ diff --git a/vignettes/Figs/WNT_12h_violin.png b/vignettes/Figs/WNT_12h_violin.png new file mode 100644 index 0000000..aa8df55 Binary files /dev/null and b/vignettes/Figs/WNT_12h_violin.png differ diff --git a/vignettes/Figs/WNT_12h_waterfall.png b/vignettes/Figs/WNT_12h_waterfall.png new file mode 100644 index 0000000..13f65c7 Binary files /dev/null and b/vignettes/Figs/WNT_12h_waterfall.png differ diff --git a/vignettes/Figs/Wnt_12h.png b/vignettes/Figs/Wnt_12h.png new file mode 100644 index 0000000..2d25474 Binary files /dev/null and b/vignettes/Figs/Wnt_12h.png differ diff --git a/vignettes/Figs/Wnt_24h.png b/vignettes/Figs/Wnt_24h.png new file mode 100644 index 0000000..df6139b Binary files /dev/null and b/vignettes/Figs/Wnt_24h.png differ diff --git a/vignettes/Figs/Wnt_48h.png b/vignettes/Figs/Wnt_48h.png new file mode 100644 index 0000000..9bb7ad2 Binary files /dev/null and b/vignettes/Figs/Wnt_48h.png differ diff --git a/vignettes/Figs/Wnt_age.png b/vignettes/Figs/Wnt_age.png new file mode 100644 index 0000000..e5711f2 Binary files /dev/null and b/vignettes/Figs/Wnt_age.png differ diff --git a/vignettes/Figs/Wnt_customized_plot.png b/vignettes/Figs/Wnt_customized_plot.png new file mode 100644 index 0000000..1c661f1 Binary files /dev/null and b/vignettes/Figs/Wnt_customized_plot.png differ diff --git a/vignettes/Figs/Wnt_slope.png b/vignettes/Figs/Wnt_slope.png new file mode 100644 index 0000000..7e3df8a Binary files /dev/null and b/vignettes/Figs/Wnt_slope.png differ diff --git a/vignettes/Figs/Wnt_timepoint_plot.png b/vignettes/Figs/Wnt_timepoint_plot.png new file mode 100644 index 0000000..0a5a55e Binary files /dev/null and b/vignettes/Figs/Wnt_timepoint_plot.png differ diff --git a/vignettes/Figs/Wntage.png b/vignettes/Figs/Wntage.png new file mode 100644 index 0000000..e5711f2 Binary files /dev/null and b/vignettes/Figs/Wntage.png differ diff --git a/vignettes/Figs/age_pathway_covariate_correlation.png b/vignettes/Figs/age_pathway_covariate_correlation.png new file mode 100644 index 0000000..b34131f Binary files /dev/null and b/vignettes/Figs/age_pathway_covariate_correlation.png differ diff --git a/vignettes/Figs/age_pathway_vs_stress_scatter.png b/vignettes/Figs/age_pathway_vs_stress_scatter.png new file mode 100644 index 0000000..ab015d1 Binary files /dev/null and b/vignettes/Figs/age_pathway_vs_stress_scatter.png differ diff --git a/vignettes/Figs/auroc_bKO.png b/vignettes/Figs/auroc_bKO.png new file mode 100644 index 0000000..8ebf172 Binary files /dev/null and b/vignettes/Figs/auroc_bKO.png differ diff --git a/vignettes/Figs/auroc_pathways.png b/vignettes/Figs/auroc_pathways.png new file mode 100644 index 0000000..ae512ba Binary files /dev/null and b/vignettes/Figs/auroc_pathways.png differ diff --git a/vignettes/Figs/cohens_d_bKO.png b/vignettes/Figs/cohens_d_bKO.png new file mode 100644 index 0000000..0368885 Binary files /dev/null and b/vignettes/Figs/cohens_d_bKO.png differ diff --git a/vignettes/Figs/confounder_scatter.png b/vignettes/Figs/confounder_scatter.png new file mode 100644 index 0000000..bc14a43 Binary files /dev/null and b/vignettes/Figs/confounder_scatter.png differ diff --git a/vignettes/Figs/cor_bKO.png b/vignettes/Figs/cor_bKO.png new file mode 100644 index 0000000..9de0956 Binary files /dev/null and b/vignettes/Figs/cor_bKO.png differ diff --git a/vignettes/Figs/distance_method_sensitivity.tiff b/vignettes/Figs/distance_method_sensitivity.tiff new file mode 100644 index 0000000..6a54f67 Binary files /dev/null and b/vignettes/Figs/distance_method_sensitivity.tiff differ diff --git a/vignettes/Figs/ncstn_auroc_pathways.png b/vignettes/Figs/ncstn_auroc_pathways.png new file mode 100644 index 0000000..17edfde Binary files /dev/null and b/vignettes/Figs/ncstn_auroc_pathways.png differ diff --git a/vignettes/Figs/ncstn_cohens_d_pathways.png b/vignettes/Figs/ncstn_cohens_d_pathways.png new file mode 100644 index 0000000..57a8a0f Binary files /dev/null and b/vignettes/Figs/ncstn_cohens_d_pathways.png differ diff --git a/vignettes/Figs/null_dis_gene_of_path.png b/vignettes/Figs/null_dis_gene_of_path.png new file mode 100644 index 0000000..7bbfc2e Binary files /dev/null and b/vignettes/Figs/null_dis_gene_of_path.png differ diff --git a/vignettes/Figs/null_distribution_cohens_d.png b/vignettes/Figs/null_distribution_cohens_d.png new file mode 100644 index 0000000..d4bda2e Binary files /dev/null and b/vignettes/Figs/null_distribution_cohens_d.png differ diff --git a/vignettes/Figs/p_benchmark.png b/vignettes/Figs/p_benchmark.png new file mode 100644 index 0000000..752c714 Binary files /dev/null and b/vignettes/Figs/p_benchmark.png differ diff --git a/vignettes/Figs/p_euc_plot.tiff b/vignettes/Figs/p_euc_plot.tiff new file mode 100644 index 0000000..c6dec67 Binary files /dev/null and b/vignettes/Figs/p_euc_plot.tiff differ diff --git a/vignettes/Figs/p_path_cor.png b/vignettes/Figs/p_path_cor.png new file mode 100644 index 0000000..f057145 Binary files /dev/null and b/vignettes/Figs/p_path_cor.png differ diff --git a/vignettes/Figs/p_tech_cor.png b/vignettes/Figs/p_tech_cor.png new file mode 100644 index 0000000..6c69e19 Binary files /dev/null and b/vignettes/Figs/p_tech_cor.png differ diff --git a/vignettes/Figs/pathway_correlation_age.png b/vignettes/Figs/pathway_correlation_age.png new file mode 100644 index 0000000..e362004 Binary files /dev/null and b/vignettes/Figs/pathway_correlation_age.png differ diff --git a/vignettes/Figs/roc_curves_bKO.png b/vignettes/Figs/roc_curves_bKO.png new file mode 100644 index 0000000..5a738d5 Binary files /dev/null and b/vignettes/Figs/roc_curves_bKO.png differ diff --git a/vignettes/Figs/tech_age.png b/vignettes/Figs/tech_age.png new file mode 100644 index 0000000..8abdcc0 Binary files /dev/null and b/vignettes/Figs/tech_age.png differ diff --git a/vignettes/Notch_Analysis_updated.Rmd b/vignettes/Notch_Analysis_updated.Rmd new file mode 100644 index 0000000..a42a736 --- /dev/null +++ b/vignettes/Notch_Analysis_updated.Rmd @@ -0,0 +1,601 @@ +--- +title: "Notch_Analysis" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Notch_Analysis} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +## Overview +This vignette demonstrates the application of PathwayEmbed in a Notch-perturbed +system (Ncstn fl/fl cKO bone marrow) and in aging SSPCs. +Reference: Remark et al., *Bone Res* 11, 50 (2023). + + +```{r setup, include=FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + warning = FALSE, + message = FALSE, + comment = "#>", + dpi = 300, + fig.width = 6, + fig.height = 4, + dev = "png" +) +``` + +--- + +## Load Packages + +```{r load} +library(Seurat) +library(PathwayEmbed) +library(ggplot2) +library(dplyr) +library(patchwork) +library(pheatmap) +library(tidyr) +library(pROC) +``` + +--- + +## Helper: Annotation Label Builder + +```{r helper} +make_label <- function(stats, group1, group2) { + d <- round(stats$cohens_d[1], 3) + p <- formatC(stats$p_value[1], format = "e", digits = 2) + on1 <- stats$percentage_on[stats$group == group1] + off1 <- stats$percentage_off[stats$group == group1] + on2 <- stats$percentage_on[stats$group == group2] + off2 <- stats$percentage_off[stats$group == group2] + paste0( + group1, ": ON=", on1, "%, OFF=", off1, "%\n", + group2, ": ON=", on2, "%, OFF=", off2, "%\n", + "Cohen's d = ", d, "\n", + "p = ", p + ) +} +``` + +--- + +## Data Preprocessing — WT vs. KO (Ncstn cKO) + +The block below is `eval=FALSE` because the raw 10X data are large. The +pre-processed SSPC subset (`COI_2`) is loaded directly from the package in +the next chunk. + +```{r preprocess-ko, eval=FALSE} +wt_data <- Read10X(data.dir = "path/to/WT", gene.column = 2) +ko_data <- Read10X(data.dir = "path/to/KO", gene.column = 2) + +wt_seurat <- CreateSeuratObject(counts = wt_data, project = "WT") +ko_seurat <- CreateSeuratObject(counts = ko_data, project = "KO") +wt_seurat$condition <- "WT" +ko_seurat$condition <- "KO" + +combined <- merge(wt_seurat, y = ko_seurat, + add.cell.ids = c("WT", "KO"), project = "WT_vs_KO") +combined[["RNA"]] <- JoinLayers(combined[["RNA"]]) + +combined[["percent.mt"]] <- PercentageFeatureSet(combined, pattern = "^mt-") +combined <- subset(combined, + subset = nFeature_RNA > 200 & + nFeature_RNA < 2000 & + percent.mt < 10) + +combined <- NormalizeData(combined, normalization.method = "LogNormalize", + scale.factor = 10000) +combined <- FindVariableFeatures(combined, selection.method = "vst", + nfeatures = 2000) +combined <- ScaleData(combined) +combined <- RunPCA(combined) +ElbowPlot(combined, ndims = 50) +combined <- FindNeighbors(combined, dims = 1:20) +combined <- FindClusters(combined, resolution = 1) +combined <- RunUMAP(combined, dims = 1:20) + +DimPlot(combined, label = TRUE) +FeaturePlot(combined, "Cxcl12") +FeaturePlot(combined, "Kitl") + +COI_2 <- subset(combined, subset = seurat_clusters %in% c("23", "25")) +``` + +--- + +## Notch Signaling in Ncstn KO vs. WT SSPCs + +```{r load-ko, echo=FALSE} +COI_2 <- readRDS(system.file("extdata", "COI_2.rds", package = "PathwayEmbed")) +``` + +```{r notch-ko} +COI_2_matrix <- as.matrix(GetAssayData(COI_2, assay = "RNA", layer = "data")) +COI_2_metadata <- COI_2@meta.data + +# Load both Notch databases +ListPathway("NOTCH") +pathwaydata_mus <- LoadPathway("NOTCH_JAG1", "mouse") # mouse perturbation data +pathwaydata_24hr <- LoadPathway("NOTCH_JAG1_24H", "mouse") # human 24hr (cross-species) + +matrix_mus <- DataPreProcess(COI_2_matrix, pathwaydata_mus, Seurat.object = FALSE) +matrix_24hr <- DataPreProcess(COI_2_matrix, pathwaydata_24hr, Seurat.object = FALSE) + +pathwaystat_mus <- PathwayMaxMin(matrix_mus, pathwaydata_mus) +pathwaystat_24hr <- PathwayMaxMin(matrix_24hr, pathwaydata_24hr) + +Notch_score_mus <- ComputeCellData(matrix_mus, pathwaystat_mus) +Notch_score_24hr <- ComputeCellData(matrix_24hr, pathwaystat_24hr) + +to_plot_1 <- PreparePlotData(COI_2_metadata, Notch_score_mus, "condition") +to_plot_2 <- PreparePlotData(COI_2_metadata, Notch_score_24hr, "condition") + +pct_1 <- CalculatePercentage(to_plot_1, "condition") +pct_2 <- CalculatePercentage(to_plot_2, "condition") +pct_1; pct_2 + +# Database comparison: gene overlap and coefficient agreement +genes_mus <- pathwaydata_mus$Gene_Symbol +genes_24hr <- pathwaydata_24hr$Gene_Symbol +shared <- intersect(genes_mus, genes_24hr) + +cat("Genes in mouse database: ", length(genes_mus), "\n") +cat("Genes in human 24hr database: ", length(genes_24hr), "\n") +cat("Shared genes: ", length(shared), "\n") +cat("Unique to mouse database: ", length(setdiff(genes_mus, genes_24hr)), "\n") +cat("Unique to 24hr database: ", length(setdiff(genes_24hr, genes_mus)), "\n") + +coef_mus <- setNames(pathwaydata_mus$Coefficient, pathwaydata_mus$Gene_Symbol) +coef_24hr <- setNames(pathwaydata_24hr$Coefficient, pathwaydata_24hr$Gene_Symbol) +coef_agree <- mean(sign(coef_mus[shared]) == sign(coef_24hr[shared]), na.rm = TRUE) +cat(sprintf("Coefficient direction agreement (shared genes): %.1f%%\n", coef_agree * 100)) + +PlotPathway(to_plot_1, "Notch (mouse database)", "condition", + c("#FFDAB9", "#A3BFD9")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_1, "WT", "KO"), size = 3.5, color = "black") + +PlotPathway(to_plot_2, "Notch (human 24hr database)", "condition", + c("#FFDAB9", "#A3BFD9")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_2, "WT", "KO"), size = 3.5, color = "black") +``` + +--- + +## Benchmark — Ncstn KO vs. WT + +```{r benchmark-ko} +common_genes <- intersect(rownames(COI_2_matrix), pathwaydata_24hr$Gene_Symbol) +gene_matrix <- as.matrix(COI_2_matrix[common_genes, ]) +mean_expr <- colMeans(gene_matrix, na.rm = TRUE) +zscore_mean_per_cell <- colMeans(t(scale(t(gene_matrix))), na.rm = TRUE) + +Notch_features <- rownames(matrix_24hr) +COI_2 <- AddModuleScore( + object = COI_2, + features = list(Notch_features), + name = "Notch_ModuleScore", + ctrl = 5, + nbin = 10 +) +module_score <- setNames( + COI_2@meta.data$Notch_ModuleScore1, + rownames(COI_2@meta.data) +) + +cells <- names(Notch_score_24hr) +benchmark_df <- data.frame( + PathwayEmbed = as.numeric(Notch_score_24hr), + AddModuleScore = as.numeric(module_score[cells]), + mean_expr = as.numeric(mean_expr[cells]), + zscore_expr = as.numeric(zscore_mean_per_cell[cells]), + row.names = cells +) + +benchmark_cor <- cor(benchmark_df, method = "spearman", + use = "pairwise.complete.obs") +print(round(benchmark_cor, 3)) + +p_cor <- pheatmap( + benchmark_cor, + color = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100), + breaks = seq(-1, 1, length.out = 101), + display_numbers = TRUE, number_format = "%.2f", + fontsize_number = 9, + main = "Method Benchmark — Spearman Correlation (Ncstn KO dataset)" +) +p_cor + +ko_label <- ifelse(COI_2@meta.data[cells, "condition"] == "KO", 1L, 0L) + +compute_auroc <- function(scores, labels) { + r <- roc(labels, scores, quiet = TRUE) + auc_val <- as.numeric(auc(r)) + if (auc_val < 0.5) auc_val <- 1 - auc_val + auc_val +} + +auroc_results <- data.frame( + Method = colnames(benchmark_df), + AUROC = sapply(benchmark_df, compute_auroc, labels = ko_label) +) +auroc_results <- auroc_results[order(-auroc_results$AUROC), ] +print(auroc_results) + +compute_cohens_d_method <- function(scores_vec, seurat_obj, group_col) { + pd <- PreparePlotData(seurat_obj, scores_vec, group_col, Seurat.object = TRUE) + pct <- CalculatePercentage(pd, group_var = group_col) + abs(pct$cohens_d[1]) +} + +cohens_d_results <- data.frame( + Method = colnames(benchmark_df), + Cohens_d = sapply( + colnames(benchmark_df), + function(m) { + sv <- setNames(benchmark_df[[m]], rownames(benchmark_df)) + compute_cohens_d_method(sv, COI_2, "condition") + } + ) +) +cohens_d_results <- cohens_d_results[order(-cohens_d_results$Cohens_d), ] +print(cohens_d_results) + +method_colors <- c( + "PathwayEmbed" = "#534AB7", + "zscore_expr" = "#E24B4A", + "AddModuleScore" = "#EF9F27", + "mean_expr" = "#888780" +) + +p_cd <- ggplot(cohens_d_results, + aes(x = reorder(Method, Cohens_d), y = Cohens_d, fill = Method)) + + geom_bar(stat = "identity", width = 0.6) + + coord_flip() + + scale_fill_manual(values = method_colors) + + labs(title = "Effect size (Cohen's d): KO vs. WT", + x = NULL, y = "Cohen's d (absolute)") + + theme_classic() + + theme(legend.position = "none") +p_cd + +p_auroc <- ggplot(auroc_results, + aes(x = reorder(Method, AUROC), y = AUROC, fill = Method)) + + geom_bar(stat = "identity", width = 0.6) + + geom_hline(yintercept = 0.5, linetype = "dashed", color = "black") + + coord_flip() + + scale_fill_manual(values = method_colors) + + labs(title = "AUROC: KO vs. WT separation (Ncstn KO dataset)", + x = NULL, y = "AUROC") + + ylim(0, 1) + + theme_classic() + + theme(legend.position = "none") +p_auroc + +roc_list <- lapply(colnames(benchmark_df), function(m) { + roc(ko_label, benchmark_df[[m]], quiet = TRUE) +}) +names(roc_list) <- colnames(benchmark_df) + +roc_df <- do.call(rbind, lapply(names(roc_list), function(m) { + r <- roc_list[[m]] + data.frame(Method = m, FPR = 1 - r$specificities, TPR = r$sensitivities) +})) + +p_roc <- ggplot(roc_df, aes(x = FPR, y = TPR, color = Method)) + + geom_line(linewidth = 0.9) + + geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "grey60") + + scale_color_manual(values = method_colors) + + labs(title = "ROC curves: KO vs. WT (Ncstn KO dataset)", + x = "False positive rate", y = "True positive rate") + + theme_classic() +p_roc +``` + +--- + +## Data Preprocessing — Middle-Age vs. Young SSPCs + +```{r preprocess-aging, eval=FALSE} +wt_data <- Read10X("path/to/WT", gene.column = 2) +young_data <- Read10X("path/to/Young", gene.column = 2) + +WT_object <- CreateSeuratObject(counts = wt_data) +Young_object <- CreateSeuratObject(counts = young_data) +WT_object$Age <- "MiddleAge" +Young_object$Age <- "Young" + +WT_object[["percent.mt"]] <- PercentageFeatureSet(WT_object, pattern = "^mt-") +Young_object[["percent.mt"]] <- PercentageFeatureSet(Young_object, pattern = "^mt-") + +# NOTE: 30% threshold is intentionally permissive — skeletal stem cells retain +# higher baseline mitochondrial content; tighter thresholds remove genuine SSPCs. +WT_object_filtered <- subset(WT_object, subset = nFeature_RNA >= 100 & percent.mt < 30) +Young_object_filtered <- subset(Young_object, subset = nFeature_RNA >= 100 & percent.mt < 30) + +merge_object <- merge(WT_object_filtered, Young_object_filtered, + add.cell.ids = c("WT", "Young")) +merge_object[["RNA"]] <- JoinLayers(merge_object[["RNA"]]) + +merge_object <- NormalizeData(merge_object) +merge_object <- subset( + merge_object, + features = rownames(merge_object)[ + Matrix::rowSums(GetAssayData(merge_object, slot = "counts") > 0) > 5] +) +merge_object <- FindVariableFeatures(merge_object, selection.method = "vst", + nfeatures = 3000) +merge_object <- ScaleData(merge_object) +merge_object <- RunPCA(merge_object) +ElbowPlot(merge_object) +merge_object <- FindNeighbors(merge_object, dims = 1:10) +merge_object <- FindClusters(merge_object, resolution = 1) +merge_object <- RunUMAP(merge_object, dims = 1:10) + +DimPlot(merge_object, reduction = "umap", group.by = "Age", label = TRUE) +FeaturePlot(merge_object, reduction = "umap", features = "Cxcl12", order = TRUE) + +cluster_of_interest <- subset(merge_object, subset = seurat_clusters == 11) +saveRDS(cluster_of_interest, file = "Middle_age_object.rds") +``` + +--- + +## Notch Signaling in Middle-Age vs. Young SSPCs + +```{r load-aging, echo=FALSE} +cluster_of_interest <- readRDS( + system.file("extdata", "cluster_of_interest.rds", package = "PathwayEmbed") +) +``` + +```{r notch-aging} +# Re-use the human 24hr database loaded earlier +matrix_notch <- DataPreProcess(cluster_of_interest, pathwaydata_24hr, + Seurat.object = TRUE) +pathwaystat_notch <- PathwayMaxMin(matrix_notch, pathwaydata_24hr) +Notch_score <- ComputeCellData(matrix_notch, pathwaystat_notch) + +to_plot <- PreparePlotData(cluster_of_interest, Notch_score, "Age", + Seurat.object = TRUE) +age_stats <- CalculatePercentage(to_plot, "Age") +age_stats + +PlotPathway(to_plot, "Notch", "Age", c("orange", "#6baed6")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(age_stats, "MiddleAge", "Young"), + size = 3.5, color = "black") +``` + +--- + +## Multi-Pathway Analysis — Middle-Age vs. Young SSPCs + +```{r multi-pathway} +HIf1a_pathwaydata <- LoadPathway("Hypoxia_24hr", "mouse") +Hippo_pathwaydata <- LoadPathway("HIPPO_heat", "mouse") +TGFb_pathwaydata <- LoadPathway("TGFB_Mouse", "mouse") +Wnt_pathwaydata <- LoadPathway("WNT3A_SLOPE_ACTIVATION", "mouse") + +pathway_list <- list( + HIF1a = HIf1a_pathwaydata, + Hippo = Hippo_pathwaydata, + TGFb = TGFb_pathwaydata, + Wnt = Wnt_pathwaydata +) + +score_list <- list() +cohens_d_list <- list() + +for (pathway_name in names(pathway_list)) { + pathway_data <- pathway_list[[pathway_name]] + matrix_data <- DataPreProcess(cluster_of_interest, pathway_data, + Seurat.object = TRUE) + pathway_stat <- PathwayMaxMin(matrix_data, pathway_data) + score <- ComputeCellData(matrix_data, pathway_stat) + score_list[[pathway_name]] <- score + + to_plot_p <- PreparePlotData(cluster_of_interest, score, "Age", + Seurat.object = TRUE) + age_stats_p <- CalculatePercentage(to_plot_p, "Age") + cohens_d_list[[pathway_name]] <- abs(age_stats_p$cohens_d[1]) + + p <- PlotPathway(to_plot_p, pathway_name, "Age", c("orange", "#6baed6")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(age_stats_p, "MiddleAge", "Young"), + size = 3.5, color = "black") + + print(p) + ggsave( + filename = paste0("figs/", gsub("[^A-Za-z0-9_]", "_", pathway_name), "_age.png"), + plot = p, width = 5, height = 4, dpi = 300 + ) +} +``` + +--- + +## Cross-Pathway Comparison + +```{r cross-pathway} +# Add Notch to score list (computed in notch-aging chunk) +score_list[["Notch"]] <- Notch_score +cohens_d_list[["Notch"]] <- abs(age_stats$cohens_d[1]) + +# Build score data frame aligned to metadata +score_df <- as.data.frame(score_list) +score_df$cell <- rownames(score_df) + +meta_df <- cluster_of_interest@meta.data +meta_df$cell <- rownames(meta_df) + +score_df$Age <- meta_df$Age[match(score_df$cell, meta_df$cell)] +score_df$Age_binary <- ifelse(score_df$Age == "MiddleAge", 1, 0) + +pathway_cols <- c("HIF1a", "Hippo", "TGFb", "Wnt", "Notch") +pathway_mat <- score_df[, pathway_cols] + +# Spearman correlation heatmap +pathway_cor <- cor(pathway_mat, method = "spearman", use = "pairwise.complete.obs") +print(round(pathway_cor, 3)) + +pheatmap( + pathway_cor, + color = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100), + breaks = seq(-1, 1, length.out = 101), + display_numbers = TRUE, number_format = "%.2f", + fontsize_number = 10, + main = "Spearman Correlation Between Pathways" +) + +# PCA of pathway activity space +pca <- prcomp(pathway_mat, scale. = TRUE) +p_pca <- data.frame(pca$x, Age = score_df$Age) + +ggplot(p_pca, aes(PC1, PC2, color = Age)) + + geom_point(alpha = 0.6) + + theme_classic() + + labs(title = "PCA of pathway activity space") + +# AUROC per pathway +compute_auroc_safe <- function(scores, labels) { + valid <- !is.na(scores) & !is.na(labels) + if (length(unique(labels[valid])) < 2) return(NA) + r <- roc(labels[valid], scores[valid], quiet = TRUE) + a <- as.numeric(auc(r)) + if (a < 0.5) a <- 1 - a + a +} + +auroc_df <- data.frame( + Pathway = pathway_cols, + AUROC = sapply(pathway_cols, function(pw) { + compute_auroc_safe(score_df[[pw]], score_df$Age_binary) + }) +) +auroc_df <- auroc_df[order(-auroc_df$AUROC), ] +print(auroc_df) + +p_auroc_age <- ggplot(auroc_df, + aes(x = reorder(Pathway, AUROC), y = AUROC, fill = Pathway)) + + geom_col(width = 0.6) + + coord_flip() + + geom_hline(yintercept = 0.5, linetype = "dashed") + + geom_text(aes(label = sprintf("%.2f", AUROC)), hjust = -0.1, size = 3) + + ylim(0, 1.05) + + labs(title = "AUROC comparison across pathways", x = NULL, y = "AUROC") + + theme_classic() + + theme(legend.position = "none") +p_auroc_age + +# Cohen's d per pathway +cohens_d_df <- data.frame( + Pathway = names(cohens_d_list), + Cohens_d = unlist(cohens_d_list) +) +cohens_d_df <- cohens_d_df[order(-cohens_d_df$Cohens_d), ] +print(cohens_d_df) + +p_cd <- ggplot(cohens_d_df, + aes(x = reorder(Pathway, Cohens_d), y = Cohens_d, fill = Pathway)) + + geom_col(width = 0.6) + + coord_flip() + + geom_text(aes(label = sprintf("%.2f", Cohens_d)), hjust = -0.1, size = 3) + + ylim(0, max(cohens_d_df$Cohens_d) * 1.1) + + labs(title = "Effect size (Cohen's d) across pathways", x = NULL, y = "Cohen's d (absolute)") + + theme_classic() + + theme(legend.position = "none") +p_cd +``` + +--- + +## Technical Confounders + +```{r confounders} +cc_genes <- Seurat::cc.genes.updated.2019 +cluster_of_interest <- CellCycleScoring( + cluster_of_interest, + s.features = cc_genes$s.genes, + g2m.features = cc_genes$g2m.genes, + set.ident = FALSE +) + +stress_genes <- c( + "Fos", "Jun", "Junb", "Atf3", "Egr1", + "Ddit3", "Atf4", "Xbp1", "Hspa5", + "Hspa1a", "Hspa1b", "Hsp90aa1", + "Gadd45a", "Gadd45b", "Gadd45g" +) +cluster_of_interest <- AddModuleScore( + cluster_of_interest, + features = list(stress_genes), + name = "StressScore", + ctrl = 25, + nbin = 24 +) + +meta_cc <- cluster_of_interest@meta.data + +# Merge scores with metadata +score_df_full <- score_df +score_df_full$S_score <- meta_cc$S.Score[ match(score_df_full$cell, rownames(meta_cc))] +score_df_full$G2M_score <- meta_cc$G2M.Score[match(score_df_full$cell, rownames(meta_cc))] +score_df_full$Stress <- cluster_of_interest$StressScore1[ + match(score_df_full$cell, rownames(meta_cc))] +score_df_full$nCount_RNA <- meta_cc$nCount_RNA[ match(score_df_full$cell, rownames(meta_cc))] +score_df_full$nFeature_RNA <- meta_cc$nFeature_RNA[match(score_df_full$cell, rownames(meta_cc))] +score_df_full$percent.mt <- meta_cc$percent.mt[ match(score_df_full$cell, rownames(meta_cc))] + +covariates <- c("nCount_RNA", "nFeature_RNA", "percent.mt", + "Stress", "S_score", "G2M_score") + +cor_mat <- sapply(covariates, function(cov) { + sapply(pathway_cols, function(pw) { + cor(score_df_full[[pw]], score_df_full[[cov]], + method = "spearman", use = "complete.obs") + }) +}) +rownames(cor_mat) <- pathway_cols +colnames(cor_mat) <- covariates +print(round(cor_mat, 3)) + +pheatmap(cor_mat, + color = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100), + breaks = seq(-1, 1, length.out = 101), + display_numbers = TRUE, number_format = "%.2f", + fontsize_number = 10, + main = "Pathway vs. covariate correlations (Spearman)") + +# Scatter: each pathway vs. stress score +plot_df_long <- pivot_longer( + score_df_full[, c("Stress", pathway_cols)], + cols = all_of(pathway_cols), + names_to = "Pathway", + values_to = "Score" +) + +cor_df_stress <- plot_df_long %>% + group_by(Pathway) %>% + summarise(cor = cor(Stress, Score, method = "spearman", use = "complete.obs"), + .groups = "drop") + +ggplot(plot_df_long, aes(x = Stress, y = Score)) + + geom_point(alpha = 0.4, size = 1.2) + + geom_smooth(method = "lm", se = FALSE, linetype = "dashed", color = "#E24B4A") + + facet_wrap(~ Pathway, scales = "free_y") + + geom_text(data = cor_df_stress, + aes(x = Inf, y = Inf, + label = paste0("\u03c1 = ", round(cor, 2))), + hjust = 1.2, vjust = 1.5, inherit.aes = FALSE) + + theme_classic() + + labs(title = "Pathway scores vs. stress score (Spearman)", + x = "Stress score", y = "Pathway score") +``` diff --git a/vignettes/TGFB_database_construction.Rmd b/vignettes/TGFB_database_construction.Rmd new file mode 100644 index 0000000..16a1303 --- /dev/null +++ b/vignettes/TGFB_database_construction.Rmd @@ -0,0 +1,579 @@ +--- +title: "TGF-β Pathway Database Construction" +author: "PathwayEmbed Package" +date: "`r Sys.Date()`" +output: + html_document: + toc: true + toc_depth: 3 + toc_float: + collapsed: false + theme: flatly + highlight: tango + number_sections: true +vignette: > + %\VignetteIndexEntry{TGF-β Pathway Database Construction} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set( + echo = TRUE, + message = FALSE, + warning = FALSE, + collapse = TRUE, + comment = "#>" +) +``` + +--- + +# Overview + +This vignette documents the construction of the **TGF-β signaling pathway database** used by `PathwayEmbed` for downstream pathway activity scoring and embedding. The same construction workflow is applied to all pathway databases in the package (e.g., WNT, NOTCH, YAP); the TGF-β pathway is used here as the worked example. + +The database integrates: + +1. A manually curated pathway gene list organized by functional category (KEGG hsa04350 ) +2. Separately curated mouse ortholog lists, with attention to symbols that differ substantially between species +3. Differential expression results from two independent bulk RNA-seq datasets covering multiple species and contexts +4. Per-gene **activity coefficients** (+1 / −1) derived from the direction of regulation under TGF-β stimulation + +The final output is a formatted Excel workbook (`TGFB_Pathway_Database.xlsx`) with three sheets: human Day 1, human Day 20, and mouse. + +**Datasets used:** + +| GEO Accession | Species | Model | Comparison | +|---|---|---|---| +| GSE110021 | Human | Lung fibroblasts | TGFβ1 vs. no TGFβ at Day 1 and Day 20 | +| GSE246932 | Mouse | T cells | TGFβ vs. none (2h) | + +--- + +# Step 1: Curate the Pathway Gene List + +## Human Gene List + +TGF-β pathway genes were curated from **KEGG hsa04350** and organized into 20 functional categories spanning canonical SMAD signaling, non-canonical branches (MAPK, PI3K/AKT, RHO), and the extracellular ligand/antagonist landscape. + +```{r tgfb-genes-human} +tgfb_genes_human <- list( + + Ligands_TGFB = c("TGFB1", "TGFB2", "TGFB3"), + + Ligands_BMP = c("BMP2", "BMP4", "BMP5", "BMP6", "BMP7", "BMP8A", "BMP8B", + "BMP10", "BMP15", "GDF5", "GDF6", "GDF7"), + + # NOTE: INHBC and INHBE have no mouse orthologs (see mouse section) + Ligands_Activin_GDF = c("INHBA", "INHBB", "INHBC", "INHBE", + "GDF1", "GDF2", "GDF3", "GDF8", "GDF9", "GDF10", + "GDF11", "GDF15", "AMH", "NODAL"), + + Receptors_TypeI = c("TGFBR1", "ACVR1", "ACVR1B", "ACVR1C", + "BMPR1A", "BMPR1B", "ACVRL1"), + + Receptors_TypeII = c("TGFBR2", "ACVR2A", "ACVR2B", "BMPR2", "AMHR2"), + + # Type III receptors act as co-receptors/presenters + Receptors_TypeIII = c("TGFBR3", "ENG"), + + # R-SMADs: phosphorylated by type I receptors; SMAD1/5/9 for BMP arm, + # SMAD2/3 for TGF-β/Activin arm + SMAD_Regulated = c("SMAD1", "SMAD2", "SMAD3", "SMAD5", "SMAD9"), + SMAD_Common = c("SMAD4"), + SMAD_Inhibitory = c("SMAD6", "SMAD7"), + + # SARA (ZFYVE9) anchors SMAD2/3 at the receptor membrane + SMAD_Anchors = c("SARA", "ZFYVE9"), + + Coactivators = c("CREBBP", "EP300", "SKI", "SKIL", "CITED1", "CITED2", + "FOXH1", "FOXO1", "FOXO3", "RUNX1", "RUNX2", "RUNX3", + "SP1", "JUN", "FOS", "ATF2"), + + Corepressors = c("TGIF1", "TGIF2", "SKI", "SKIL", "SIN3A", "NCOR1", + "NCOR2", "HDAC1", "HDAC2", "HDAC3"), + + E3_Ligases = c("SMURF1", "SMURF2", "NEDD4L", "WWP1", "WWP2", + "RNF12", "STUB1", "TRIM33"), + + Transcriptional_Targets = c( + "SERPINE1", "SMAD7", "CDKN1A", "CDKN2B", + "MYC", "SNAI1", "SNAI2", "TWIST1", "ZEB1", "ZEB2", + "VIM", "CDH1", "CDH2", "MMP2", "MMP9", + "COL1A1", "COL1A2", "COL3A1", "FN1", "ACTA2", + "CTGF", "TGFB1", "ID1", "ID2", "ID3" + ), + + Secreted_Antagonists = c( + "FST", "FSTL1", "FSTL3", "CHRD", "CHRDL1", "CHRDL2", + "NOG", "GREM1", "GREM2", "NBL1", "BAMBI", + "LTBP1", "LTBP2", "LTBP3", "LTBP4", "THBS1", "THBS2", + "DCN", "BGN", "ASPN" + ), + + MAPK_Pathway = c( + "MAP3K7", "TAB1", "TAB2", "TAB3", + "MAP2K3", "MAP2K4", "MAP2K6", "MAP2K7", + "MAPK1", "MAPK3", "MAPK8", "MAPK9", "MAPK10", + "MAPK11", "MAPK12", "MAPK13", "MAPK14" + ), + + PI3K_AKT_Pathway = c("PIK3CA", "PIK3CB", "PIK3CD", "PIK3R1", "PIK3R2", + "AKT1", "AKT2", "AKT3", "MTOR", "RHEB"), + + RHO_Pathway = c("RHOA", "RAC1", "CDC42", "ROCK1", "ROCK2", + "TGFBR1", "PAK1", "PAK2", "LIMK1", "LIMK2"), + + Latency_Activation = c( + "LTBP1", "LTBP2", "LTBP3", "LTBP4", + "LRRC32", "LRRC33", "THBS1", "ITGAV", "ITGB1", + "ITGB3", "ITGB5", "ITGB6", "ITGB8", "MMP2", "MMP9" + ), + + Phosphatases = c("PPM1A", "PPP1CA", "PPP1CB", "PPP1CC", "MTMR4"), + + Nuclear_Transport = c("IMPORTIN7", "IMPORTIN8", "XPO1", "RAN"), + + Other_Regulators = c( + "DAXX", "FNTA", "FKBP1A", "ELF", "YAP1", "TAZ", + "PMEPA1", "TRIM33", "EVI1", "BCOR", "DRAP1", "MAML1", + "PPP2CA", "PPP2R1A", "STRAP", "CDKN1B", "CDKN1C", + "RBL1", "RBL2", "E2F4", "E2F5", "COPS5" + ) +) + +# Genes per category +sapply(tgfb_genes_human, length) +cat("Total unique human TGF-β genes:", length(unique(unlist(tgfb_genes_human))), "\n") +``` + +## Mouse Gene List + +> ⚠️ **Mouse symbols are NOT simply lowercased human symbols.** The mouse list was curated manually with special attention to genes that have completely different symbols between species. Key differences are highlighted below. + +```{r tgfb-genes-mouse} +# Critical human → mouse symbol differences: +# RNF12 → Rlim (E3_Ligases) +# IMPORTIN7 → Ipo7 (Nuclear_Transport) +# IMPORTIN8 → Ipo8 (Nuclear_Transport) +# TAZ (WWTR1) → Wwtr1 (Other_Regulators) +# EVI1 (MECOM)→ Mecom (Other_Regulators) +# SARA → removed (protein name, not gene; gene is Zfyve9) +# INHBC, INHBE→ removed (no mouse ortholog) +# ELF → removed (ambiguous; could be Elf1–5) + +tgfb_genes_mouse <- list( + + Ligands_TGFB = c("Tgfb1", "Tgfb2", "Tgfb3"), + + Ligands_BMP = c("Bmp2", "Bmp4", "Bmp5", "Bmp6", "Bmp7", "Bmp8a", "Bmp8b", + "Bmp10", "Bmp15", "Gdf5", "Gdf6", "Gdf7"), + + # INHBC and INHBE have no mouse orthologs and are excluded + Ligands_Activin_GDF = c("Inhba", "Inhbb", + "Gdf1", "Gdf2", "Gdf3", "Gdf8", "Gdf9", "Gdf10", + "Gdf11", "Gdf15", "Amh", "Nodal"), + + Receptors_TypeI = c("Tgfbr1", "Acvr1", "Acvr1b", "Acvr1c", + "Bmpr1a", "Bmpr1b", "Acvrl1"), + + Receptors_TypeII = c("Tgfbr2", "Acvr2a", "Acvr2b", "Bmpr2", "Amhr2"), + + Receptors_TypeIII = c("Tgfbr3", "Eng"), + + SMAD_Regulated = c("Smad1", "Smad2", "Smad3", "Smad5", "Smad9"), + SMAD_Common = c("Smad4"), + SMAD_Inhibitory = c("Smad6", "Smad7"), + + # SARA is a protein name for ZFYVE9; only the gene symbol is used + SMAD_Anchors = c("Zfyve9"), + + Coactivators = c("Crebbp", "Ep300", "Ski", "Skil", "Cited1", "Cited2", + "Foxh1", "Foxo1", "Foxo3", "Runx1", "Runx2", "Runx3", + "Sp1", "Jun", "Fos", "Atf2"), + + Corepressors = c("Tgif1", "Tgif2", "Ski", "Skil", "Sin3a", "Ncor1", + "Ncor2", "Hdac1", "Hdac2", "Hdac3"), + + # RNF12 (human) = Rlim (mouse) — different symbol! + E3_Ligases = c("Smurf1", "Smurf2", "Nedd4l", "Wwp1", "Wwp2", + "Rlim", "Stub1", "Trim33"), + + Transcriptional_Targets = c( + "Serpine1", "Smad7", "Cdkn1a", "Cdkn2b", + "Myc", "Snai1", "Snai2", "Twist1", "Zeb1", "Zeb2", + "Vim", "Cdh1", "Cdh2", "Mmp2", "Mmp9", + "Col1a1", "Col1a2", "Col3a1", "Fn1", "Acta2", + "Ctgf", "Tgfb1", "Id1", "Id2", "Id3" + ), + + Secreted_Antagonists = c( + "Fst", "Fstl1", "Fstl3", "Chrd", "Chrdl1", "Chrdl2", + "Nog", "Grem1", "Grem2", "Nbl1", "Bambi", + "Ltbp1", "Ltbp2", "Ltbp3", "Ltbp4", "Thbs1", "Thbs2", + "Dcn", "Bgn", "Aspn" + ), + + MAPK_Pathway = c("Map3k7", "Tab1", "Tab2", "Tab3", + "Map2k3", "Map2k4", "Map2k6", "Map2k7", + "Mapk1", "Mapk3", "Mapk8", "Mapk9", "Mapk10", + "Mapk11", "Mapk12", "Mapk13", "Mapk14"), + + PI3K_AKT_Pathway = c("Pik3ca", "Pik3cb", "Pik3cd", "Pik3r1", "Pik3r2", + "Akt1", "Akt2", "Akt3", "Mtor", "Rheb"), + + RHO_Pathway = c("Rhoa", "Rac1", "Cdc42", "Rock1", "Rock2", + "Tgfbr1", "Pak1", "Pak2", "Limk1", "Limk2"), + + Latency_Activation = c("Ltbp1", "Ltbp2", "Ltbp3", "Ltbp4", + "Lrrc32", "Lrrc33", "Thbs1", "Itgav", "Itgb1", + "Itgb3", "Itgb5", "Itgb6", "Itgb8", "Mmp2", "Mmp9"), + + Phosphatases = c("Ppm1a", "Ppp1ca", "Ppp1cb", "Ppp1cc", "Mtmr4"), + + # IMPORTIN7 = Ipo7, IMPORTIN8 = Ipo8 in mouse + Nuclear_Transport = c("Ipo7", "Ipo8", "Xpo1", "Ran"), + + # TAZ = Wwtr1 (mouse), EVI1 = Mecom (mouse) + Other_Regulators = c("Daxx", "Fnta", "Fkbp1a", + "Yap1", "Wwtr1", "Pmepa1", "Trim33", + "Mecom", "Bcor", "Drap1", "Maml1", + "Ppp2ca", "Ppp2r1a", "Strap", "Cdkn1b", "Cdkn1c", + "Rbl1", "Rbl2", "E2f4", "E2f5", "Cops5") +) + +cat("Total unique mouse TGF-β genes:", length(unique(unlist(tgfb_genes_mouse))), "\n") +``` + +## Flatten to Data Frames + +Both lists are converted to flat two-column data frames (`gene`, `category`) for downstream joining operations. + +```{r flatten} +flatten_gene_list <- function(gene_list) { + do.call(rbind, lapply(names(gene_list), function(cat) { + data.frame(gene = gene_list[[cat]], category = cat, stringsAsFactors = FALSE) + })) +} + +tgfb_genes_human_flat <- flatten_gene_list(tgfb_genes_human) +tgfb_genes_mouse_flat <- flatten_gene_list(tgfb_genes_mouse) + +head(tgfb_genes_human_flat) +``` + +--- + +# Step 2: Bulk RNA-seq Differential Expression + +## Human — Lung Fibroblasts (GSE110021) + +Human WI-38 fibroblasts were treated with TGFβ1 and profiled at **Day 1** (acute response) and **Day 20** (chronic/fibrotic response). The dataset provides voom-normalized log-counts, so limma is applied directly without further normalization. + +```{r human-rnaseq, eval=FALSE} +library(limma) + +# Load voom-normalized expression matrix +data_fibroblasts <- read.table( + "GSE110021_counts.voom.annot.txt.gz", + header = TRUE, sep = "\t", row.names = 1 +) + +# Separate expression values from annotation columns +expr <- as.matrix(data_fibroblasts[, -(1:2)]) +rownames(expr) <- data_fibroblasts$GeneSymbol + +# Sample metadata: 24 samples total, 12 per treatment, 6 per timepoint per treatment +sample_info <- data.frame( + sample = colnames(expr), + treatment = rep(c("noTGFb", "TGFb"), each = 12), + timepoint = rep(c("D1", "D20"), each = 6, times = 2) +) + +# Design matrix with all four groups +design <- model.matrix(~ 0 + treatment:timepoint, data = sample_info) +colnames(design) <- c("D1_noTGFb", "D1_TGFb", "D20_noTGFb", "D20_TGFb") + +fit <- lmFit(expr, design) + +# Contrasts: TGFb vs. control at each timepoint +contrast_matrix <- makeContrasts( + D1_TGFb_vs_noTGFb = D1_TGFb - D1_noTGFb, + D20_TGFb_vs_noTGFb = D20_TGFb - D20_noTGFb, + levels = design +) + +fit2 <- contrasts.fit(fit, contrast_matrix) +fit2 <- eBayes(fit2) + +# Extract full results tables +res_D1 <- topTable(fit2, coef = "D1_TGFb_vs_noTGFb", number = Inf, sort.by = "p") +res_D20 <- topTable(fit2, coef = "D20_TGFb_vs_noTGFb", number = Inf, sort.by = "p") + +# Add gene descriptions +res_D1$Description <- data_fibroblasts$Description[match(rownames(res_D1), data_fibroblasts$GeneSymbol)] +res_D20$Description <- data_fibroblasts$Description[match(rownames(res_D20), data_fibroblasts$GeneSymbol)] + +write.csv(res_D1, "DEG_D1_TGFb_vs_noTGFb.csv", row.names = TRUE) +write.csv(res_D20, "DEG_D20_TGFb_vs_noTGFb.csv", row.names = TRUE) +``` + +## Mouse — T Cells (GSE246932) + +Mouse CD8+ T cells were treated with TGFβ for 2 hours. Raw count data required DESeq2 for normalization and differential testing. + +```{r mouse-rnaseq, eval=FALSE} +library(DESeq2) +library(dplyr) + +# Load raw counts +counts_data <- read.csv( + "GSE246932_220809-P490-1_RawGeneCounts.csv.gz", + header = TRUE, check.names = FALSE +) + +# Remove SIINFEKL peptide-treated samples (not relevant to TGFb comparison) +counts_data <- counts_data[, !grepl("SIINFEKL", colnames(counts_data))] + +# Separate gene annotation from count columns +gene_anno <- counts_data[, 1:4] +counts_only <- counts_data[, -(1:4)] + +# Collapse duplicate gene IDs by summing +counts_collapsed <- counts_only %>% + mutate(geneId = gene_anno$geneId) %>% + group_by(geneId) %>% + summarise(across(where(is.numeric), sum), .groups = "drop") + +counts_mat <- as.matrix(counts_collapsed[, -1]) +rownames(counts_mat) <- counts_collapsed$geneId + +# Build DESeq2 object +sample_names <- colnames(counts_mat) +coldata <- data.frame( + treatment = factor( + ifelse(grepl("TGFb", sample_names), "TGFb", "none"), + levels = c("none", "TGFb") + ), + row.names = sample_names +) + +dds <- DESeqDataSetFromMatrix( + countData = counts_mat, + colData = coldata, + design = ~ treatment +) +dds <- dds[rowSums(counts(dds)) > 10, ] # low-count filter +dds <- DESeq(dds) + +res <- results(dds, contrast = c("treatment", "TGFb", "none")) +res_df <- as.data.frame(res) + +# Map gene names back from annotation +res_df$geneId <- rownames(res_df) +res_df$geneName <- gene_anno$geneName[match(res_df$geneId, gene_anno$geneId)] +res_df$description <- gene_anno$description[match(res_df$geneId, gene_anno$geneId)] + +library(openxlsx) +write.xlsx(res_df, file = "Mus_TGFb_vs_none.xlsx", rowNames = FALSE) +``` + +--- + +# Step 3: Filter for TGF-β Pathway Genes + +DEG results are joined against the curated gene lists, retaining only TGF-β pathway members that reach statistical significance (adjusted *p* < 0.05). + +```{r filter, eval=FALSE} +library(readr) +library(readxl) +library(dplyr) + +human_d1 <- read_csv("DEG_D1_TGFb_vs_noTGFb.csv") +human_d20 <- read_csv("DEG_D20_TGFb_vs_noTGFb.csv") +mouse_df <- read_excel("Mus_TGFb_vs_none.xlsx") + +# Human Day 1 +human_d1_results <- human_d1 %>% + filter(ID %in% tgfb_genes_human_flat$gene) %>% + left_join(tgfb_genes_human_flat, by = c("ID" = "gene")) %>% + filter(!is.na(adj.P.Val) & adj.P.Val < 0.05) %>% + arrange(adj.P.Val) + +# Human Day 20 +human_d20_results <- human_d20 %>% + filter(ID %in% tgfb_genes_human_flat$gene) %>% + left_join(tgfb_genes_human_flat, by = c("ID" = "gene")) %>% + filter(!is.na(adj.P.Val) & adj.P.Val < 0.05) %>% + arrange(adj.P.Val) + +# Mouse +mouse_df_results <- mouse_df %>% + filter(geneName %in% tgfb_genes_mouse_flat$gene) %>% + left_join(tgfb_genes_mouse_flat, by = c("geneName" = "gene")) %>% + filter(!is.na(padj) & padj < 0.05) %>% + arrange(padj) + +cat("Human D1 pathway genes (padj<0.05):", nrow(human_d1_results), "\n") +cat("Human D20 pathway genes (padj<0.05):", nrow(human_d20_results), "\n") +cat("Mouse pathway genes (padj<0.05):", nrow(mouse_df_results), "\n") +``` + +--- + +# Step 4: Assign Activity Coefficients + +## Rationale + +Each gene receives a **direction coefficient** reflecting its behavior under TGFβ activation: + +| Coefficient | Meaning | +|:-----------:|---------| +| **+1** | Upregulated with TGFβ — consistent with pathway activation | +| **−1** | Downregulated with TGFβ — consistent with pathway inhibition | + +These coefficients are used by `PathwayEmbed` to compute a **signed pathway activity score**: the weighted sum of a sample's expression values multiplied by their coefficients, giving a single number that reflects the net direction and magnitude of TGF-β activity. + +The function also supports inhibitor experiments via `TGFB_activation = FALSE`, which flips the sign logic — a gene downregulated by an inhibitor is inferred to be positively regulated under activation. + +```{r coef-function} +assign_coefficient_tgfb <- function(log2FoldChange, + fc_threshold = 0, + TGFB_activation = TRUE) { + if (is.na(log2FoldChange)) return(0) + + if (TGFB_activation) { + if (log2FoldChange > fc_threshold) return( 1) + else if (log2FoldChange < -fc_threshold) return(-1) + else return( 0) + } else { + # Inhibitor data: flip direction + if (log2FoldChange < -fc_threshold) return( 1) + else if (log2FoldChange > fc_threshold) return(-1) + else return( 0) + } +} +``` + +> **Threshold note:** `fc_threshold = 0` assigns a coefficient to any non-zero fold-change. For stricter databases, use `fc_threshold = 0.5` to restrict to genes with |log₂FC| ≥ 0.5, focusing on more robust responses. + +```{r apply-coef, eval=FALSE} +human_d1_results <- human_d1_results %>% + mutate(coef = sapply(logFC, assign_coefficient_tgfb, fc_threshold = 0)) + +human_d20_results <- human_d20_results %>% + mutate(coef = sapply(logFC, assign_coefficient_tgfb, fc_threshold = 0)) + +mouse_df_results <- mouse_df_results %>% + mutate(coef = sapply(log2FoldChange, assign_coefficient_tgfb, fc_threshold = 0)) +``` + +--- + +# Step 5: Export to Excel + +The final database is exported as a formatted `.xlsx` workbook with a styled header row, frozen pane, and auto-sized columns. + +```{r export, eval=FALSE} +library(openxlsx) + +# --- Helper: prepare one sheet's data frame --- +prepare_sheet <- function(results, gene_col, logfc_col) { + results %>% + dplyr::select( + Gene_Symbol = !!sym(gene_col), + Category = category, + Coefficient = coef, + log2FoldChange = !!sym(logfc_col) + ) %>% + as.data.frame() +} + +human_d1_sheet <- prepare_sheet(human_d1_results, "ID", "logFC") +human_d20_sheet <- prepare_sheet(human_d20_results, "ID", "logFC") +mouse_df_sheet <- prepare_sheet(mouse_df_results, "geneName", "log2FoldChange") + +# --- Helper: write one formatted sheet --- +add_pathway_sheet <- function(wb, sheet_name, df) { + + addWorksheet(wb, sheet_name) + + writeData(wb, sheet_name, df, + headerStyle = createStyle( + fontSize = 11, fontColour = "#FFFFFF", halign = "center", + fgFill = "#4472C4", border = "TopBottom", + fontName = "Arial", textDecoration = "bold" + ) + ) + + freezePane(wb, sheet_name, firstRow = TRUE) + tryCatch( + setColWidths(wb, sheet_name, cols = seq_len(ncol(df)), widths = "auto"), + error = function(e) + setColWidths(wb, sheet_name, cols = seq_len(ncol(df)), widths = 15) + ) +} + +# --- Build workbook --- +wb <- createWorkbook() +add_pathway_sheet(wb, "TGFB_Human_D1", human_d1_sheet) +add_pathway_sheet(wb, "TGFB_Human_D20", human_d20_sheet) +add_pathway_sheet(wb, "TGFB_Mouse", mouse_df_sheet) + +saveWorkbook(wb, "TGFB_Pathway_Database.xlsx", overwrite = TRUE) +cat("Saved: TGFB_Pathway_Database.xlsx\n") +``` + +--- + +# Final Database Structure + +Each sheet in `TGFB_Pathway_Database.xlsx` contains: + +| Column | Description | +|--------|-------------| +| `Gene_Symbol` | HGNC (human) or MGI (mouse) gene symbol | +| `Category` | Functional category from KEGG + curation | +| `Coefficient` | +1 (activated) or −1 (repressed) under TGFβ; filtered by padj < 0.05 | +| `log2FoldChange` | Log₂ fold-change from the corresponding DEG analysis | + +Sheets produced: + +| Sheet | Species | Context | Method | +|-------|---------|---------|--------| +| `TGFB_Human_D1` | Human | Lung fibroblasts, Day 1 | limma / voom | +| `TGFB_Human_D20` | Human | Lung fibroblasts, Day 20 | limma / voom | +| `TGFB_Mouse` | Mouse | CD8+ T cells, 2h | DESeq2 | + +--- + +# Important Curation Notes + +The following caveats should be kept in mind when extending or modifying the database: + +**Genes excluded from the mouse list due to no ortholog:** +`INHBC`, `INHBE` — these activin subunits are primate-specific and have no mouse ortholog. + +**Gene name ambiguities resolved:** +`SARA` is a protein alias for the gene `ZFYVE9` and should not be used as a gene symbol. `ELF` is ambiguous (could refer to `ELF1` through `ELF5`) and was removed from the mouse list. + +**Genes with completely different human/mouse symbols:** + +| Human | Mouse | Category | +|-------|-------|----------| +| RNF12 | Rlim | E3_Ligases | +| IMPORTIN7 | Ipo7 | Nuclear_Transport | +| IMPORTIN8 | Ipo8 | Nuclear_Transport | +| TAZ (WWTR1) | Wwtr1 | Other_Regulators | +| EVI1 (MECOM) | Mecom | Other_Regulators | + +Always verify mouse gene symbols against [MGI](http://www.informatics.jax.org/) before adding new genes. + +--- + +# Session Information + +```{r session-info} +sessionInfo() +``` diff --git a/vignettes/beta_catenin_ko.Rmd b/vignettes/beta_catenin_ko.Rmd deleted file mode 100644 index 865a162..0000000 --- a/vignettes/beta_catenin_ko.Rmd +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: "Beta-Catenin Knockout Analysis with PathwayEmbed" -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{Beta-Catenin Knockout Analysis} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - - -```{r, include = FALSE} -knitr::opts_chunk$set( - collapse = TRUE, - comment = "#>" -) -``` - - -## Load Packages and Download Data from Online Source -```{r setup} -library(PathwayEmbed) -library(Seurat) - -url_ko <- "https://ftp.ncbi.nlm.nih.gov/geo/series/GSE233nnn/GSE233978/suppl/GSE233978_KO_filtered_feature_bc_matrix.h5" -url_wt <- "https://ftp.ncbi.nlm.nih.gov/geo/series/GSE233nnn/GSE233978/suppl/GSE233978_WT_filtered_feature_bc_matrix.h5" - - -download.file(url_ko, destfile = "GSE233978_KO_filtered_feature_bc_matrix.h5", mode = "wb") -download.file(url_wt, destfile = "GSE233978_WT_filtered_feature_bc_matrix.h5", mode = "wb") -``` - -## Data Preparation -```{r} -# Load KO and WT expression matrices from local HDF5 files -ko_data <- Read10X_h5("GSE233978_KO_filtered_feature_bc_matrix.h5") -wt_data <- Read10X_h5("GSE233978_WT_filtered_feature_bc_matrix.h5") - -# Create Seurat objects -# Apply during object creation -ko <- CreateSeuratObject(counts = ko_data, project = "KO", min.cells = 3, min.features = 200) -wt <- CreateSeuratObject(counts = wt_data, project = "WT", min.cells = 3, min.features = 200) - - -# Add sample metadata -ko$sample <- "KO" -wt$sample <- "WT" - -# Merge and join layers -merged <- merge(ko, wt) -merged[["RNA"]] <- JoinLayers(merged[["RNA"]]) -``` - -## Preprocessing -Get normalized and scaled data -```{r} -# Normalize and scale -merged <- NormalizeData( - object = merged, - normalization.method = "LogNormalize", - scale.factor = 10000 -) - -merged <- FindVariableFeatures( - object = merged, - selection.method = "vst", - nfeatures = 2000 -) - -merged <- ScaleData( - object = merged, - features = VariableFeatures(object = merged) -) -``` - -## Wnt Pathway Scoring and Visualization Using Pathway Embed -```{r} -# Compute Wnt pathway score -wnt_scores <- ComputeCellData(merged, "Wnt", distance.method = "manhattan", batch.size = 1000) - -# Prepare for plotting -plot_data <- PreparePlotData(merged, wnt_scores, group = "sample") - -# Plot -PlotPathway(plot_data, pathway = "Wnt", group = "sample", c("#f4a4a4", "#6baed6")) - -# Show percentage of high-scoring cells (optional) -CalculatePercentage(plot_data, "sample") -``` diff --git a/vignettes/beta_catenin_ko_updated.Rmd b/vignettes/beta_catenin_ko_updated.Rmd new file mode 100644 index 0000000..64706fc --- /dev/null +++ b/vignettes/beta_catenin_ko_updated.Rmd @@ -0,0 +1,349 @@ +--- +title: "Beta-Catenin Knockout Analysis with PathwayEmbed" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Beta-Catenin Knockout Analysis} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + warning = FALSE, + message = FALSE, + comment = "#>", + dpi = 300, + fig.width = 4, + fig.height = 3, + dev = "png" +) +``` + +## Overview +This vignette demonstrates the application of PathwayEmbed in a beta-catenin +perturbed system where the *Ctnnb1* upstream enhancer is depleted in intestinal +epithelia. Because the KO genotype is known by design, this dataset provides a +clean biological ground truth for a direct AUROC benchmark against PROGENy and +AddModuleScore. + +Reference: Hua et al., *eLife* 13: RP98238 (2024). + + +--- + +## Load Packages + +```{r load} +library(PathwayEmbed) +library(Seurat) +library(ggplot2) +library(patchwork) +library(pheatmap) +library(progeny) +library(pROC) +``` + +--- + +## Helper: Annotation Label Builder + +```{r helper} +make_label <- function(stats, group1, group2) { + d <- round(stats$cohens_d[1], 3) + p <- formatC(stats$p_value[1], format = "e", digits = 2) + on1 <- stats$percentage_on[stats$group == group1] + off1 <- stats$percentage_off[stats$group == group1] + on2 <- stats$percentage_on[stats$group == group2] + off2 <- stats$percentage_off[stats$group == group2] + paste0( + group1, ": ON=", on1, "%, OFF=", off1, "%\n", + group2, ": ON=", on2, "%, OFF=", off2, "%\n", + "Cohen's d = ", d, "\n", + "p = ", p + ) +} +``` + +--- + +## Download Data + +```{r download, eval=FALSE} +url_ko <- "https://ftp.ncbi.nlm.nih.gov/geo/series/GSE233nnn/GSE233978/suppl/GSE233978_KO_filtered_feature_bc_matrix.h5" +url_wt <- "https://ftp.ncbi.nlm.nih.gov/geo/series/GSE233nnn/GSE233978/suppl/GSE233978_WT_filtered_feature_bc_matrix.h5" + +download.file(url_ko, destfile = "GSE233978_KO_filtered_feature_bc_matrix.h5", mode = "wb") +download.file(url_wt, destfile = "GSE233978_WT_filtered_feature_bc_matrix.h5", mode = "wb") +``` + +--- + +## Data Preparation and Preprocessing + +```{r prepare} +ko_data <- Read10X_h5("GSE233978_KO_filtered_feature_bc_matrix.h5") +wt_data <- Read10X_h5("GSE233978_WT_filtered_feature_bc_matrix.h5") + +ko <- CreateSeuratObject(counts = ko_data, project = "KO", + min.cells = 3, min.features = 200) +wt <- CreateSeuratObject(counts = wt_data, project = "WT", + min.cells = 3, min.features = 200) +ko$sample <- "KO" +wt$sample <- "WT" + +merged <- merge(ko, wt) +merged[["RNA"]] <- JoinLayers(merged[["RNA"]]) + +merged <- NormalizeData(merged, normalization.method = "LogNormalize", + scale.factor = 10000) +merged <- FindVariableFeatures(merged, selection.method = "vst", + nfeatures = 2000) +merged <- ScaleData(merged, features = VariableFeatures(merged)) +``` + +--- + +## Wnt Pathway Scoring + +```{r scoring} +Wnt_12h <- LoadPathway("WNT3A_12H_ACTIVATION", "mouse") +Wnt_24h <- LoadPathway("WNT3A_24H_ACTIVATION", "mouse") +Wnt_48h <- LoadPathway("WNT3A_48H_ACTIVATION", "mouse") +Wnt_slope <- LoadPathway("WNT3A_SLOPE_ACTIVATION", "mouse") + +matrix_12h <- DataPreProcess(merged, Wnt_12h, Seurat.object = TRUE) +matrix_24h <- DataPreProcess(merged, Wnt_24h, Seurat.object = TRUE) +matrix_48h <- DataPreProcess(merged, Wnt_48h, Seurat.object = TRUE) +matrix_slope <- DataPreProcess(merged, Wnt_slope, Seurat.object = TRUE) + +pathwaystat_12h <- PathwayMaxMin(matrix_12h, Wnt_12h) +pathwaystat_24h <- PathwayMaxMin(matrix_24h, Wnt_24h) +pathwaystat_48h <- PathwayMaxMin(matrix_48h, Wnt_48h) +pathwaystat_slope <- PathwayMaxMin(matrix_slope, Wnt_slope) + +score_12h <- ComputeCellData(matrix_12h, pathwaystat_12h) +score_24h <- ComputeCellData(matrix_24h, pathwaystat_24h) +score_48h <- ComputeCellData(matrix_48h, pathwaystat_48h) +score_slope <- ComputeCellData(matrix_slope, pathwaystat_slope) +``` + +--- + +## Visualization + +```{r visualization} +plot_data_12h <- PreparePlotData(merged, score_12h, "sample", Seurat.object = TRUE) +plot_data_24h <- PreparePlotData(merged, score_24h, "sample", Seurat.object = TRUE) +plot_data_48h <- PreparePlotData(merged, score_48h, "sample", Seurat.object = TRUE) +plot_data_slope <- PreparePlotData(merged, score_slope, "sample", Seurat.object = TRUE) + +pct_12h <- CalculatePercentage(plot_data_12h, "sample") +pct_24h <- CalculatePercentage(plot_data_24h, "sample") +pct_48h <- CalculatePercentage(plot_data_48h, "sample") +pct_slope <- CalculatePercentage(plot_data_slope, "sample") + +pct_12h; pct_24h; pct_48h; pct_slope + +p_12h <- PlotPathway(plot_data_12h, "Wnt 12h", "sample", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_12h, "KO", "WT"), size = 3.5, color = "black") + +p_24h <- PlotPathway(plot_data_24h, "Wnt 24h", "sample", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_24h, "KO", "WT"), size = 3.5, color = "black") + +p_48h <- PlotPathway(plot_data_48h, "Wnt 48h", "sample", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_48h, "KO", "WT"), size = 3.5, color = "black") + +p_slope <- PlotPathway(plot_data_slope, "Wnt (slope)", "sample", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_slope, "KO", "WT"), size = 3.5, color = "black") + +p_12h; p_24h; p_48h; p_slope +``` + +--- + +## Technical Confounders + +```{r confounders} +merged[["percent.mt"]] <- PercentageFeatureSet(merged, pattern = "^mt-") +seurat_meta <- merged@meta.data + +make_scatter <- function(df, x_col, x_label) { + r <- cor(df$embed_score, df[[x_col]], method = "spearman", use = "complete.obs") + ggplot(df, aes(x = .data[[x_col]], y = embed_score)) + + geom_point(alpha = 0.3, size = 0.8, color = "#534AB7") + + geom_smooth(method = "lm", color = "#E24B4A", linewidth = 0.8, se = TRUE) + + labs(title = sprintf("%s (rho = %.3f)", x_label, r), + x = x_label, y = "PathwayEmbed score") + + theme_minimal() +} + +confounder_df <- data.frame( + cell = names(score_slope), + embed_score = as.numeric(score_slope), + nCount_RNA = seurat_meta[names(score_slope), "nCount_RNA"], + nFeature_RNA = seurat_meta[names(score_slope), "nFeature_RNA"], + percent_mt = seurat_meta[names(score_slope), "percent.mt"] +) + +for (cov in c("nCount_RNA", "nFeature_RNA", "percent_mt")) { + r <- cor(confounder_df$embed_score, confounder_df[[cov]], + method = "spearman", use = "complete.obs") + cat(sprintf("Spearman vs %-15s : %.3f\n", cov, r)) +} + +(make_scatter(confounder_df, "nCount_RNA", "nCount_RNA") + + make_scatter(confounder_df, "nFeature_RNA", "nFeature_RNA") + + make_scatter(confounder_df, "percent_mt", "percent.mt")) +``` + +--- + +## Benchmark Against PROGENy and AddModuleScore + +```{r benchmark} +normalized_mat <- GetAssayData(merged, assay = "RNA", layer = "data") +normalized_mat_dense <- as.matrix(normalized_mat) + +common_genes <- intersect(rownames(normalized_mat_dense), Wnt_slope$Gene_Symbol) +gene_matrix <- normalized_mat_dense[common_genes, ] +mean_expr <- colMeans(gene_matrix, na.rm = TRUE) +zscore_mean_per_cell <- colMeans(t(scale(t(gene_matrix))), na.rm = TRUE) + +progeny_scores <- progeny( + normalized_mat_dense, + scale = TRUE, + organism = "Mouse", + top = 100, + perm = 1 +) +progeny_wnt <- setNames(as.numeric(progeny_scores[, "WNT"]), + rownames(progeny_scores)) + +wnt_features <- rownames(matrix_slope) +merged <- AddModuleScore( + object = merged, + features = list(wnt_features), + name = "WNT_ModuleScore", + ctrl = 5, + nbin = 10 +) +module_score <- setNames( + merged@meta.data$WNT_ModuleScore1, + rownames(merged@meta.data) +) + +cells <- names(score_slope) +benchmark_df <- data.frame( + PathwayEmbed = as.numeric(score_slope), + PROGENy = as.numeric(progeny_wnt[cells]), + AddModuleScore = as.numeric(module_score[cells]), + mean_expr = as.numeric(mean_expr[cells]), + zscore_expr = as.numeric(zscore_mean_per_cell[cells]), + row.names = cells +) + +benchmark_cor <- cor(benchmark_df, method = "spearman", + use = "pairwise.complete.obs") +print(round(benchmark_cor, 3)) + +p_cor <- pheatmap( + benchmark_cor, + color = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100), + breaks = seq(-1, 1, length.out = 101), + display_numbers = TRUE, number_format = "%.2f", + fontsize_number = 9, + main = "Method Benchmark — Spearman Correlation (Ctnnb1 KO dataset)" +) +p_cor + +ko_label <- ifelse(merged@meta.data[cells, "sample"] == "KO", 1L, 0L) + +compute_auroc <- function(scores, labels) { + r <- roc(labels, scores, quiet = TRUE) + auc_val <- as.numeric(auc(r)) + if (auc_val < 0.5) auc_val <- 1 - auc_val + auc_val +} + +auroc_results <- data.frame( + Method = colnames(benchmark_df), + AUROC = sapply(benchmark_df, compute_auroc, labels = ko_label) +) +auroc_results <- auroc_results[order(-auroc_results$AUROC), ] +print(auroc_results) + +compute_cohens_d_method <- function(scores_vec, seurat_obj, group_col) { + pd <- PreparePlotData(seurat_obj, scores_vec, group_col, Seurat.object = TRUE) + pct <- CalculatePercentage(pd, group_var = group_col) + abs(pct$cohens_d[1]) +} + +cohens_d_results <- data.frame( + Method = colnames(benchmark_df), + Cohens_d = sapply( + colnames(benchmark_df), + function(m) { + sv <- setNames(benchmark_df[[m]], rownames(benchmark_df)) + compute_cohens_d_method(sv, merged, "sample") + } + ) +) +cohens_d_results <- cohens_d_results[order(-cohens_d_results$Cohens_d), ] +print(cohens_d_results) + +method_colors <- c( + "PathwayEmbed" = "#534AB7", + "PROGENy" = "#E24B4A", + "AddModuleScore" = "#EF9F27", + "mean_expr" = "#888780", + "zscore_expr" = "#B4B2A9" +) + +p_cd <- ggplot(cohens_d_results, + aes(x = reorder(Method, Cohens_d), y = Cohens_d, fill = Method)) + + geom_bar(stat = "identity", width = 0.6) + + coord_flip() + + scale_fill_manual(values = method_colors) + + labs(title = "Effect size (Cohen's d): KO vs. WT", + x = NULL, y = "Cohen's d (absolute)") + + theme_classic() + + theme(legend.position = "none") +p_cd + +p_auroc <- ggplot(auroc_results, + aes(x = reorder(Method, AUROC), y = AUROC, fill = Method)) + + geom_bar(stat = "identity", width = 0.6) + + geom_hline(yintercept = 0.5, linetype = "dashed", color = "black") + + coord_flip() + + scale_fill_manual(values = method_colors) + + labs(title = "AUROC: KO vs. WT separation (Ctnnb1 KO dataset)", + x = NULL, y = "AUROC") + + ylim(0, 1) + + theme_classic() + + theme(legend.position = "none") +p_auroc + +roc_list <- lapply(colnames(benchmark_df), function(m) { + roc(ko_label, benchmark_df[[m]], quiet = TRUE) +}) +names(roc_list) <- colnames(benchmark_df) + +roc_df <- do.call(rbind, lapply(names(roc_list), function(m) { + r <- roc_list[[m]] + data.frame(Method = m, FPR = 1 - r$specificities, TPR = r$sensitivities) +})) + +p_roc <- ggplot(roc_df, aes(x = FPR, y = TPR, color = Method)) + + geom_line(linewidth = 0.9) + + geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "grey60") + + scale_color_manual(values = method_colors) + + labs(title = "ROC curves: KO vs. WT (Ctnnb1 KO dataset)", + x = "False positive rate", y = "True positive rate") + + theme_classic() +p_roc +``` diff --git a/vignettes/examples.Rmd b/vignettes/examples.Rmd deleted file mode 100644 index c906b4b..0000000 --- a/vignettes/examples.Rmd +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: "Toy Set" -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{Toy Set} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r, include = FALSE} -knitr::opts_chunk$set( - collapse = TRUE, - comment = "#>" -) -``` - -## Overview -This vignette demonstrates how to use the PathwayEmbed package to compute and visualize pathway activation using single-cell transcriptomic data. We use the example dataset fake_test_object included with the package. - -## Load Package and Example Data -```{r setup} -library(PathwayEmbed) -# Load the example Seurat object included in the package -data(fake_test_object) -``` - -## Compute Pathway Activation -```{r} -# Calculate pathway activation using MDS -# Default batch.size is set to 1000 -mds_results <- ComputeCellData( - fake_test_object, - pathway = "Wnt", - distance.method = "manhattan" -) -``` - -## Prepare Data for Plotting -```{r} -# Format MDS results and metadata for plotting -plot_data <- PreparePlotData( - fake_test_object, - mds_results, - group = "genotype" -) -``` - -## Visualize Pathway Activation -```{r} -# Visualize 2D MDS embedding colored by genotype -PlotPathway( - to.plot = plot_data, - pathway = "Wnt", - group = "genotype", - color = c("#ae282c", "#2066a8") -) -``` - -## Calculate Group-wise Activation Percentage (Optional) -```{r} -# Calculate % of cells per group with high pathway activation -CalculatePercentage( - to.plot = plot_data, - group_var = "genotype" -) -``` - ---- - diff --git a/vignettes/examples_updated.Rmd b/vignettes/examples_updated.Rmd new file mode 100644 index 0000000..f0b9391 --- /dev/null +++ b/vignettes/examples_updated.Rmd @@ -0,0 +1,753 @@ +--- +title: "Toy Set" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Toy Set} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + warning = FALSE, + message = FALSE, + comment = "#>", + dpi = 300, + fig.width = 8, + fig.height = 6, + dev = "png" +) +``` + +## Overview + +This vignette demonstrates how to use the PathwayEmbed package to compute and visualize pathway activation using single-cell transcriptomic data. We use the example dataset `synthetic_test_object_100` included with the package. + +------------------------------------------------------------------------ + +## Load Packages and Data + +```{r load} +library(PathwayEmbed) +library(Seurat) +library(dplyr) +library(tidyr) +library(ggplot2) +library(ggridges) +library(patchwork) +library(pheatmap) +library(progeny) +library(pROC) + +data("synthetic_test_object_100") +data("synthetic_test_metadata") +``` + +------------------------------------------------------------------------ + +## Helper: Annotation Label Builder + +```{r helper} +make_label <- function(stats, group1, group2) { + d <- round(stats$cohens_d[1], 3) + p <- formatC(stats$p_value[1], format = "e", digits = 2) + on1 <- stats$percentage_on[stats$group == group1] + off1 <- stats$percentage_off[stats$group == group1] + on2 <- stats$percentage_on[stats$group == group2] + off2 <- stats$percentage_off[stats$group == group2] + paste0( + group1, ": ON=", on1, "%, OFF=", off1, "%\n", + group2, ": ON=", on2, "%, OFF=", off2, "%\n", + "Cohen's d = ", d, "\n", + "p = ", p + ) +} +``` + +------------------------------------------------------------------------ + +## Load Pathway Databases + +```{r pathways} +ListPathway() +ListPathway("Pathway") +ListPathway("WNT") + +Wnt_12h <- LoadPathway("WNT3A_12H_ACTIVATION", "mouse") +Wnt_24h <- LoadPathway("WNT3A_24H_ACTIVATION", "mouse") +Wnt_48h <- LoadPathway("WNT3A_48H_ACTIVATION", "mouse") +Wnt_slope <- LoadPathway("WNT3A_SLOPE_ACTIVATION", "mouse") +``` + +------------------------------------------------------------------------ + +## Preprocessing and Pathway Reference States + +```{r preprocess} +matrix_12h <- DataPreProcess(synthetic_test_object_100, Wnt_12h, Seurat.object = TRUE) +matrix_24h <- DataPreProcess(synthetic_test_object_100, Wnt_24h, Seurat.object = TRUE) +matrix_48h <- DataPreProcess(synthetic_test_object_100, Wnt_48h, Seurat.object = TRUE) +matrix_slope <- DataPreProcess(synthetic_test_object_100, Wnt_slope, Seurat.object = TRUE) + +pathwaystat_12h <- PathwayMaxMin(matrix_12h, Wnt_12h) +pathwaystat_24h <- PathwayMaxMin(matrix_24h, Wnt_24h) +pathwaystat_48h <- PathwayMaxMin(matrix_48h, Wnt_48h) +pathwaystat_slope <- PathwayMaxMin(matrix_slope, Wnt_slope) +``` + +------------------------------------------------------------------------ + +## Compute Pathway Scores + +```{r scores} +score_12h <- ComputeCellData(matrix_12h, pathwaystat_12h) +score_24h <- ComputeCellData(matrix_24h, pathwaystat_24h) +score_48h <- ComputeCellData(matrix_48h, pathwaystat_48h) +score_slope <- ComputeCellData(matrix_slope, pathwaystat_slope) +``` + +------------------------------------------------------------------------ + +## Prepare Plot Data and Calculate Group Statistics + +```{r plotdata} +plot_data_12h <- PreparePlotData(synthetic_test_metadata, score_12h, group = "genotype") +plot_data_24h <- PreparePlotData(synthetic_test_metadata, score_24h, group = "genotype") +plot_data_48h <- PreparePlotData(synthetic_test_metadata, score_48h, group = "genotype") +plot_data_slope <- PreparePlotData(synthetic_test_metadata, score_slope, group = "genotype") + +pct_12h <- CalculatePercentage(to.plot = plot_data_12h, group_var = "genotype") +pct_24h <- CalculatePercentage(to.plot = plot_data_24h, group_var = "genotype") +pct_48h <- CalculatePercentage(to.plot = plot_data_48h, group_var = "genotype") +pct_slope <- CalculatePercentage(to.plot = plot_data_slope, group_var = "genotype") + +pct_12h; pct_24h; pct_48h; pct_slope +``` + +------------------------------------------------------------------------ + +## Visualization 1 — Density Plots + +```{r density-plots} +p1 <- PlotPathway(plot_data_12h, "12hr Wnt", "genotype", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_12h, "WT", "Mutant"), size = 3.5, color = "black") + +p2 <- PlotPathway(plot_data_24h, "24hr Wnt", "genotype", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_24h, "WT", "Mutant"), size = 3.5, color = "black") + +p3 <- PlotPathway(plot_data_48h, "48hr Wnt", "genotype", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_48h, "WT", "Mutant"), size = 3.5, color = "black") + +p4 <- PlotPathway(plot_data_slope, "Wnt (slope)", "genotype", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_slope, "WT", "Mutant"), size = 3.5, color = "black") + +p1; p2; p3; p4 +``` + +------------------------------------------------------------------------ + +## Visualization 2 — Violin + Jitter Plot + +```{r violin} +p5 <- ggplot(plot_data_12h, + aes(x = genotype, y = scale, fill = genotype, color = genotype)) + + geom_violin(alpha = 0.5, trim = FALSE) + + geom_jitter(width = 0.15, size = 0.6, alpha = 0.3) + + geom_hline(yintercept = 0, linetype = "dotted", color = "black", linewidth = 0.5) + + scale_fill_manual(values = c("#ae282c", "#2066a8")) + + scale_color_manual(values = c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_12h, "WT", "Mutant"), size = 3.5, color = "black") + + labs(title = "12hr WNT Pathway Activation", + x = NULL, y = "Relative Transduction State (z-score)") + + theme_classic() + + theme(legend.position = "none") +p5 +``` + +------------------------------------------------------------------------ + +## Visualization 3 — Waterfall Plot + +```{r waterfall} +waterfall_data <- plot_data_12h %>% + group_by(genotype) %>% + arrange(scale, .by_group = TRUE) %>% + mutate(rank = row_number(), + state = ifelse(scale >= 0, "ON", "OFF")) %>% + ungroup() + +annotation_df <- pct_12h %>% + mutate( + label = paste0("Cohen's d = ", round(cohens_d, 3), "\n", + "p = ", formatC(p_value, format = "e", digits = 2), "\n", + "ON = ", percentage_on, "%\n", + "OFF = ", percentage_off, "%"), + genotype = group + ) + +p6 <- ggplot(waterfall_data, aes(x = rank, y = scale, fill = state)) + + geom_bar(stat = "identity", width = 1) + + facet_wrap(~ genotype, scales = "free_x") + + scale_fill_manual(values = c("ON" = "#ae282c", "OFF" = "#2066a8")) + + geom_hline(yintercept = 0, color = "black", linewidth = 0.4) + + geom_text(data = annotation_df, + aes(x = Inf, y = Inf, label = label), + hjust = 1.1, vjust = 1.5, size = 3, color = "black", + inherit.aes = FALSE) + + labs(title = "Waterfall Plot of Cell Activation", + x = "Cells (ranked by activation)", + y = "Relative Transduction State (z-score)", + fill = "State") + + theme_classic() + + theme(axis.text.x = element_blank(), axis.ticks.x = element_blank(), + strip.background = element_rect(fill = "grey90", color = NA)) +p6 +``` + +------------------------------------------------------------------------ + +## Customize Pathway Input + +```{r self-defined pathway} +# Customize the wnt pathway using coefficients defined by us +Wnt.molecules <- c('Lgr5','Rnf43','Lrp5', + 'Lrp6','Fzd6','Ctnnb1', + 'Gsk3b','Ccnd1','Axin2', + 'Myc','Lef1','Tcf7', + 'Tcf7l1','Tcf7l2','Tle1', + 'Apc','Csnk1a1','Dvl1') +Wnt.cof <- c(1,1,-1,-1,-1,-1, 1,1,1, 1,1,1, 1,1,1, -1,-1,-1) +Wnt_df <- data.frame( + Gene_Symbol = Wnt.molecules, + Coefficient = Wnt.cof) + +print(Wnt_df) + +# Calculate score using customized pathway data +matrix_df <- DataPreProcess(synthetic_test_object_100, Wnt_df, Seurat.object = TRUE) +pathwaystat_df <- PathwayMaxMin(matrix_df, Wnt_df) +score_df <- ComputeCellData(matrix_df, pathwaystat_df) +plot_data_df <- PreparePlotData(synthetic_test_metadata, score_df, group = "genotype") +pct_df <- CalculatePercentage(to.plot = plot_data_df, group_var = "genotype") +PlotPathway(plot_data_df, "Customized Wnt", "genotype", c("#ae282c", "#2066a8")) + + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.5, + label = make_label(pct_df, "WT", "Mutant"), size = 3.5, color = "black") + + +``` + +## Null Distribution — Random Gene Sets + +```{r null-random} +set.seed(123) + +real_n_genes <- nrow(matrix_12h) +real_cohens_d <- pct_12h$cohens_d[1] +n_reps <- 20 + +# Sparse size grid covering the relevant range, always including real n +size_grid <- sort(unique(c( + seq(5, 50, by = 5), + seq(60, 200, by = 20), + real_n_genes +))) + +all_genes_pool <- rownames( + GetAssayData(synthetic_test_object_100, assay = "RNA", layer = "data") +) +size_grid <- size_grid[size_grid <= length(all_genes_pool)] + +cohens_d_random <- data.frame() + +for (i in size_grid) { + for (rep in seq_len(n_reps)) { + sampled_genes <- sample(all_genes_pool, i) + fake_pathway <- data.frame( + Gene_Symbol = sampled_genes, + Coefficient = sample(c(-1L, 1L), i, replace = TRUE) + ) + expr_matrix <- DataPreProcess(synthetic_test_object_100, fake_pathway, + Seurat.object = TRUE) + pathwaystat_rand <- PathwayMaxMin(expr_matrix, fake_pathway) + score_rand <- ComputeCellData(expr_matrix, pathwaystat_rand) + plot_data_rand <- PreparePlotData(synthetic_test_metadata, score_rand, + group = "genotype") + outcome_rand <- CalculatePercentage(plot_data_rand, group_var = "genotype") + + cohens_d_random <- rbind(cohens_d_random, data.frame( + n_genes = i, + rep = rep, + cohens_d = outcome_rand$cohens_d[1] + )) + } +} + +cohens_d_summary_rand <- cohens_d_random %>% + group_by(n_genes) %>% + summarise(mean_d = mean(cohens_d, na.rm = TRUE), + sd_d = sd(cohens_d, na.rm = TRUE), + .groups = "drop") + +null_at_real_n <- cohens_d_random %>% filter(n_genes == real_n_genes) +emp_p <- mean(abs(null_at_real_n$cohens_d) >= abs(real_cohens_d), na.rm = TRUE) + +cat("Real pathway Cohen's d: ", round(real_cohens_d, 3), "\n") +cat("Null mean at same n genes: ", round(mean(null_at_real_n$cohens_d, na.rm = TRUE), 3), "\n") +cat("Null SD at same n genes: ", round(sd(null_at_real_n$cohens_d, na.rm = TRUE), 3), "\n") +cat("Empirical p-value: ", round(emp_p, 3), "\n") + +p7 <- ggplot() + + geom_hline(yintercept = 0, linetype = "solid", color = "#888780", linewidth = 0.4) + + geom_hline(yintercept = 0.8, linetype = "dashed", color = "#E24B4A", linewidth = 0.5) + + geom_hline(yintercept = -0.8, linetype = "dashed", color = "#E24B4A", linewidth = 0.5) + + geom_hline(yintercept = 0.5, linetype = "dashed", color = "#EF9F27", linewidth = 0.5) + + geom_hline(yintercept = -0.5, linetype = "dashed", color = "#EF9F27", linewidth = 0.5) + + geom_point(data = cohens_d_random, + aes(x = n_genes, y = cohens_d), + color = "#534AB7", alpha = 0.25, size = 1.2) + + geom_ribbon(data = cohens_d_summary_rand, + aes(x = n_genes, ymin = mean_d - sd_d, ymax = mean_d + sd_d), + fill = "#534AB7", alpha = 0.15) + + geom_line(data = cohens_d_summary_rand, + aes(x = n_genes, y = mean_d), + color = "#534AB7", linewidth = 0.9) + + geom_point(aes(x = real_n_genes, y = real_cohens_d), + color = "#E24B4A", size = 3, shape = 18) + + geom_vline(xintercept = real_n_genes, color = "#E24B4A", + linetype = "dashed", linewidth = 0.5) + + annotate("text", x = real_n_genes, y = Inf, + label = paste0("Real pathway\nn = ", real_n_genes, + "\nd = ", round(real_cohens_d, 3), + "\nemp. p = ", round(emp_p, 3)), + hjust = -0.1, vjust = 1.5, size = 3, color = "#E24B4A") + + annotate("text", x = max(cohens_d_summary_rand$n_genes), y = 0.82, + label = "large (+0.8)", hjust = 1, size = 3, color = "#E24B4A") + + annotate("text", x = max(cohens_d_summary_rand$n_genes), y = -0.82, + label = "large (-0.8)", hjust = 1, size = 3, color = "#E24B4A") + + annotate("text", x = max(cohens_d_summary_rand$n_genes), y = 0.52, + label = "medium (+0.5)", hjust = 1, size = 3, color = "#EF9F27") + + annotate("text", x = max(cohens_d_summary_rand$n_genes), y = -0.52, + label = "medium (-0.5)", hjust = 1, size = 3, color = "#EF9F27") + + labs(title = "Null Distribution — Cohen's d by Gene Set Size", + x = "Number of genes", y = "Cohen's d") + + theme_minimal() +p7 +``` + +------------------------------------------------------------------------ + +## Null Distribution — Within Pathway Gene Pool + +```{r null-pathway-genes} +set.seed(123) + +all_genes <- rownames(matrix_12h) +n_genes <- length(all_genes) +n_reps <- 10 + +cohens_d_pathway <- data.frame() + +for (i in 2:n_genes) { + for (rep in seq_len(n_reps)) { + sampled_genes <- sample(all_genes, i) + expr_matrix <- matrix_12h[sampled_genes, , drop = FALSE] + pathwaystat_rand <- PathwayMaxMin(expr_matrix, Wnt_12h) + score_rand <- ComputeCellData(expr_matrix, pathwaystat_rand) + plot_data_rand <- PreparePlotData(synthetic_test_metadata, score_rand, + group = "genotype") + outcome_rand <- CalculatePercentage(to.plot = plot_data_rand, + group_var = "genotype") + cohens_d_pathway <- rbind(cohens_d_pathway, data.frame( + n_genes = i, + rep = rep, + cohens_d = outcome_rand$cohens_d[1] + )) + } +} + +cohens_d_summary_pw <- cohens_d_pathway %>% + group_by(n_genes) %>% + summarise(mean_d = mean(cohens_d, na.rm = TRUE), + sd_d = sd(cohens_d, na.rm = TRUE), + .groups = "drop") + +null_at_real_n_pw <- cohens_d_pathway %>% filter(n_genes == real_n_genes) +emp_p_pw <- mean(abs(null_at_real_n_pw$cohens_d) >= abs(real_cohens_d), na.rm = TRUE) + +cat("Real pathway Cohen's d: ", round(real_cohens_d, 3), "\n") +cat("Null mean at same n genes: ", round(mean(null_at_real_n_pw$cohens_d, na.rm = TRUE), 3), "\n") +cat("Null SD at same n genes: ", round(sd(null_at_real_n_pw$cohens_d, na.rm = TRUE), 3), "\n") +cat("Empirical p-value: ", round(emp_p_pw, 3), "\n") + +p_null <- ggplot() + + geom_hline(yintercept = 0, linetype = "solid", color = "#888780", linewidth = 0.4) + + geom_hline(yintercept = 0.8, linetype = "dashed", color = "#E24B4A", linewidth = 0.5) + + geom_hline(yintercept = -0.8, linetype = "dashed", color = "#E24B4A", linewidth = 0.5) + + geom_hline(yintercept = 0.5, linetype = "dashed", color = "#EF9F27", linewidth = 0.5) + + geom_hline(yintercept = -0.5, linetype = "dashed", color = "#EF9F27", linewidth = 0.5) + + geom_point(data = cohens_d_pathway, + aes(x = n_genes, y = cohens_d), + color = "#534AB7", alpha = 0.25, size = 1.2) + + geom_ribbon(data = cohens_d_summary_pw, + aes(x = n_genes, ymin = mean_d - sd_d, ymax = mean_d + sd_d), + fill = "#534AB7", alpha = 0.15) + + geom_line(data = cohens_d_summary_pw, + aes(x = n_genes, y = mean_d), + color = "#534AB7", linewidth = 0.9) + + geom_point(aes(x = real_n_genes, y = real_cohens_d), + color = "#E24B4A", size = 3, shape = 18) + + geom_vline(xintercept = real_n_genes, color = "#E24B4A", + linetype = "dashed", linewidth = 0.5) + + annotate("text", x = real_n_genes, y = Inf, + label = paste0("Real pathway\nn = ", real_n_genes, + "\nd = ", round(real_cohens_d, 3)), + hjust = -0.1, vjust = 1.5, size = 3, color = "#E24B4A") + + labs(title = "Null Distribution — Cohen's d by Gene Set Size (10 reps each)", + x = "Number of genes", y = "Cohen's d") + + theme_minimal() +p_null +``` + +------------------------------------------------------------------------ + +## Sensitivity Analysis 1 — Effect of Input Matrix Type + +```{r sensitivity-input} +data("synthetic_test_matrix_100") + +matrix_raw <- synthetic_test_matrix_100 +lib_size <- colSums(synthetic_test_matrix_100) +matrix_lognorm <- log1p(sweep(synthetic_test_matrix_100, 2, lib_size, "/") * 1e4) +matrix_norm <- sweep(synthetic_test_matrix_100, 2, lib_size, "/") * 1e4 +gene_var <- apply(matrix_lognorm, 1, var) +hvg_genes <- names(sort(gene_var, decreasing = TRUE))[ + 1:ceiling(nrow(matrix_lognorm) * 0.5)] +matrix_hvg <- matrix_lognorm[hvg_genes, ] + +run_pipeline <- function(expr_mat, pathwaydata, metadata, group, + scale.data = TRUE) { + mat <- DataPreProcess(expr_mat, pathwaydata, scale.data = scale.data) + pstat <- PathwayMaxMin(mat, pathwaydata) + score <- ComputeCellData(mat, pstat) + plotdata <- PreparePlotData(metadata, score, group = group) + outcome <- CalculatePercentage(plotdata, group_var = group) + list(score = score, plotdata = plotdata, outcome = outcome) +} + +result_raw <- run_pipeline(matrix_raw, Wnt_12h, synthetic_test_metadata, "genotype") +result_lognorm <- run_pipeline(matrix_lognorm, Wnt_12h, synthetic_test_metadata, "genotype") +result_norm <- run_pipeline(matrix_norm, Wnt_12h, synthetic_test_metadata, "genotype") +result_hvg <- run_pipeline(matrix_hvg, Wnt_12h, synthetic_test_metadata, "genotype") +result_raw_noscale <- run_pipeline(matrix_raw, Wnt_12h, synthetic_test_metadata, "genotype", scale.data = FALSE) +result_lognorm_noscale <- run_pipeline(matrix_lognorm, Wnt_12h, synthetic_test_metadata, "genotype", scale.data = FALSE) +result_norm_noscale <- run_pipeline(matrix_norm, Wnt_12h, synthetic_test_metadata, "genotype", scale.data = FALSE) +result_hvg_noscale <- run_pipeline(matrix_hvg, Wnt_12h, synthetic_test_metadata, "genotype", scale.data = FALSE) + +input_labels <- c("Raw", "Log-norm", "Norm", "HVG", + "Raw (noscale)", "Log-norm (noscale)", + "Norm (noscale)", "HVG (noscale)") +results_list <- list(result_raw, result_lognorm, result_norm, result_hvg, + result_raw_noscale, result_lognorm_noscale, + result_norm_noscale, result_hvg_noscale) + +cohens_d_input <- data.frame( + input_type = input_labels, + cohens_d = sapply(results_list, function(r) r$outcome$cohens_d[1]), + p_value = sapply(results_list, function(r) r$outcome$p_value[1]) +) +print(cohens_d_input) + +score_df_sens <- as.data.frame( + setNames(lapply(results_list, function(r) as.numeric(r$score)), input_labels), + row.names = names(results_list[[1]]$score) +) + +score_cor <- cor(score_df_sens, method = "spearman", use = "pairwise.complete.obs") +p12 <- pheatmap(score_cor, + color = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100), + breaks = seq(-1, 1, length.out = 101), + display_numbers = TRUE, number_format = "%.2f", + fontsize_number = 9, + main = "Score Correlation Across Input Matrix Types — Spearman") + +named_results <- list(Raw = result_raw, `Log-norm` = result_lognorm, + Norm = result_norm, HVG = result_hvg) +density_plots <- lapply( + names(named_results), + function(nm) PlotPathway(named_results[[nm]]$plotdata, + paste("Wnt 12h —", nm), "genotype", + c("#ae282c", "#2066a8")) +) +p13 <- wrap_plots(density_plots, ncol = 2) + + plot_annotation(title = "Pathway Activation by Input Matrix Type") + +p12; p13 +``` + +------------------------------------------------------------------------ + +## Correlation with Technical Confounders + +```{r confounders-normalized} +normalized_mat <- GetAssayData(synthetic_test_object_100, assay = "RNA", layer = "data") +common_genes <- intersect(rownames(normalized_mat), Wnt_12h$Gene_Symbol) +gene_matrix <- as.matrix(normalized_mat[common_genes, ]) + +mean_expr <- colMeans(gene_matrix, na.rm = TRUE) +zscore_mean_per_cell <- colMeans(t(scale(t(gene_matrix))), na.rm = TRUE) +seurat_meta <- synthetic_test_object_100@meta.data + +make_scatter <- function(df, x_col, x_label) { + r <- cor(df$embed_score, df[[x_col]], method = "spearman", use = "complete.obs") + ggplot(df, aes(x = .data[[x_col]], y = embed_score)) + + geom_point(alpha = 0.4, size = 1.2, color = "#534AB7") + + geom_smooth(method = "lm", color = "#E24B4A", linewidth = 0.8, se = TRUE) + + labs(title = sprintf("%s (rho = %.3f)", x_label, r), + x = x_label, y = "PathwayEmbed score") + + theme_minimal() +} + +confounder_df_norm <- data.frame( + cell = names(score_12h), + embed_score = as.numeric(score_12h), + mean_expr = mean_expr[names(score_12h)], + zscore_expr = zscore_mean_per_cell[names(score_12h)], + nCount_RNA = seurat_meta[names(score_12h), "nCount_RNA"], + nFeature_RNA = seurat_meta[names(score_12h), "nFeature_RNA"] +) + +for (cov in c("mean_expr", "zscore_expr", "nCount_RNA", "nFeature_RNA")) { + r <- cor(confounder_df_norm$embed_score, confounder_df_norm[[cov]], + method = "spearman", use = "complete.obs") + cat(sprintf("Spearman vs %-20s : %.3f\n", cov, r)) +} + +p_nor <- (make_scatter(confounder_df_norm, "mean_expr", "Mean expression") + + make_scatter(confounder_df_norm, "zscore_expr", "Z-score mean")) / + (make_scatter(confounder_df_norm, "nCount_RNA", "nCount_RNA") + + make_scatter(confounder_df_norm, "nFeature_RNA", "nFeature_RNA")) +p_nor +``` + +## Correlation with Technical Confounders — Raw Counts + +```{r confounders-raw} +common_genes_raw <- intersect(rownames(matrix_raw), Wnt_12h$Gene_Symbol) +gene_matrix_raw <- as.matrix(matrix_raw[common_genes_raw, ]) + +mean_expr_raw <- colMeans(gene_matrix_raw, na.rm = TRUE) +zscore_mean_per_cell_raw <- colMeans(t(scale(t(gene_matrix_raw))), na.rm = TRUE) +score_raw_12h <- result_raw$score + +confounder_df_raw <- data.frame( + cell = names(score_raw_12h), + embed_score = as.numeric(score_raw_12h), + mean_expr = mean_expr_raw[names(score_raw_12h)], + zscore_expr = zscore_mean_per_cell_raw[names(score_raw_12h)], + nCount_RNA = seurat_meta[names(score_raw_12h), "nCount_RNA"], + nFeature_RNA = seurat_meta[names(score_raw_12h), "nFeature_RNA"] +) + +for (cov in c("mean_expr", "zscore_expr", "nCount_RNA", "nFeature_RNA")) { + r <- cor(confounder_df_raw$embed_score, confounder_df_raw[[cov]], + method = "spearman", use = "complete.obs") + cat(sprintf("Spearman vs %-20s : %.3f\n", cov, r)) +} + +p_raw <- (make_scatter(confounder_df_raw, "mean_expr", "Mean expression") + + make_scatter(confounder_df_raw, "zscore_expr", "Z-score mean")) / + (make_scatter(confounder_df_raw, "nCount_RNA", "nCount_RNA") + + make_scatter(confounder_df_raw, "nFeature_RNA", "nFeature_RNA")) +p_raw +``` + +------------------------------------------------------------------------ + +## Benchmark Against PROGENy and AddModuleScore + +```{r benchmark} +normalized_mat_dense <- as.matrix(normalized_mat) + +progeny_scores <- progeny( + normalized_mat_dense, + scale = TRUE, + organism = "Mouse", + top = 100, + perm = 1 +) +progeny_wnt <- setNames(as.numeric(progeny_scores[, "WNT"]), + rownames(progeny_scores)) + +wnt_features <- rownames(matrix_24h) +synthetic_test_object_100 <- AddModuleScore( + object = synthetic_test_object_100, + features = list(wnt_features), + name = "WNT_ModuleScore", + ctrl = 5, + nbin = 10 +) +module_score <- setNames( + synthetic_test_object_100@meta.data$WNT_ModuleScore1, + rownames(synthetic_test_object_100@meta.data) +) + +cells <- names(score_24h) +benchmark_df <- data.frame( + PathwayEmbed = as.numeric(score_24h), + PROGENy = as.numeric(progeny_wnt[cells]), + AddModuleScore = as.numeric(module_score[cells]), + mean_expr = as.numeric(mean_expr[cells]), + zscore_expr = as.numeric(zscore_mean_per_cell[cells]), + row.names = cells +) + +benchmark_cor <- cor(benchmark_df, method = "spearman", + use = "pairwise.complete.obs") +print(round(benchmark_cor, 3)) + +p9 <- pheatmap( + benchmark_cor, + color = colorRampPalette(c("#185FA5", "white", "#993C1D"))(100), + breaks = seq(-1, 1, length.out = 101), + display_numbers = TRUE, number_format = "%.2f", + fontsize_number = 9, + main = "Method Benchmark — Spearman Correlation" +) +p9 + +genotype_label <- ifelse( + synthetic_test_metadata[cells, "genotype"] == "Mutant", 1L, 0L +) + +compute_auroc <- function(scores, labels) { + r <- roc(labels, scores, quiet = TRUE) + auc_val <- as.numeric(auc(r)) + if (auc_val < 0.5) auc_val <- 1 - auc_val + auc_val +} + +auroc_results <- data.frame( + Method = colnames(benchmark_df), + AUROC = sapply(benchmark_df, compute_auroc, labels = genotype_label) +) +auroc_results <- auroc_results[order(-auroc_results$AUROC), ] +print(auroc_results) + +compute_cohens_d_method <- function(scores, metadata, group_col) { + scores <- setNames(as.numeric(scores), names(scores)) + pd <- PreparePlotData(metadata, scores, group = group_col) + pct <- CalculatePercentage(pd, group_var = group_col) + abs(pct$cohens_d[1]) +} + +cohens_d_results <- data.frame( + Method = colnames(benchmark_df), + Cohens_d = sapply( + colnames(benchmark_df), + function(m) compute_cohens_d_method( + setNames(benchmark_df[[m]], rownames(benchmark_df)), + synthetic_test_metadata, "genotype" + ) + ) +) +cohens_d_results <- cohens_d_results[order(-cohens_d_results$Cohens_d), ] +print(cohens_d_results) + +method_colors <- c( + "PathwayEmbed" = "#534AB7", + "PROGENy" = "#E24B4A", + "AddModuleScore" = "#EF9F27", + "mean_expr" = "#888780", + "zscore_expr" = "#B4B2A9" +) + +p10 <- ggplot(auroc_results, aes(x = reorder(Method, AUROC), y = AUROC, fill = Method)) + + geom_bar(stat = "identity", width = 0.6) + + geom_hline(yintercept = 0.5, linetype = "dashed", color = "black") + + coord_flip() + + scale_fill_manual(values = method_colors) + + labs(title = "AUROC: Mutant vs WT separation by scoring method", + x = NULL, y = "AUROC") + + ylim(0, 1) + + theme_classic() + + theme(legend.position = "none", + axis.text.y = element_text(size = 12), + axis.text.x = element_text(size = 11), + axis.title.x = element_text(size = 12), + plot.title = element_text(size = 13, face = "bold")) + +p11 <- ggplot(cohens_d_results, aes(x = reorder(Method, Cohens_d), y = Cohens_d, fill = Method)) + + geom_bar(stat = "identity", width = 0.6) + + geom_hline(yintercept = 0.5, linetype = "dashed", color = "black") + + coord_flip() + + scale_fill_manual(values = method_colors) + + labs(title = "Cohen's d: Mutant vs WT separation by scoring method", + x = NULL, y = "Cohen's d") + + ylim(0, 1) + + theme_classic() + + theme(legend.position = "none", + axis.text.y = element_text(size = 12), + axis.text.x = element_text(size = 11), + axis.title.x = element_text(size = 12), + plot.title = element_text(size = 13, face = "bold")) + +p10; p11 +``` + +------------------------------------------------------------------------ + +## Sensitivity Analysis 2 — Effect of Distance Method + +```{r sensitivity-distance} +score_manhattan <- ComputeCellData(matrix_24h, pathwaystat_24h, + distance.method = "manhattan") +score_euclidean <- ComputeCellData(matrix_24h, pathwaystat_24h, + distance.method = "euclidean") + +cor_dist <- cor(score_manhattan, score_euclidean, method = "spearman") +cat("Spearman correlation (manhattan vs euclidean):", round(cor_dist, 3), "\n") + +plotdata_manhattan <- PreparePlotData(synthetic_test_metadata, score_manhattan, + group = "genotype") +plotdata_euclidean <- PreparePlotData(synthetic_test_metadata, score_euclidean, + group = "genotype") + +pct_manhattan <- CalculatePercentage(plotdata_manhattan, group_var = "genotype") +pct_euclidean <- CalculatePercentage(plotdata_euclidean, group_var = "genotype") + +distance_comparison <- data.frame( + method = c("Manhattan", "Euclidean"), + cohens_d = c(pct_manhattan$cohens_d[1], pct_euclidean$cohens_d[1]), + p_value = c(pct_manhattan$p_value[1], pct_euclidean$p_value[1]), + pct_on_wt = c(pct_manhattan$percentage_on[pct_manhattan$group == "WT"], + pct_euclidean$percentage_on[pct_euclidean$group == "WT"]), + pct_on_mut = c(pct_manhattan$percentage_on[pct_manhattan$group == "Mutant"], + pct_euclidean$percentage_on[pct_euclidean$group == "Mutant"]) +) +print(distance_comparison) + +dist_df <- data.frame(manhattan = as.numeric(score_manhattan), + euclidean = as.numeric(score_euclidean), + row.names = names(score_manhattan)) + +p_scatter <- ggplot(dist_df, aes(x = manhattan, y = euclidean)) + + geom_point(alpha = 0.4, size = 1.2, color = "#534AB7") + + geom_smooth(method = "lm", color = "#E24B4A", linewidth = 0.8, se = TRUE) + + labs(title = sprintf("Manhattan vs Euclidean (rho = %.3f)", cor_dist), + x = "Manhattan score", y = "Euclidean score") + + theme_minimal() + +p_man_plot <- PlotPathway(plotdata_manhattan, "Wnt 24h — Manhattan", + "genotype", c("#ae282c", "#2066a8")) +p_euc_plot <- PlotPathway(plotdata_euclidean, "Wnt 24h — Euclidean", + "genotype", c("#ae282c", "#2066a8")) + +p_scatter / (p_man_plot + p_euc_plot) + + plot_annotation(title = "Sensitivity to Distance Method") +``` diff --git a/vignettes/spatial_pathway.Rmd b/vignettes/spatial_pathway.Rmd deleted file mode 100644 index b0bfb2b..0000000 --- a/vignettes/spatial_pathway.Rmd +++ /dev/null @@ -1,216 +0,0 @@ ---- -title: "Spatial Pathway Visualization" -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{Spatial Pathway Visualization} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r setup} -knitr::opts_chunk$set(echo = TRUE) - -# load library -library(PathwayEmbed) -library(Seurat) -library(ggplot2) -library(viridis) -library(cowplot) - -``` - -## Spatial data load and process - -The files can be downloaded from figshare via below link: - -Huang, Yaqing (2025). dat3.with.niches.norm.Robj. figshare. Dataset. https://doi.org/10.6084/m9.figshare.29649995.v1 - -Huang, Yaqing (2025). dat4.with.niches.norm.Robj. figshare. Dataset. https://doi.org/10.6084/m9.figshare.29649989.v1 - -Huang, Yaqing (2025). dat1.with.niches.norm.Robj. figshare. Dataset. https://doi.org/10.6084/m9.figshare.29649992.v1 - -Huang, Yaqing (2025). dat2.with.niches.norm.Robj. figshare. Dataset. https://doi.org/10.6084/m9.figshare.29649986.v1 - -```{r load data, eval=FALSE} -# load data -load("dat1.with.niches.norm.Robj") -load("dat2.with.niches.norm.Robj") -load("dat3.with.niches.norm.Robj") -load("dat4.with.niches.norm.Robj") - -# Merge together -merged_spatial <- merge( - dat1, y = c(dat2, dat3, dat4)) - -# Set Default Assay to be "RNA" -DefaultAssay(merged_spatial) <- "RNA" -``` - -## Compute pathway score - -Compute score for Wnt, Notch, Hippo, Tgfb, and HIF-1a pathways for the merged subject using 'ComputeCellData' in PathwayEmbed - -```{r score compute, eval=FALSE} - -# Compute the score for each pathway -Wnt_mds <- ComputeCellData(merged_spatial, "Wnt", "manhattan", batch.size = 1000) -Notch_mds <- ComputeCellData(merged_spatial, "Notch", "manhattan", batch.size = 1000) -Hippo_mds <- ComputeCellData(merged_spatial, "Hippo", "manhattan", batch.size = 1000) -Tgfb_mds <- ComputeCellData(merged_spatial, "Tgfb", "manhattan", batch.size = 1000) -HIF1a_mds <- ComputeCellData(merged_spatial, "HIF-1a", "manhattan", batch.size = 1000) - -# Process the mds -Wnt_to.plot <- PreparePlotData(merged_spatial, Wnt_mds, "timepoint") -Notch_to.plot <- PreparePlotData(merged_spatial, Notch_mds, "timepoint") -Hippo_to.plot <- PreparePlotData(merged_spatial, Hippo_mds, "timepoint") -Tgfb_to.plot <- PreparePlotData(merged_spatial, Tgfb_mds, "timepoint") -HIF1a_to.plot <- PreparePlotData(merged_spatial, HIF1a_mds, "timepoint") - -# Combine to list -pathway_list <- list( - Wnt = Wnt_to.plot, - Notch = Notch_to.plot, - Hippo = Hippo_to.plot, - Tgfb = Tgfb_to.plot, - HIF1a = HIF1a_to.plot -) - -``` - -## Preparation for groups - -```{r, echo = FALSE} -# Load to.plot rds -pathway_list <- readRDS(system.file("extdata", "pathway_list.rds", package = "PathwayEmbed")) - -``` - -```{r plot set up} -# Color set-up -magma_colors <- c("#000004FF", "#721F81FF", "#F1605DFF", "#5A90E6") - -# Desired timepoint order -ordered_timepoints <- c("E9.5", "E10.5", "E11.5", "E12.5") - -# Reorder timepoint levels -for (name in names(pathway_list)) { - pathway_list[[name]]$timepoint <- factor(pathway_list[[name]]$timepoint, levels = ordered_timepoints) -} - -``` - -## Plot across different timepoints - -```{r} - -# Loop through each pathway and generate/save the plot -for (i in seq_along(pathway_list)) { - # Generate the plot - p <- PlotPathway(pathway_list[[i]], names(pathway_list)[i], "timepoint", magma_colors) + - facet_wrap(~timepoint, ncol = 1) - print(p) -} - - -``` - -## Merge score with original metadata - -```{r, eval = FALSE} -# Step 1: Create named score vectors for each pathway -score_list <- lapply(pathway_list, function(df) { - s <- df$scale - names(s) <- rownames(df) - return(s) -}) - -# Step 2: Add each pathway score to dat1–dat4 -for (i in 1:4) { - dat <- get(paste0("dat", i)) # get dat1, dat2, ... - - for (pathway_name in names(score_list)) { - score_vec <- score_list[[pathway_name]] - dat[[paste0(pathway_name, "_score")]] <- score_vec[colnames(dat)] - } - - assign(paste0("dat", i), dat) # assign back to dat1, dat2, etc. -} - - -# List of Seurat objects -dat_list <- list(dat1, dat2, dat3, dat4) -names(dat_list) <- paste0("dat", 1:4) - -# List of pathways -pathways <- names(pathway_list) # e.g., "Wnt", "Notch", etc. - -``` - -## Extract the coordinates - -```{r, eval=FALSE} -# Function to extract -extract_pathway_df <- function(seu, pathway, sample_name = "sample") { - coords <- as.data.frame(Embeddings(seu[["spatial"]])) - colnames(coords) <- c("x", "y") - coords$score <- seu[[paste0(pathway, "_score")]][rownames(coords), 1] - coords$sample <- sample_name - return(coords) -} - -# Set list to save the coordinates -combined_df_lists <- list() - -# For loop for all pathways -for (pathway in pathways) { - pathway_df_list <- mapply( - FUN = extract_pathway_df, - seu = dat_list, - sample_name = names(dat_list), - MoreArgs = list(pathway = pathway), - SIMPLIFY = FALSE - ) - - combined_df <- do.call(rbind, pathway_df_list) - combined_df_lists[[pathway]] <- combined_df -} - -``` - -## Plot the spatial data - -```{r, echo=FALSE} -combined_df_lists <- readRDS(system.file("extdata", "combined_df_lists.rds", package = "PathwayEmbed")) - -``` - -```{r} -limits_list <- list( - Wnt = c(-3, 4), - Notch = c(-3, 4), - Hippo = c(-2, 3), - Tgfb = c(-2, 3), - HIF1a = c(-3, 5) -) - -for (pathway in names(combined_df_lists)) { - combined_df <- combined_df_lists[[pathway]] - selected_limits <- limits_list[[pathway]] - - p <- ggplot(combined_df, aes(x = x, y = y, color = score)) + - geom_point(size = 0.3) + - scale_color_viridis_c( - option = "magma", - name = paste0(pathway, "_score"), - limits = selected_limits, - oob = scales::squish - ) + - scale_y_reverse() + - coord_fixed() + - theme_void() + - theme(legend.position = "right") - - print(p) -} - -``` diff --git a/vignettes/spatial_pathway_updated.Rmd b/vignettes/spatial_pathway_updated.Rmd new file mode 100644 index 0000000..6891578 --- /dev/null +++ b/vignettes/spatial_pathway_updated.Rmd @@ -0,0 +1,773 @@ +--- +title: "Spatial Pathway Visualization" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Spatial Pathway Visualization} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +## Overview +This vignette demonstrates the application of PathwayEmbed in mouse embryo spatial data (E9.5 - E12.5). With curated pathway database, we examined and compared Wnt, Notch, TGFb, Hippo, and HIF-1a signaling transduction states across spatial and temporal development. +Reference for the initial data: Chen et al. Spatiotemporal transcriptomic atlas of mouse organogenesis using DNA nanoball-patterned arrays, Cell, Volume 185, Issue 10, 2022, Pages 1777-1792.e21. + + +```{r setup} +knitr::opts_chunk$set( + echo = TRUE, + collapse = TRUE, + warning = FALSE, + message = FALSE, + comment = "#>", + fig.width = 8, + fig.height = 6 +) + +# load library +library(PathwayEmbed) +library(Seurat) +library(ggplot2) +library(viridis) +library(cowplot) +library(dplyr) +library(Hmisc) +library(corrplot) +library(tibble) +library(tidyr) + +``` + +## Spatial data load and process + +The files can be downloaded from figshare via below link: + +Huang, Yaqing (2025). dat3.with.niches.norm.Robj. figshare. Dataset. https://doi.org/10.6084/m9.figshare.29649995.v1 + +Huang, Yaqing (2025). dat4.with.niches.norm.Robj. figshare. Dataset. https://doi.org/10.6084/m9.figshare.29649989.v1 + +Huang, Yaqing (2025). dat1.with.niches.norm.Robj. figshare. Dataset. https://doi.org/10.6084/m9.figshare.29649992.v1 + +Huang, Yaqing (2025). dat2.with.niches.norm.Robj. figshare. Dataset. https://doi.org/10.6084/m9.figshare.29649986.v1 + +```{r load data, eval=FALSE} +# load data +load("dat1.with.niches.norm.Robj") +load("dat2.with.niches.norm.Robj") +load("dat3.with.niches.norm.Robj") +load("dat4.with.niches.norm.Robj") + +# Merge together +merged_spatial <- merge( + dat1, y = c(dat2, dat3, dat4)) + +# Set Default Assay to be "RNA" +DefaultAssay(merged_spatial) <- "RNA" + +# Get genes x cell matrix +merged_spatial_matrix <- as.matrix(GetAssayData(merged_spatial, assay = "RNA", layer = "data")) + +# Get metadata matrix +merged_spatial_metadata <- merged_spatial@meta.data +``` + +## Get Pathway Data for Each Pathway first + +```{r} + +# All Pathways +ListPathway("Pathway") +ListPathway("HIF1A") # Pick Hypoxia_24hr +ListPathway("HIPPO") # Only one: HIPPO_heat +ListPathway("NOTCH") # Use NOTCH_JAG1_24H -> validated in another datasets +ListPathway("TGFB") # Use TGFB_Mouse since this is the only Ms dataset +ListPathway("WNT") # Use WNT3A_SLOPE_ACTIVATION + +# Load Each Pathwaydatabase +HIf1a_pathwaydata <- LoadPathway("Hypoxia_24hr", "mouse") +Hippo_pathwaydata <- LoadPathway("HIPPO_heat", "mouse") +Notch_pathwaydata <- LoadPathway("NOTCH_JAG1_24H", "mouse") +TGFb_pathwaydata <- LoadPathway("TGFB_Mouse", "mouse") +Wnt_pathwaydata <- LoadPathway("WNT3A_SLOPE_ACTIVATION", "mouse") + + +``` + +## Calculation + +Using Matrix extracted to avoid large size data object, compute score for Wnt, Notch, Hippo, Tgfb, and HIF-1a pathways for the merged subject using 'ComputeCellData' in PathwayEmbed + +```{r score compute, eval=FALSE} + + +# DataPreProcess +matrix_HIf1a <- DataPreProcess(merged_spatial_matrix, HIf1a_pathwaydata, Seurat.object = FALSE) +matrix_Hippo <- DataPreProcess(merged_spatial_matrix, Hippo_pathwaydata, Seurat.object = FALSE) +matrix_Notch <- DataPreProcess(merged_spatial_matrix, Notch_pathwaydata, Seurat.object = FALSE) +matrix_TGFb <- DataPreProcess(merged_spatial_matrix, TGFb_pathwaydata, Seurat.object = FALSE) +matrix_Wnt <- DataPreProcess(merged_spatial_matrix, Wnt_pathwaydata, Seurat.object = FALSE) + +# PathwayMaxMin +pathwaystat_HIf1a <- PathwayMaxMin(matrix_HIf1a, HIf1a_pathwaydata) +pathwaystat_Hippo <- PathwayMaxMin(matrix_Hippo, Hippo_pathwaydata) +pathwaystat_Notch <- PathwayMaxMin(matrix_Notch, Notch_pathwaydata) +pathwaystat_TGFb <- PathwayMaxMin(matrix_TGFb, TGFb_pathwaydata) +pathwaystat_Wnt <- PathwayMaxMin(matrix_Wnt, Wnt_pathwaydata) + +# Computing Score +HIf1a_score <- ComputeCellData(matrix_HIf1a, pathwaystat_HIf1a) +Hippo_score <- ComputeCellData(matrix_Hippo, pathwaystat_Hippo) +Notch_score <- ComputeCellData(matrix_Notch, pathwaystat_Notch) +TGFb_score <- ComputeCellData(matrix_TGFb, pathwaystat_TGFb) +Wnt_score <- ComputeCellData(matrix_Wnt, pathwaystat_Wnt) + + +``` + + +## Prepare plot data + +Map Timepoints back to the data + +```{r prepare plot data, eval=FALSE} + +# Compute the score for each pathway +Wnt_to.plot <- PreparePlotData(merged_spatial_metadata, Wnt_score, "timepoint", Seurat.object = FALSE) +Notch_to.plot <- PreparePlotData(merged_spatial_metadata, Notch_score, "timepoint", Seurat.object = FALSE) +Hippo_to.plot <- PreparePlotData(merged_spatial_metadata, Hippo_score, "timepoint", Seurat.object = FALSE) +Tgfb_to.plot <- PreparePlotData(merged_spatial_metadata, TGFb_score, "timepoint", Seurat.object = FALSE) +HIF1a_to.plot <- PreparePlotData(merged_spatial_metadata, HIf1a_score,"timepoint", Seurat.object = FALSE) + + +# Combine to list +pathway_timepoint <- list( + Wnt = Wnt_to.plot, + Notch = Notch_to.plot, + Hippo = Hippo_to.plot, + Tgfb = Tgfb_to.plot, + HIF1a = HIF1a_to.plot +) + +``` + +## Preparation for groups + +```{r, echo = FALSE} +pathway_timepoint <- readRDS(system.file("extdata", "pathway_list_timepoint.rds", + package = "PathwayEmbed", + mustWork = TRUE)) +``` + +```{r debug, echo = FALSE} +cat(system.file("extdata", "pathway_list_timepoint.rds", package = "PathwayEmbed")) +cat("\n") +cat(.libPaths()) +``` + +```{r plot set up} +# Color set-up +magma_colors <- c("#000004FF", "#721F81FF", "#F1605DFF", "#5A90E6") + +# Desired timepoint order +ordered_timepoints <- c("E9.5", "E10.5", "E11.5", "E12.5") + +# Reorder timepoint levels +for (name in names(pathway_timepoint)) { + pathway_timepoint[[name]]$timepoint <- factor(pathway_timepoint[[name]]$timepoint, levels = ordered_timepoints) +} + +``` + +## Plot across different timepoints + +```{r} +# Calculation + +stats <- list() +# Loop through each pathway and generate/save the plot +for (i in seq_along(pathway_timepoint)) { + stats[[i]] <- CalculatePercentage(pathway_timepoint[[i]], "timepoint") + + df_stats <- stats[[i]] + + df_stats <- stats[[i]] %>% + dplyr::distinct(group, .keep_all = TRUE) %>% + dplyr::rename(timepoint = group) + +p <- PlotPathway( + pathway_timepoint[[i]], + names(pathway_timepoint)[i], + "timepoint", + magma_colors +) + + facet_wrap(~factor(timepoint, levels = ordered_timepoints), ncol = 1) + + geom_text( + data = df_stats %>% + mutate(timepoint = factor(timepoint, levels = ordered_timepoints)), + aes( + x = Inf, + y = Inf, + label = sprintf( + "ON: %.1f%%\nOFF: %.1f%%\np = %.2g", + percentage_on, percentage_off, kruskal_p + ) + ), + hjust = 1.1, + vjust = 1.1, + size = 3, + inherit.aes = FALSE + ) + + print(p) + # ggsave( + # filename = paste0(names(pathway_timepoint)[i], "_timepoint_plot.png"), + # plot = p, + # width = 6, + # height = 8, + # dpi = 300 +# ) +} + +``` + +## Merge score with original metadata + +```{r, eval = FALSE} +# Step 1: Create named score vectors for each pathway +score_list <- lapply(pathway_list, function(df) { + s <- df$scale + names(s) <- rownames(df) + return(s) +}) + +# Step 2: Add each pathway score to dat1–dat4 +for (i in 1:4) { + dat <- get(paste0("dat", i)) # get dat1, dat2, ... + + for (pathway_name in names(score_list)) { + score_vec <- score_list[[pathway_name]] + dat[[paste0(pathway_name, "_score")]] <- score_vec[colnames(dat)] + } + + assign(paste0("dat", i), dat) # assign back to dat1, dat2, etc. +} + + +# List of Seurat objects +dat_list <- list(dat1, dat2, dat3, dat4) +names(dat_list) <- paste0("dat", 1:4) + +# List of pathways +pathways <- names(pathway_list) # e.g., "Wnt", "Notch", etc. + +``` + +## Extract the coordinates + +```{r, eval=FALSE} +# Function to extract +extract_pathway_df <- function(seu, pathway, sample_name = "sample") { + coords <- as.data.frame(Embeddings(seu[["spatial"]])) + colnames(coords) <- c("x", "y") + coords$score <- seu[[paste0(pathway, "_score")]][rownames(coords), 1] + coords$sample <- sample_name + return(coords) +} + +# Set list to save the coordinates +combined_df_lists <- list() + +# For loop for all pathways +for (pathway in pathways) { + pathway_df_list <- mapply( + FUN = extract_pathway_df, + seu = dat_list, + sample_name = names(dat_list), + MoreArgs = list(pathway = pathway), + SIMPLIFY = FALSE + ) + + combined_df <- do.call(rbind, pathway_df_list) + combined_df_lists[[pathway]] <- combined_df +} + +``` + +## Plot the spatial data + +```{r, echo=FALSE} +combined_df_lists <- readRDS(system.file("extdata", "combined_df_lists_updated.rds", package = "PathwayEmbed")) + +``` + +```{r} +# Compute global symmetric limits (recommended) +all_values <- unlist(lapply(combined_df_lists, function(df) df$scale)) +q <- quantile(all_values, c(0.02, 0.98), na.rm = TRUE) +max_abs <- max(abs(q)) +global_limits <- c(-max_abs, max_abs) + +for (pathway in names(combined_df_lists)) { + + combined_df <- combined_df_lists[[pathway]] + # randomize the plot + combined_df <- combined_df[sample(nrow(combined_df)), ] + + p <- ggplot(combined_df, aes(x = x, y = y, color = scale)) + + geom_point(size = 0.01) + + scale_color_viridis_c( + option = "magma", + limits = global_limits, # symmetric across all pathways + oob = scales::squish, + name = paste0(pathway, "_score") + ) + + scale_y_reverse() + + coord_fixed() + + theme_void() + + theme( + legend.position = "right", + plot.title = element_text(hjust = 0.5, face = "bold") + ) + + ggtitle(pathway) + + print(p) +} + +``` +## Spatial Correlation Analysis using Moran's I + +```{r, eval=FALSE} +library(spdep) + +# Global Moran's I + +compute_morans_I <- function(df, k = 6) { + + coords <- as.matrix(df[, c("x", "y")]) + + # k-nearest neighbors graph + knn <- knearneigh(coords, k = k) + nb <- knn2nb(knn) + lw <- nb2listw(nb, style = "W") + + # Moran’s I test + moran.test(df$scale, lw) +} + +moran_results <- lapply(names(combined_df_lists), function(pw) { + + df <- combined_df_lists[[pw]] + res <- compute_morans_I(df) + + data.frame( + pathway = pw, + morans_I = res$estimate[["Moran I statistic"]], + p_value = res$p.value + ) +}) +moran_results <- do.call(rbind, moran_results) + + +``` + +```{r, echo=FALSE} +moran_results <- readRDS(system.file("extdata", "moran_results.rds", package = "PathwayEmbed")) + +``` + +```{r plot moransI} +print(moran_results) + +``` + +```{r, eval=FALSE} +# compute neighbor Moran's I for pathways with high spatial autocorrelation +compute_local_moran <- function(df, lw, pathway_name) { + + local <- localmoran(df$scale, lw) + + transform( + df, + local_I = local[, 1], + z_score = local[, 4], + p_value = local[, 5], + pathway = pathway_name + ) +} + +# Apply to selected pathways +selected_pathways <- c("Notch", "HIF1a") + +df_plot <- do.call(rbind, lapply(selected_pathways, function(pw) { + compute_local_moran(combined_df_lists_updated[[pw]], lw, pw) +})) +``` + +```{r, echo=FALSE} + +df_plot <- readRDS(system.file("extdata", "moran_df_plot.rds", package = "PathwayEmbed")) +``` + +```{r plot local morans I} +library(ggplot2) +library(viridis) + +# 🔀 Randomize plotting order +df_plot <- df_plot[sample(nrow(df_plot)), ] + +df_plot$cluster <- "Not significant" + +df_plot$cluster[df_plot$p_value < 0.05 & df_plot$local_I > 0] <- "High-High" +df_plot$cluster[df_plot$p_value < 0.05 & df_plot$local_I < 0] <- "Low-Low" + +df_plot$cluster <- factor(df_plot$cluster, + levels = c("High-High", "Low-Low", "Not significant")) + +df_plot <- df_plot[sample(nrow(df_plot)), ] + +p_cluster <- ggplot(df_plot, aes(x = x, y = y, color = cluster)) + + geom_point(size = 0.001) + + scale_color_manual(values = c( + "High-High" = "#d73027", # red = hotspot + "Low-Low" = "#4575b4", # blue = coldspot + "Not significant" = "grey80" + )) + + scale_y_reverse() + + coord_fixed() + + facet_wrap(~ pathway) + + theme_void() + + labs(title = "Local Moran’s I Clusters", + color = "Cluster") + +print(p_cluster) +``` + +## Benchmark towards Progeny +Benchmark + Technical Confounding Factors +```{r, eval = FALSE} +set.seed(123) +# Load all required libraries + library(progeny) + library(ggplot2) + library(dplyr) + library(tidyr) + library(patchwork) + library(corrplot) + library(Hmisc) + library(Matrix) + library(tibble) +library(tidyr) + +# Explicitly import pipe in case dplyr loaded partially +`%>%` <- dplyr::`%>%` + +# ----Progeny----- + +merged_spatial_matrix <- readRDS("merged_spatial_matrix.rds") + +progeny_scores <- progeny( + merged_spatial_matrix, + scale = TRUE, + organism = "Mouse", + top = 100, + perm = 1 +) + +``` + +```{r, echo=FALSE} +progeny_scores <- readRDS(system.file("extdata", "progeny_scores.rds", package = "PathwayEmbed")) +# load corresponding pathway scores +HIf1a_score <- readRDS(system.file("extdata", "HIf1a_score.rds", package = "PathwayEmbed")) +Hippo_score <- readRDS(system.file("extdata", "Hippo_score.rds", package = "PathwayEmbed")) +Notch_score <- readRDS(system.file("extdata", "Notch_score.rds", package = "PathwayEmbed")) +TGFb_score <- readRDS(system.file("extdata", "TGFb_score.rds", package = "PathwayEmbed")) +Wnt_score <- readRDS(system.file("extdata", "Wnt_score.rds", package = "PathwayEmbed")) + +``` + +```{r} +# Extract pathways — check column names exist first +print(colnames(progeny_scores)) + +# Extract existed pathways +progeny_wnt <- progeny_scores[, "WNT"] +progeny_hypoxia <- progeny_scores[, "Hypoxia"] +progeny_tgfb <- progeny_scores[, "TGFb"] + +# correlation with Progeny score +cor_wnt <- cor(Wnt_score, progeny_wnt, use = "complete.obs", method = "spearman") +cor_tgfb <- cor(TGFb_score, progeny_tgfb, use = "complete.obs", method = "spearman") +cor_hif <- cor(HIf1a_score, progeny_hypoxia, use = "complete.obs", method = "spearman") + +cor_results <- data.frame( + comparison = c("Wnt vs PROGENy WNT", "TGFb vs PROGENy TGFb", "HIf1a vs PROGENy Hypoxia"), + spearman_r = round(c(cor_wnt, cor_tgfb, cor_hif), 4), + pathway_our = c("Wnt_score", "TGFb_score", "HIf1a_score"), + pathway_ref = c("WNT", "TGFb", "Hypoxia") +) + +df_all <- rbind( + data.frame(our = Wnt_score, progeny = progeny_wnt, pathway = "WNT"), + data.frame(our = TGFb_score, progeny = progeny_tgfb, pathway = "TGFb"), + data.frame(our = HIf1a_score, progeny = progeny_hypoxia, pathway = "Hypoxia") +) + +label_df <- cor_results %>% + mutate(pathway = c("WNT", "TGFb", "Hypoxia"), + label = paste0("r = ", round(spearman_r, 3))) + +p_benchmark <- ggplot(df_all, aes(x = our, y = progeny)) + + + geom_point(alpha = 0.3, size = 0.8, color = "grey30") + + + geom_smooth(method = "lm", se = TRUE, + color = "#E24B4A", fill = "#FAD4D4", + linewidth = 0.8) + + geom_text( + data = label_df, + aes(label = label), + x = -Inf, y = Inf, + hjust = -0.1, vjust = 1.2, + size = 5, + fontface = "bold", + inherit.aes = FALSE + ) + + facet_wrap(~ pathway, ncol = 1, scales = "free_x") + + labs( + title = "Benchmark: Our Scores vs PROGENy", + x = "Our pathway score", + y = "PROGENy score" + ) + + theme_classic(base_size = 15) + + theme( + strip.background = element_rect(fill = "grey95", color = NA), + strip.text = element_text(face = "bold"), + plot.title = element_text(hjust = 0.5, face = "bold"), + axis.title = element_text(face = "bold") + ) + +p_benchmark + +``` +--- + +## Cross-pathway Spearman Correlation matrix +```{r cross-pathway spearman correlation matrix} +score_df <- data.frame( + HIf1a = HIf1a_score, + Hippo = Hippo_score, + Notch = Notch_score, + TGFb = TGFb_score, + Wnt = Wnt_score +) + +cor_matrix <- cor(score_df, method = "spearman", use = "complete.obs") + +cor_test <- Hmisc::rcorr(as.matrix(score_df), type = "spearman") +p_matrix <- cor_test$P +diag(p_matrix) <- 0 # rcorr sets diagonal to NA; corrplot requires numeric diagonal +print(round(cor_matrix, 3)) + +# Correlation heatmap + +corrplot::corrplot(cor_matrix, + method = "color", type = "upper", + addCoef.col = "black", number.cex = 0.8, + tl.col = "black", tl.srt = 45, + p.mat = p_matrix, sig.level = 0.05, insig = "blank", + title = "Pathway Spearman Correlations", + mar = c(0, 0, 2, 0)) + + + +``` + +--- +## Technical Cofounders +```{r, eval=FALSE} +#---Basic QC metrics from the raw count matrix ---- +# merged_spatial_matrix is genes x spots (dense or sparse both work here) +nCount <- Matrix::colSums(merged_spatial_matrix) +nFeature <- Matrix::colSums(merged_spatial_matrix > 0) + +# Mitochondrial genes — mouse mt genes start with "mt-" (lowercase) +mt_genes <- grep("^mt-", rownames(merged_spatial_matrix), + value = TRUE, ignore.case = TRUE) +if (length(mt_genes) == 0) { + warning("No mitochondrial genes found. Check rowname format (expected 'mt-*').") + pct_mt <- rep(NA_real_, ncol(merged_spatial_matrix)) +} else { + mt_counts <- Matrix::colSums(merged_spatial_matrix[mt_genes, , drop = FALSE]) + pct_mt <- 100 * mt_counts / nCount +} + + + +#---Cell Cycle Scoring---- + +# Strategy: compute the mean z-scored expression of S-phase genes and G2M +# genes per spot as module scores, then correlate with pathway scores. +# This is equivalent to Seurat's AddModuleScore but works on a plain matrix. + +# Mouse cell cycle gene sets (Tirosh et al. 2015, mouse-converted) +s_genes_mouse <- c( + "Mcm5", "Pcna", "Tyms", "Fen1", "Mcm7", "Mcm4", "Rrm1", "Ung", + "Gins2", "Mcm6", "Cdca7", "Dtl", "Prim1", "Uhrf1", "Cenpu", + "Hells", "Rfc2", "Rad51ap1", "Gmnn", "Wdc", "Slbp", "Ccne2", + "Ubr7", "Pold3", "Msh2", "Atad2", "Rad51", "Rrm2", "Cdc45", + "Cdc6", "Exo1", "Tipin", "Dscc1", "Blm", "Casp8ap2", "Usp1", + "Clspn", "Pola1", "Chaf1b", "Brip1", "E2f8" +) + +g2m_genes_mouse <- c( + "Hmgb2", "Cdk1", "Nusap1", "Ube2c", "Birc5", "Tpx2", "Top2a", + "Ndc80", "Cks2", "Nuf2", "Cks1b", "Mki67", "Ckap2l", "Ckap2", + "Aurkb", "Bub1", "Kif11", "Anp32e", "Tubb4b", "Gtse1", "Kif20b", + "Hjurp", "Cdca3", "Hn1", "Cdc20", "Ttk", "Cdc25c", "Kif2c", + "Rangap1", "Ncapd2", "Dlgap5", "Cdca2", "Cdca8", "Ect2", "Kif23", + "Hmmr", "Aurka", "Psrc1", "Anln", "Lbr", "Ckap5", "Cenpe", + "Ctcf", "Nek2", "G2e3", "Gas2l3", "Cbx5", "Cenpa" +) + +# Helper: compute mean z-scored module score per spot for a gene set. +# Works on a genes x spots matrix (dense or sparse). +# Returns a named numeric vector of length = ncol(mat). +compute_module_score <- function(mat, gene_set) { + genes_present <- intersect(gene_set, rownames(mat)) + if (length(genes_present) == 0) { + warning("No genes from gene set found in matrix.") + return(rep(NA_real_, ncol(mat))) + } + if (length(genes_present) < length(gene_set)) { + message(" Using ", length(genes_present), " / ", length(gene_set), + " genes from gene set.") + } + sub_mat <- as.matrix(mat[genes_present, , drop = FALSE]) + # Row-wise z-score (across spots), then average per spot + sub_z <- t(scale(t(sub_mat))) + sub_z[is.nan(sub_z)] <- 0 # genes with zero variance -> score 0 + colMeans(sub_z, na.rm = TRUE) +} + +s_score <- compute_module_score(merged_spatial_matrix, s_genes_mouse) +g2m_score <- compute_module_score(merged_spatial_matrix, g2m_genes_mouse) +cc_score <- s_score - g2m_score # signed cell-cycle activity index + + +# ---- Stress / Immediate-Early Gene Score--- +# Immediate-early response genes (Fos, Jun family, Hsps, Atf3, Ddit3) are +# strongly induced by dissociation stress and ambient RNA contamination. +# A high correlation between a pathway score and this module raises a red flag. + +stress_genes_mouse <- c( + # IEG + "Fos","Jun","Junb","Atf3","Egr1", + + # ER stress / UPR + "Ddit3","Atf4","Xbp1","Hspa5", + + # heat shock + "Hspa1a","Hspa1b","Hsp90aa1", + + # oxidative + "Gadd45a","Gadd45b","Gadd45g" +) + +stress_score <- compute_module_score(merged_spatial_matrix, stress_genes_mouse) + + +# --Assemble confounder data frame--- + +spot_names <- names(Wnt_score) # canonical spot order from PathwayEmbed scores + +confounder_df <- data.frame( + spot = spot_names, + # PathwayEmbed scores + Wnt = Wnt_score[spot_names], + TGFb = TGFb_score[spot_names], + HIf1a = HIf1a_score[spot_names], + Hippo = Hippo_score[spot_names], + Notch = Notch_score[spot_names], + # QC metrics + nCount = nCount[spot_names], + nFeature = nFeature[spot_names], + pct_mt = pct_mt[spot_names], + # Module scores + S_score = s_score[spot_names], + G2M_score = g2m_score[spot_names], + CC_score = cc_score[spot_names], + Stress = stress_score[spot_names], + row.names = spot_names, + stringsAsFactors = FALSE) +``` + +```{r echo=FALSE} +confounder_df <- readRDS(system.file("extdata", "confounder_df.rds", package = "PathwayEmbed")) +``` + +```{r} +pathway_cols <- c("Wnt", "TGFb", "HIf1a", "Hippo", "Notch") +confounder_cols <- c("nCount", "nFeature", "pct_mt", + "S_score", "G2M_score", "CC_score", "Stress") + +# Build a long-form correlation table +cor_rows <- lapply(pathway_cols, function(pw) { + lapply(confounder_cols, function(cov) { + complete_idx <- complete.cases(confounder_df[[pw]], confounder_df[[cov]]) + r <- cor(confounder_df[[pw]][complete_idx], + confounder_df[[cov]][complete_idx], + method = "spearman") + # Two-sided p-value via t-approximation (valid for large n) + n <- sum(complete_idx) + t_stat <- r * sqrt((n - 2) / (1 - r^2)) + pv <- 2 * pt(-abs(t_stat), df = n - 2) + data.frame(pathway = pw, covariate = cov, + spearman_r = round(r, 4), + p_value = pv, + n_spots = n, + stringsAsFactors = FALSE) + }) +}) +cor_table <- do.call(rbind, do.call(c, cor_rows)) + +# FDR correction across all pathway-covariate pairs +cor_table$p_adj_BH <- p.adjust(cor_table$p_value, method = "BH") +cor_table$significant <- cor_table$p_adj_BH < 0.05 +print(cor_table[, c("pathway", "covariate", "spearman_r", "p_adj_BH", "significant")]) + +cor_wide <- cor_table %>% + select(pathway, covariate, spearman_r) %>% + tidyr::pivot_wider(names_from = covariate, values_from = spearman_r) %>% + tibble::column_to_rownames("pathway") %>% + as.matrix() + +sig_wide <- cor_table %>% + select(pathway, covariate, significant) %>% + tidyr::pivot_wider(names_from = covariate, values_from = significant) %>% + tibble::column_to_rownames("pathway") %>% + as.matrix() + +# Build asterisk annotation matrix: * = FDR < 0.05, blank otherwise +annot_wide <- ifelse(sig_wide, "*", "") + +# Use corrplot for the heatmap (consistent with cross-pathway section) + +corrplot::corrplot( + cor_wide, + method = "color", + is.corr = FALSE, # raw values, not a correlation matrix + col = colorRampPalette(c("#2066a8", "white", "#ae282c"))(200), + cl.lim = c(-1, 1), + addCoef.col = "black", + number.cex = 0.7, + tl.col = "black", + tl.srt = 45, + title = "Pathway scores vs technical confounders (Spearman rho)", + mar = c(0, 0, 2, 0) +) + + + + +``` + diff --git a/vignettes/spatial_pathway_updated_files/figure-html/cross-pathway spearman correlation matrix-1.png b/vignettes/spatial_pathway_updated_files/figure-html/cross-pathway spearman correlation matrix-1.png new file mode 100644 index 0000000..33bb3d4 Binary files /dev/null and b/vignettes/spatial_pathway_updated_files/figure-html/cross-pathway spearman correlation matrix-1.png differ diff --git a/vignettes/spatial_pathway_updated_files/figure-html/plot local morans I-1.png b/vignettes/spatial_pathway_updated_files/figure-html/plot local morans I-1.png new file mode 100644 index 0000000..b59f081 Binary files /dev/null and b/vignettes/spatial_pathway_updated_files/figure-html/plot local morans I-1.png differ diff --git a/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-14-1.png b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-14-1.png new file mode 100644 index 0000000..371c88b Binary files /dev/null and b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-14-1.png differ diff --git a/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-1.png b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-1.png new file mode 100644 index 0000000..4714a37 Binary files /dev/null and b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-1.png differ diff --git a/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-2.png b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-2.png new file mode 100644 index 0000000..12380aa Binary files /dev/null and b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-2.png differ diff --git a/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-3.png b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-3.png new file mode 100644 index 0000000..ca774d0 Binary files /dev/null and b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-3.png differ diff --git a/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-4.png b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-4.png new file mode 100644 index 0000000..d569041 Binary files /dev/null and b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-4.png differ diff --git a/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-5.png b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-5.png new file mode 100644 index 0000000..2080534 Binary files /dev/null and b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-3-5.png differ diff --git a/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-1.png b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-1.png new file mode 100644 index 0000000..bf80757 Binary files /dev/null and b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-1.png differ diff --git a/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-2.png b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-2.png new file mode 100644 index 0000000..27cb725 Binary files /dev/null and b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-2.png differ diff --git a/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-3.png b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-3.png new file mode 100644 index 0000000..c1b7e1a Binary files /dev/null and b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-3.png differ diff --git a/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-4.png b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-4.png new file mode 100644 index 0000000..a9fc74b Binary files /dev/null and b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-4.png differ diff --git a/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-5.png b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-5.png new file mode 100644 index 0000000..7415878 Binary files /dev/null and b/vignettes/spatial_pathway_updated_files/figure-html/unnamed-chunk-7-5.png differ