beatrina 0.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/LICENSE +92 -0
  2. package/NOTICES +72 -0
  3. package/README.md +124 -0
  4. package/bin/beatrina.mjs +223 -0
  5. package/bin/cli.mjs +80 -0
  6. package/bin/failsafe.mjs +74 -0
  7. package/bin/identity.mjs +45 -0
  8. package/bin/prova-post.mjs +51 -0
  9. package/bin/sessions.mjs +95 -0
  10. package/bin/shortcut.mjs +151 -0
  11. package/bin/update-check.mjs +55 -0
  12. package/bin/upgrade.mjs +76 -0
  13. package/build-info.json +1 -0
  14. package/carmar_V0.8.6.html +1310 -0
  15. package/check/acceptance.mjs +278 -0
  16. package/check/session.mjs +215 -0
  17. package/engines/js/document-exec.mjs +82 -0
  18. package/engines/js/persist.mjs +214 -0
  19. package/engines/js/worker.mjs +424 -0
  20. package/engines/python/adapter.py +577 -0
  21. package/engines/python/analyze.py +814 -0
  22. package/engines/python/bootstrap.py +309 -0
  23. package/engines/python/dataview.py +735 -0
  24. package/engines/python/debugger.py +346 -0
  25. package/engines/python/document_exec.py +158 -0
  26. package/engines/python/engine.json +28 -0
  27. package/engines/python/handoff.py +118 -0
  28. package/engines/python/worker.py +564 -0
  29. package/engines/r/engine.json +25 -0
  30. package/engines/r/handoff.R +92 -0
  31. package/failsafe/ai-policy.R +255 -0
  32. package/failsafe/ai-store.R +373 -0
  33. package/failsafe/cite.R +418 -0
  34. package/failsafe/journal.R +684 -0
  35. package/failsafe/plugins.R +809 -0
  36. package/failsafe/serve.R +5500 -0
  37. package/host/ai-policy.mjs +218 -0
  38. package/host/deployment.mjs +160 -0
  39. package/host/engine-js.mjs +98 -0
  40. package/host/engine-pool.mjs +383 -0
  41. package/host/engine-python.mjs +228 -0
  42. package/host/engine-r.mjs +206 -0
  43. package/host/engine-stdio.mjs +401 -0
  44. package/host/journal-store.mjs +749 -0
  45. package/host/main.mjs +503 -0
  46. package/host/planes/README.md +41 -0
  47. package/host/planes/ai-store.mjs +327 -0
  48. package/host/planes/ai.mjs +467 -0
  49. package/host/planes/analyze.mjs +397 -0
  50. package/host/planes/cite.mjs +517 -0
  51. package/host/planes/files.mjs +0 -0
  52. package/host/planes/jobs.mjs +704 -0
  53. package/host/planes/journal.mjs +53 -0
  54. package/host/planes/latex.mjs +201 -0
  55. package/host/planes/mcp.mjs +493 -0
  56. package/host/planes/pair.mjs +325 -0
  57. package/host/planes/pipe-term.mjs +122 -0
  58. package/host/planes/plugins.mjs +112 -0
  59. package/host/planes/proc-tree.mjs +76 -0
  60. package/host/planes/sessions.mjs +434 -0
  61. package/host/planes/settings.mjs +164 -0
  62. package/host/planes/terminal.mjs +286 -0
  63. package/host/planes/test-file.mjs +80 -0
  64. package/host/planes/update.mjs +214 -0
  65. package/host/plugin-store.mjs +838 -0
  66. package/host/server.mjs +441 -0
  67. package/host/settings.mjs +379 -0
  68. package/host/update-record.mjs +59 -0
  69. package/host/user-dirs.mjs +117 -0
  70. package/host/windows-runtime.mjs +145 -0
  71. package/host/worker-plane.mjs +713 -0
  72. package/host/ws.mjs +190 -0
  73. package/kernel/analyze.R +668 -0
  74. package/kernel/deployment.R +165 -0
  75. package/kernel/examples/NOTICE.md +38 -0
  76. package/kernel/examples/tna-complete-tutorial.Rmd +210 -0
  77. package/kernel/fileio.R +656 -0
  78. package/kernel/index.html +96 -0
  79. package/kernel/job-run.R +391 -0
  80. package/kernel/jobs.R +276 -0
  81. package/kernel/kernel-protocol +1 -0
  82. package/kernel/kernel-version +1 -0
  83. package/kernel/kernel.R +671 -0
  84. package/kernel/knitr-run.R +245 -0
  85. package/kernel/latex.R +609 -0
  86. package/kernel/mcp/carmar-mcp.mjs +516 -0
  87. package/kernel/notebook-page.R +67 -0
  88. package/kernel/plugins/csl/apa/apa.csl +2273 -0
  89. package/kernel/plugins/csl/apa/plugin.json +19 -0
  90. package/kernel/plugins/csl/chicago-author-date/chicago-author-date.csl +4216 -0
  91. package/kernel/plugins/csl/chicago-author-date/plugin.json +19 -0
  92. package/kernel/plugins/csl/harvard-cite-them-right/harvard-cite-them-right.csl +316 -0
  93. package/kernel/plugins/csl/harvard-cite-them-right/plugin.json +19 -0
  94. package/kernel/plugins/csl/ieee/ieee.csl +519 -0
  95. package/kernel/plugins/csl/ieee/plugin.json +19 -0
  96. package/kernel/plugins/csl/modern-language-association/modern-language-association.csl +1184 -0
  97. package/kernel/plugins/csl/modern-language-association/plugin.json +19 -0
  98. package/kernel/plugins/csl/nature/nature.csl +189 -0
  99. package/kernel/plugins/csl/nature/plugin.json +19 -0
  100. package/kernel/plugins/latex/apa7/apa7.json +14 -0
  101. package/kernel/plugins/latex/apa7/plugin.json +19 -0
  102. package/kernel/plugins/latex/elsarticle/elsarticle.json +14 -0
  103. package/kernel/plugins/latex/elsarticle/plugin.json +19 -0
  104. package/kernel/plugins/latex/ieeetran/ieeetran.json +10 -0
  105. package/kernel/plugins/latex/ieeetran/plugin.json +19 -0
  106. package/kernel/project.R +131 -0
  107. package/kernel/settings.R +410 -0
  108. package/kernel/sniff.R +769 -0
  109. package/kernel/worker-boot.R +22 -0
  110. package/kernel/worker.R +3496 -0
  111. package/lib/agent-authoring-contract.js +547 -0
  112. package/lib/cell-kinds.js +108 -0
  113. package/lib/engine-labels.js +324 -0
  114. package/package.json +32 -0
@@ -0,0 +1,165 @@
1
+ # deployment.R — where this kernel listens, and who is allowed to reach it.
2
+ #
3
+ # CarmaR was written for exactly one deployment: a loopback socket serving one
4
+ # person on their own machine. Every trust rule in serve.R is an expression of
5
+ # that, and one of them INVERTS the moment the socket leaves loopback:
6
+ #
7
+ # a request with NO Origin header is currently allowed outright.
8
+ #
9
+ # On 127.0.0.1 that is correct and deliberate — no Origin means "not a
10
+ # browser", i.e. the launcher, R, curl, the MCP bridge, all of which are the
11
+ # same OS user, all of which could have run `Rscript` themselves. The socket
12
+ # grants them nothing they did not already have.
13
+ #
14
+ # On 0.0.0.0 the identical rule reads: `curl` from anywhere on the network may
15
+ # execute R as this user, without so much as a consent click. Same code, same
16
+ # header, opposite meaning — because the premise that "no Origin" implies
17
+ # "same user" was a fact about loopback, not a fact about HTTP.
18
+ #
19
+ # So this module computes the posture ONCE, at startup, and hands serve.R a
20
+ # decided answer rather than an environment variable to re-interpret at each
21
+ # call site. Everything here is pure: `env` is injected so the whole policy is
22
+ # testable without a server (test/deployment.test.mjs drives it through R).
23
+ #
24
+ # The refusals are the point. Binding off loopback is a deployment decision
25
+ # with consequences the operator must state out loud:
26
+ #
27
+ # · no CARMAR_HOSTS → refuse. An unset Host allow-list off
28
+ # loopback is a DNS-rebinding hole with the
29
+ # door held open.
30
+ # · no authentication in front → refuse, unless CARMAR_ALLOW_UNAUTHENTICATED
31
+ # is set. The variable is deliberately long
32
+ # and unpleasant to type; it is a decision,
33
+ # not a default.
34
+ #
35
+ # The intended P0 shape is one CarmaR per person, each as their own OS user on
36
+ # its own port, with TLS and login in a reverse proxy (Caddy + OIDC
37
+ # forward-auth). serve.R never sees a password; it trusts an identity header,
38
+ # and only from the proxy address. See docs/server.md.
39
+
40
+ `%||%` <- if (exists("%||%")) `%||%` else function(a, b) if (is.null(a)) b else a
41
+
42
+ LOOPBACK_HOSTS <- c("127.0.0.1", "::1", "[::1]", "localhost")
43
+
44
+ #' Split a comma/space-separated environment value into trimmed, non-empty parts.
45
+ split_list <- function(value) {
46
+ parts <- trimws(unlist(strsplit(value %||% "", "[,[:space:]]+")))
47
+ parts[nzchar(parts)]
48
+ }
49
+
50
+ #' Is this bind address one of the loopback literals?
51
+ #'
52
+ #' Deliberately a literal comparison and not a resolve: a NAME that currently
53
+ #' resolves to 127.0.0.1 is not the same promise as an address that cannot
54
+ #' leave the machine, and the whole point of the flag is that it cannot be
55
+ #' talked into being true.
56
+ is_loopback_bind <- function(bind) tolower(bind %||% "") %in% LOOPBACK_HOSTS
57
+
58
+ #' Compute the deployment posture from the environment.
59
+ #'
60
+ #' @param port the port the server will listen on.
61
+ #' @param env a getter with `Sys.getenv`'s signature; injected for tests.
62
+ #' @return a list with `bind`, `loopback`, `origins` (exact strings that may
63
+ #' open a socket with no consent click), `hosts` (accepted Host headers),
64
+ #' `allow_native` (may an Origin-less client connect?), `trust_proxy`,
65
+ #' `user_header`, `proxy_addrs`, and `errors` — a character vector that is
66
+ #' EMPTY when the posture is safe to serve. A non-empty `errors` must abort
67
+ #' startup; it is never a warning.
68
+ carmar_deployment <- function(port, env = Sys.getenv) {
69
+ bind <- trimws(env("CARMAR_BIND", "127.0.0.1"))
70
+ if (!nzchar(bind)) bind <- "127.0.0.1"
71
+ loopback <- is_loopback_bind(bind)
72
+
73
+ # The origin this kernel serves its own page from is always allowed: that is
74
+ # the same-origin case, and it is what `origin_ok` meant before this file
75
+ # existed. Off loopback the server is behind a proxy, so its own page
76
+ # arrives with the PROXY's origin — which the operator must name.
77
+ self_origins <- c(sprintf("http://%s:%d", bind, port),
78
+ sprintf("http://127.0.0.1:%d", port),
79
+ sprintf("http://localhost:%d", port))
80
+ origins <- unique(c(self_origins, split_list(env("CARMAR_ORIGINS", ""))))
81
+
82
+ hosts_env <- split_list(env("CARMAR_HOSTS", ""))
83
+ default_hosts <- c(sprintf("127.0.0.1:%d", port), sprintf("localhost:%d", port),
84
+ sprintf("[::1]:%d", port))
85
+ # A configured host may or may not carry a port. Accept both spellings so an
86
+ # operator writing `stats.example.edu` is not silently refused behind a proxy
87
+ # that forwards the default 80/443 and therefore sends no port at all.
88
+ hosts_env <- unique(c(hosts_env, ifelse(grepl(":", hosts_env, fixed = TRUE),
89
+ hosts_env,
90
+ sprintf("%s:%d", hosts_env, port))))
91
+ hosts <- tolower(unique(c(default_hosts, hosts_env)))
92
+
93
+ # "Anyone who reaches this port is this same OS user" is the premise behind
94
+ # allowing an Origin-less client, and binding off loopback is the obvious way
95
+ # to break it — but not the only one. A shared multi-user host, or a container
96
+ # whose 127.0.0.1 is port-forwarded out, breaks it while still binding
97
+ # loopback. So the posture is declarable in its own right and the bind
98
+ # address merely IMPLIES it; an operator hardening a shared machine does not
99
+ # have to move the socket to say so.
100
+ require_origin <- identical(env("CARMAR_REQUIRE_ORIGIN", ""), "1") || !loopback
101
+
102
+ trust_proxy <- identical(env("CARMAR_TRUST_PROXY", ""), "1")
103
+ user_header <- trimws(env("CARMAR_USER_HEADER", "X-Forwarded-User"))
104
+ proxy_addrs <- split_list(env("CARMAR_TRUSTED_PROXY", "127.0.0.1 ::1"))
105
+ allow_open <- identical(env("CARMAR_ALLOW_UNAUTHENTICATED", ""), "1")
106
+
107
+ errors <- character(0)
108
+ if (!loopback) {
109
+ if (!length(hosts_env)) {
110
+ errors <- c(errors, paste0(
111
+ "CARMAR_BIND is ", bind, " but CARMAR_HOSTS is unset. Off loopback the ",
112
+ "Host allow-list is the only defence against DNS rebinding, so it must ",
113
+ "name the hostname readers will use (e.g. CARMAR_HOSTS=stats.example.edu)."))
114
+ }
115
+ if (!trust_proxy && !allow_open) {
116
+ errors <- c(errors, paste0(
117
+ "CARMAR_BIND is ", bind, " with no authentication in front of it. Put ",
118
+ "CarmaR behind a reverse proxy that authenticates and set ",
119
+ "CARMAR_TRUST_PROXY=1, or set CARMAR_ALLOW_UNAUTHENTICATED=1 to serve R ",
120
+ "execution to everyone who can reach this port. See docs/server.md."))
121
+ }
122
+ if (trust_proxy && !nzchar(user_header)) {
123
+ errors <- c(errors, "CARMAR_TRUST_PROXY=1 requires a non-empty CARMAR_USER_HEADER.")
124
+ }
125
+ if (trust_proxy && !length(proxy_addrs)) {
126
+ errors <- c(errors, "CARMAR_TRUST_PROXY=1 requires CARMAR_TRUSTED_PROXY to name the proxy's address.")
127
+ }
128
+ }
129
+
130
+ list(
131
+ bind = bind,
132
+ port = port,
133
+ loopback = loopback,
134
+ origins = origins,
135
+ hosts = hosts,
136
+ # THE INVERSION. On a private loopback an absent Origin is a same-user
137
+ # native client and is allowed; anywhere the port is reachable by someone
138
+ # else it is an unauthenticated stranger and is not.
139
+ allow_native = !require_origin,
140
+ require_origin = require_origin,
141
+ trust_proxy = trust_proxy && require_origin,
142
+ user_header = user_header,
143
+ # httpuv's Rook environment spells a header `HTTP_` + uppercase, `-`→`_`.
144
+ user_header_key = paste0("HTTP_", toupper(gsub("-", "_", user_header, fixed = TRUE))),
145
+ proxy_addrs = proxy_addrs,
146
+ allow_unauthenticated = allow_open,
147
+ errors = errors)
148
+ }
149
+
150
+ #' Who is this request, according to the proxy in front of us?
151
+ #'
152
+ #' Returns "" unless the posture trusts a proxy AND the request actually came
153
+ #' from one of the named proxy addresses. That second half is what stops the
154
+ #' header being a self-service login: anyone who can reach the port directly
155
+ #' can set `X-Forwarded-User: root`, so the header is only ever as trustworthy
156
+ #' as the guarantee that nobody but the proxy can reach the port.
157
+ proxy_user <- function(req, deployment) {
158
+ if (!isTRUE(deployment$trust_proxy)) return("")
159
+ peer <- tolower(req$REMOTE_ADDR %||% "")
160
+ if (!nzchar(peer) || !(peer %in% tolower(deployment$proxy_addrs))) return("")
161
+ name <- req[[deployment$user_header_key]] %||% ""
162
+ # One line, printable, bounded — it reaches the audit log and the page title.
163
+ name <- gsub("[[:cntrl:]]", "", name)
164
+ trimws(substr(name, 1L, 128L))
165
+ }
@@ -0,0 +1,38 @@
1
+ # Test files shipped with CarmaR
2
+
3
+ ## tna-complete-tutorial.Rmd
4
+
5
+ "A showcase of the main tna functions" — the `complete_tutorial.Rmd` vignette of
6
+ the **tna** R package, copied unmodified.
7
+
8
+ - Source: https://github.com/sonsoleslp/tna/blob/main/vignettes/complete_tutorial.Rmd
9
+ - Revision: `5c08ec9dbed28d47f67f6c9c79e58aee152fcc9a` (2026-03-03)
10
+ - License: MIT (the package's DESCRIPTION: `MIT + file LICENSE`)
11
+
12
+ ```
13
+ YEAR: 2025-2026
14
+ COPYRIGHT HOLDER: tna authors
15
+ ```
16
+
17
+ MIT License
18
+
19
+ Copyright (c) 2025-2026 tna authors
20
+
21
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
22
+ this software and associated documentation files (the "Software"), to deal in
23
+ the Software without restriction, including without limitation the rights to
24
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
25
+ the Software, and to permit persons to whom the Software is furnished to do so,
26
+ subject to the following conditions:
27
+
28
+ The above copyright notice and this permission notice shall be included in all
29
+ copies or substantial portions of the Software.
30
+
31
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
33
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
34
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
35
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
36
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37
+
38
+ To run it, R needs the packages it loads: `tna`, `tibble`, `dplyr` and `gt`.
@@ -0,0 +1,210 @@
1
+ ---
2
+ title: "A showcase of the main tna functions"
3
+ output: rmarkdown::html_vignette
4
+ vignette: >
5
+ %\VignetteIndexEntry{A showcase of the main tna functions}
6
+ %\VignetteEngine{knitr::rmarkdown}
7
+ %\VignetteEncoding{UTF-8}
8
+ ---
9
+
10
+ ```{r, include = FALSE}
11
+ knitr::opts_chunk$set(
12
+ collapse = TRUE,
13
+ fig.width = 6,
14
+ fig.height = 4,
15
+ out.width = "100%",
16
+ dev = "jpeg",
17
+ dpi = 100,
18
+ comment = "#>"
19
+ )
20
+ suppressPackageStartupMessages({
21
+ library("tna")
22
+ library("tibble")
23
+ library("dplyr")
24
+ library("gt")
25
+ })
26
+ options(scipen = 99)
27
+ options(digits = 2)
28
+ options(max.print = 30)
29
+ options(width = 83)
30
+ ```
31
+
32
+
33
+ # Tutorial of TNA with R
34
+
35
+ This is a short tutorial of the `tna` package. We begin by loading the package and the example data set `group_regulation`.
36
+
37
+ ```{r}
38
+ library("tna")
39
+ data("group_regulation", package = "tna")
40
+ ```
41
+
42
+ ## Building `tna` Model
43
+
44
+ TNA models can be built with the `tna` function, which accepts several types of data such a sequence data, data frames or matrices.
45
+ ```{r, message = FALSE, results = FALSE}
46
+ model <- tna(group_regulation)
47
+ print(model)
48
+ ```
49
+
50
+
51
+ ## Plotting and interpreting `tna` models
52
+
53
+ ### Interpretation of the model
54
+
55
+ ```{r fig.height=6, fig.width=6, fig.align='center', layout = c(1,1)}
56
+ # TNA visualization
57
+ plot(model)
58
+ ```
59
+
60
+ ### Pruning and retaining edges that "matter"
61
+
62
+
63
+ ```{r, fig.show='hold', fig.width=5, fig.height=5 }
64
+ layout(matrix(1:4, ncol = 2, byrow = TRUE))
65
+ # Pruning with different methods (using comparable parameters)
66
+ pruned_threshold <- prune(model, method = "threshold", threshold = 0.15)
67
+ pruned_lowest <- prune(model, method = "lowest", lowest = 0.15)
68
+ pruned_disparity <- prune(model, method = "disparity", level = 0.5)
69
+
70
+ # Plotting for comparison
71
+ plot(pruned_threshold)
72
+ plot(pruned_lowest)
73
+ plot(pruned_disparity)
74
+ plot(model)
75
+ ```
76
+
77
+ ## Patterns
78
+
79
+ ```{r }
80
+ layout(t(1:2))
81
+ # Identify 2-cliques (dyads) from the TNA model, excluding loops in the visualization
82
+ # A clique of size 2 is essentially a pair of connected nodes
83
+ cliques_of_two <- cliques(
84
+ model,
85
+ size = 2,
86
+ threshold = 0.15 # Only consider edges with weight > 0.15
87
+ )
88
+ print(cliques_of_two)
89
+ plot(cliques_of_two, ask = FALSE)
90
+ ```
91
+
92
+ ```{r, fig.width=6,fig.height=2}
93
+ layout(t(1:3))
94
+ # Identify 3-cliques (triads) from the TNA_Model
95
+ # A clique of size 3 means a fully connected triplet of nodes
96
+ cliques_of_three <- cliques(
97
+ model,
98
+ size = 3,
99
+ threshold = 0.05 # Only consider edges with weight > 0.05
100
+ )
101
+ print(cliques_of_three)
102
+ plot(cliques_of_three, ask = FALSE)
103
+ ```
104
+
105
+ ```{r, fig.width=5}
106
+ # Identify 4-cliques (quadruples) from the TNA_Model
107
+ # A clique of size 4 means four nodes that are all mutually connected
108
+ cliques_of_four <- cliques(
109
+ model,
110
+ size = 4,
111
+ threshold = 0.035 # Only consider edges with weight > 0.03
112
+ )
113
+ print(cliques_of_four)
114
+ plot(cliques_of_four, ask = FALSE)
115
+ ```
116
+
117
+
118
+ ### Centralities
119
+
120
+ #### Node-level measures
121
+
122
+ ```{r fig.height=8, fig.width=8, fig.align='center'}
123
+ # Compute centrality measures for the TNA model
124
+ Centralities <- centralities(model)
125
+
126
+ # Visualize the centrality measures
127
+ plot(Centralities)
128
+ ```
129
+
130
+
131
+ ```{r}
132
+ # Calculate hub scores and the authority scores for the network
133
+ hits_scores <- igraph::hits_scores(as.igraph(model))
134
+ hub_scores <- hits_scores$hub
135
+ authority_scores <- hits_scores$authority
136
+
137
+ # Print the calculated hub and authority scores for further analysis
138
+ print(hub_scores)
139
+ print(authority_scores)
140
+ ```
141
+
142
+
143
+ #### Edge-level measures
144
+
145
+
146
+ ```{r, fig.align='center', fig.width=6, fig.height=5.5, out.width="60%"}
147
+ # Edge betweenness
148
+ Edge_betweeness <- betweenness_network(model)
149
+ plot(Edge_betweeness)
150
+ ```
151
+
152
+ ### Community finding
153
+
154
+ ```{r}
155
+ communities <- communities(model)
156
+ print(communities)
157
+ plot(communities, method = "leading_eigen")
158
+ ```
159
+
160
+ ## Network inference
161
+
162
+ ### Bootstrapping
163
+
164
+ ```{r}
165
+ # Perform bootstrapping on the TNA model with a fixed seed for reproducibility
166
+ set.seed(265)
167
+ boot <- bootstrap(model, threshold = 0.05)
168
+
169
+ # Print a summary of the bootstrap results
170
+ print(summary(boot))
171
+
172
+ # Show the non-significant edges (p-value >= 0.05 in this case)
173
+ # These are edges that are less likely to be stable across bootstrap samples
174
+ print(boot, type = "nonsig")
175
+ ```
176
+
177
+ ### Permutation
178
+
179
+ ```{r, fig.align='center', fig.width = 5, fig.height = 5, layout = c(1,1)}
180
+ # Create TNA for the high-achievers subset (rows 1 to 1000)
181
+ Hi <- tna(group_regulation[1:1000, ])
182
+
183
+ # Create TNA for the low-achievers subset (rows 1001 to 2000)
184
+ Lo <- tna(group_regulation[1001:2000, ])
185
+
186
+ # Plot a comparison of the "Hi" and "Lo" models
187
+ # The 'minimum' parameter is set to 0.001, so edges with weights >= 0.001 are shown
188
+ plot_compare(Hi, Lo, minimum = 0.01)
189
+
190
+ # Run a permutation test to determine statistical significance of differences
191
+ # between "Hi" and "Lo"
192
+ # The 'iter' argument is set to 1000, meaning 1000 permutations are performed
193
+ Permutation <- permutation_test(Hi, Lo, iter = 1000, measures = "Betweenness")
194
+
195
+ # Plot the significant differences identified in the permutation test
196
+ plot(Permutation, minimum = 0.01)
197
+ ```
198
+
199
+ ```{r}
200
+ print(Permutation$edges$stats)
201
+ print(Permutation$centralities$stats)
202
+ ```
203
+
204
+ ### Interpreting the Results of the Case-Dropping Bootstrap for Centrality Indices
205
+
206
+ ```{r, fig.align='center', fig.width=7, fig.height=4}
207
+ # Results of the Case-Dropping Bootstrap for Centrality Indices
208
+ Centrality_stability <- estimate_centrality_stability(model, iter = 100)
209
+ plot(Centrality_stability)
210
+ ```