Compare commits
1 Commits
main
...
wharton-ce
Author | SHA1 | Date | |
---|---|---|---|
|
7706ddc76d |
1
Makefile
1
Makefile
@ -51,6 +51,7 @@ publish: build #> Publish site
|
||||
--safe-links \
|
||||
--times \
|
||||
--delete \
|
||||
--cvs-exclude \
|
||||
--chmod=D755,F644 \
|
||||
public/ \
|
||||
${DEST}
|
||||
|
@ -6,3 +6,7 @@ draft: false
|
||||
|
||||
Maybe I will add a brief bio. Until then, this is just a landing page for
|
||||
information about me.
|
||||
|
||||
{{< rawhtml >}}
|
||||
<a rel="me" href="https://mastodon.sdf.org/@axs">Mastodon</a>
|
||||
{{< /rawhtml >}}
|
||||
|
57
content/about/wharton.md
Normal file
57
content/about/wharton.md
Normal file
@ -0,0 +1,57 @@
|
||||
---
|
||||
title: 'Wharton CTO Program'
|
||||
date: 2024-09-08T10:47:47-07:00
|
||||
draft: true
|
||||
---
|
||||
|
||||
The [Chief Technology Officer
|
||||
Program](https://api.accredible.com/v1/credential-net/user_referrals/90db19b55d3d85f1319d31fe7aab9ff1/click)
|
||||
equips technology leaders with business context and skills that they need to effectively
|
||||
contribute to executive teams. I took program from
|
||||
the [University of Pennsylvania's](https://www.upenn.edu) [Wharton Business
|
||||
School](https://www.wharton.upenn.edu) between September 2023 and June 2024.
|
||||
|
||||
The structure was that of a core program plus three electives. Wharton awards a
|
||||
certificate for the successful completion of each of these elements.
|
||||
|
||||
I found this program to very helpful. I learned lots.
|
||||
|
||||
# CTO Core Program
|
||||
|
||||
The core program covered:
|
||||
|
||||
- Technology adoption
|
||||
- Alliances
|
||||
- Thing 3
|
||||
|
||||

|
||||
|
||||
# Scaling a Unicorn
|
||||
|
||||
The Scaling a Unicorn elective covered:
|
||||
|
||||
- Thing 1
|
||||
- Thing 2
|
||||
- Thing 3
|
||||
|
||||

|
||||
|
||||
# Driving Strategic Innovation
|
||||
|
||||
The Driving Strategic Innovation elective covered:
|
||||
|
||||
- Thing 1
|
||||
- Thing 2
|
||||
- Thing 3
|
||||
|
||||

|
||||
|
||||
The Es
|
||||
- Thing 1
|
||||
- Thing 2
|
||||
- Thing 3
|
||||
|
||||

|
@ -2,8 +2,6 @@
|
||||
title: Notes
|
||||
date: 2024-07-13T10:00:00-00:00
|
||||
draft: false
|
||||
xparams:
|
||||
math: true
|
||||
---
|
||||
|
||||
Public notes and guides.
|
||||
Public notes and guides for various topics.
|
||||
|
@ -1,41 +0,0 @@
|
||||
---
|
||||
title: Using HTML in Markdown
|
||||
date: 2025-02-25T21:21:21-08:00
|
||||
draft: false
|
||||
tags:
|
||||
- Writing
|
||||
- Markdown
|
||||
- HTML
|
||||
- Hugo
|
||||
---
|
||||
|
||||
Markdown uses punctuation-based syntax to format text, drawing inspiration from
|
||||
plain text email conventions. The goal is for Markdown documents to be easy to
|
||||
read. For concerns that the [specification](https://commonmark.org/) does not
|
||||
cover, users are free to use HTML. However, the HTML tags that rendering
|
||||
engines support vary considerably. Further, some rendering engines have their
|
||||
own approach to extensions, like
|
||||
[shortcodes](https://gohugo.io/content-management/shortcodes/) in Hugo.
|
||||
Generally, best practice is to avoid mixing Markdown and HTML, as doing so can
|
||||
detract from Markdown’s intended simplicity and readability.
|
||||
|
||||
The following items are exceptions to this rule—cases where HTML provides
|
||||
functionality or control that Markdown does not.
|
||||
|
||||
| HTML Tag(s) | Description | Notes |
|
||||
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------ |
|
||||
| `<details>` and `<summary>` | Create collapsible sections for hiding and revealing content. | [^HUGO] |
|
||||
| `<kbd>` | Represent keyboard inputs or shortcuts. | — |
|
||||
| `<abbr>` | Add tooltips to abbreviations for clarity. | [^NOHUGO] |
|
||||
| `<sup>` and `<sub>` | Format text as superscript or subscript. | — |
|
||||
| `<mark>` | Highlight text with a background color. | [^HUGO] |
|
||||
| `<!-- ... -->` (HTML Comments) | Insert comments that won’t appear in the rendered output. | [^HUGO] |
|
||||
| `<img>` | Embed images with enhanced control over attributes like class, style, width, and height. | — |
|
||||
| `<var>` | Represent variables, parameters, or mathematical symbols to add semantic clarity in technical documentation. | [^GH] |
|
||||
| `<samp>` | Denote sample output from programs or command-line operations, helping readers distinguish between code input and output. | [^GH] |
|
||||
|
||||
[^NOHUGO]: Not supported in Hugo.
|
||||
|
||||
[^HUGO]: Supported in Hugo, but may depend on the theme.
|
||||
|
||||
[^GH]: Not supported in GitHub
|
@ -1 +0,0 @@
|
||||
index.md
|
@ -1,107 +0,0 @@
|
||||
---
|
||||
title: Bayes' Theorem Expressed as Odds
|
||||
date: 2025-03-10T20:25:00-08:00
|
||||
draft: false
|
||||
tags:
|
||||
- Coup
|
||||
- US Politics
|
||||
- R
|
||||
- Bayes
|
||||
xparams:
|
||||
math: true
|
||||
share:
|
||||
- mastodon
|
||||
---
|
||||
|
||||
[Bayes' Theorem][wiki-bayes-theorem] is typically stated as:
|
||||
|
||||
\[
|
||||
P(A \mid E) = \frac{P(E \mid A) \, P(A)}{P(E \mid A) \, P(A) + P(E \mid \neg A) \, P(\neg A)}
|
||||
\]
|
||||
|
||||
This form explicitly shows all the pieces of Bayesian reasoning:
|
||||
|
||||
- The _posterior_ probability of the hypothesis \(A\), given evidence \(E\):
|
||||
\(P(A \mid E)\).
|
||||
|
||||
- The probability _prior_ to the evidence: \(P(A)\).
|
||||
|
||||
- The likelihood observing the evidence if the hypothesis is true:
|
||||
\(P(E \mid A)\).
|
||||
|
||||
- The likelihood observing the evidence if the hypothesis is _not_ true.
|
||||
Equivalently, the likelihood of observing the evidence if the
|
||||
_alternative_ hypothesis is true: \(P(E \mid \neg A)\).
|
||||
|
||||
However, the above form is not terribly convenient when making calculations
|
||||
over a series of events:
|
||||
|
||||
\[
|
||||
P(A \mid E_1, \dots, E_n) = \frac{P(E_1, \dots, E_n \mid A)\,P(A)}{P(E_1, \dots, E_n \mid A) \, P(A) + P(E_1, \dots, E_n \mid \neg A) \, P(\neg A)}
|
||||
\]
|
||||
|
||||
While we can calculate \(P(E_1, \dots, E_n)\) via successive substitutions,
|
||||
there is a more convenient approach. This involves transforming
|
||||
Bayes' Theorem as follows:
|
||||
|
||||
We start with the probability of the hypothesis (show above), and the
|
||||
probability of the complement, alternate hypothesis
|
||||
|
||||
\[
|
||||
P( \neg A \mid E_1, \dots, E_n) = \frac{P(E_1, \dots, E_n \mid \neg A)\,P( \neg
|
||||
A)}{P(E_1, \dots, E_n \mid \neg A) \, P(\neg A) + P(E_1, \dots, E_n \mid A) \, P(A)}
|
||||
\]
|
||||
|
||||
Assuming the pieces of evidence are _[conditionally
|
||||
independent][wiki-independence]_ given \(A\) (and similarly given \(\neg A\)),
|
||||
we can factorize the likelihood terms:
|
||||
|
||||
\[ P(E_1, \dots, E_n \mid A) = \prod_{i=1}^{n} P(E_i \mid A) \]
|
||||
|
||||
and
|
||||
|
||||
\[
|
||||
P(E_1, \dots, E_n \mid \neg A) = \prod_{i=1}^{n} P(E_i \mid \neg A).
|
||||
\]
|
||||
|
||||
Substitute these into the posterior odds:
|
||||
|
||||
\[
|
||||
\frac{P(A \mid E_1, \dots, E_n)}{P(\neg A \mid E_1, \dots, E_n)} = \frac{P(A)}{P(\neg A)} \prod_{i=1}^{n} \frac{P(E_i \mid A)}{P(E_i \mid \neg A)}.
|
||||
\]
|
||||
|
||||
Define the _prior [odds][wiki-odds]_, as:
|
||||
|
||||
\[
|
||||
O(A) = \frac{P(A)}{P(\neg A)}
|
||||
\]
|
||||
|
||||
and the [_likelihood ratio_][wiki-lr] for each piece of evidence \(E_i\) as:
|
||||
|
||||
\[
|
||||
\text{LR}_i = \frac{P(E_i \mid A)}{P(E_i \mid \neg A)}.
|
||||
\]
|
||||
|
||||
|
||||
Then, we write the _posterior odds_ and the posterior probability, our desired
|
||||
result, compactly as:
|
||||
|
||||
\[
|
||||
\begin{align}
|
||||
O(A \mid E_1, \dots, E_n) &= O(A) \prod_{i=1}^{n} \text{LR}_i, \\
|
||||
P(A \mid E_1, \dots, E_n) &= \frac{O(A \mid E_1, \dots, E_n)}{1 + O(A \mid E_1, \dots, E_n)}.
|
||||
\end{align}
|
||||
\]
|
||||
|
||||
Thus, we have a two-step process to compute the posterior probability:
|
||||
|
||||
1. Calculate the posterior odds as the prior odds times the product of the
|
||||
likelihood ratios.
|
||||
|
||||
2. Convert the odds to probabilities.
|
||||
|
||||
|
||||
[wiki-bayes-theorem]: https://en.wikipedia.org/wiki/Bayes%27_theorem
|
||||
[wiki-independence]: https://en.wikipedia.org/wiki/Conditional_independence
|
||||
[wiki-odds]: https://en.wikipedia.org/wiki/Odds
|
||||
[wiki-lr]: https://en.wikipedia.org/wiki/Likelihood_function#Likelihood_ratio
|
@ -1,275 +0,0 @@
|
||||
---
|
||||
title: 'Autogolpe Bayesian'
|
||||
date: 2025-02-24T20:17:01-08:00
|
||||
draft: true
|
||||
xparams:
|
||||
math: true
|
||||
---
|
||||
|
||||
We are six weeks into a presidential administration that is clearly making
|
||||
a break with past administrations. Many prominent observers like [Paul
|
||||
Krugman][PK] and [Robert Reich][RR] are calling this an authoritarian
|
||||
_autogolpe_, or self-coup. Of course, both of these observers are left of
|
||||
center, so being skeptical of these claims is a natural--and even
|
||||
prudent--reaction. After all, we have experienced 250 years of democratic
|
||||
government. On the other hand, maybe they are correct. Many of the stories
|
||||
company out of Washington seem alarming and the sheer number of stories is
|
||||
overwhelming. The Department of Government Efficiency (DOGE) shutting down
|
||||
agencies such as USAID. DOGE asking federal workers to justify the work they
|
||||
performed last week in an email or risk termination. Deciding how to think
|
||||
about this moment in light of emotionally charged claims and commentary is
|
||||
difficult. To not be sure what to think is completely understandable.
|
||||
|
||||
In this post, I will do my best to walk through this moment rationally. To do
|
||||
this, we will take a [Bayesian approach][Wiki-Bayesian]. I'll get into the
|
||||
details below, but for now think of Bayesian analysis gives a rigorous
|
||||
framework for combining disparate pieces of information. In this case, we will
|
||||
combine pieces of evidence that events support or refute the hypothesis that
|
||||
the administration is staging an autogolpe.
|
||||
|
||||
## Bayesian Overview
|
||||
|
||||
There are a few concepts that we need for this analysis. While the math might
|
||||
look fancy at first, all this is a series of probabilities, number that range
|
||||
between 0 (no change) and 1 (complete certainty).
|
||||
|
||||
- Initial probability of a coup in the United States. We can label this as
|
||||
\( P(A) \), where \(A\) is for autrocatic, self-coup or autogolpe. We label
|
||||
the probability of _not_ an autogolpe as \( P( \neg A ) \). We will refer
|
||||
to this initial probability as the _prior_ probability or just prior.
|
||||
|
||||
- Evidence that supports or refutes the conclusion that the administration
|
||||
is conducting an autogolpe. We think of evidence as objective and verifiable.
|
||||
For example, Trump posting a picture of himself as a king on Instagram.
|
||||
|
||||
- The probability that the evidence is consistent with an autogolpe,
|
||||
\( P( E \mid A) \). This is our _intrepration_ of the evidence. Our
|
||||
interpretation is inherentally _subjective_. Perhaps Trump was only
|
||||
joking when he made the Instagram post. Perhaps Trump was very serious.
|
||||
The point is that as ae outsider we can only interpret the evidence. That is
|
||||
to say, there is _uncertainty_. We use probability values to
|
||||
represent the uncertainty. This term is a _likelihood_.
|
||||
|
||||
- The probability that the evidence is consistent with business as usual.
|
||||
\( P( E \mid \neg A) \). This the alternative hypothesis, that we
|
||||
are not experiencing an autogolpe. We also refer to this term as a
|
||||
likelihood.
|
||||
|
||||
- The probability that we are in the middle of autogolpe given the evidence,
|
||||
\( P( A \mid E ) \). We call this the _posterior_ probability as this
|
||||
the probability after accounting for the evidence.
|
||||
|
||||
What we doing here is defining a framework for explicitly stating our beliefs.
|
||||
Prior to inauguration day, what was the probability that we would have an
|
||||
autogolpe in the United States? Maybe a 1% chance. That is, \( P( A ) \). How
|
||||
likely is it that the Instagram post implies an autogolpe? Maybe 70% chance.
|
||||
That is, \( P( E \mid A ) \).
|
||||
|
||||
Our last step is a way to put this information together. This is where we
|
||||
use the Bayesian approach is define that probability that the administration
|
||||
is staging an autogolpe as:
|
||||
|
||||
\[
|
||||
P(A \mid E) = \frac{P(E \mid A) \, P(A)}{P(E \mid A) \, P(A) + P(E \mid \neg A) \, P(\neg A)}
|
||||
\]
|
||||
|
||||
That is, the probability that we are experiencing an autogolpe is equal to
|
||||
a ratio. The numerator is the probability that the evidence is consistent with
|
||||
an autogolpe times our prior. The denominator is the sum of two quantities.
|
||||
The first is numerator and the second is probability that the evidence is
|
||||
_not_ consistent with an autogolpe times the 1 minus the prior. That is, the
|
||||
probability that we would _not_ have an autogolpe prior to the evidence.
|
||||
|
||||
With these quantities defined, let's work through a few examples to make this
|
||||
clear.
|
||||
|
||||
## Initial Example: Replacing Top Brass in the Military
|
||||
|
||||
To work an example, we need an initial probability that an autogolpe would
|
||||
happen in the United States. Prior to inauguration, we might have said a very
|
||||
small chance. The United States has gone almost 250 years without a coup, so
|
||||
the value should be low. There are recent example of a democratic government
|
||||
transforming into a dictatorship (e.g., Hungary), so the value should be not
|
||||
be zero. Let's say our prior probability, \( P(A) \), is 1%.
|
||||
|
||||
Next, let's assess one piece of evidence. The president the Secretary of
|
||||
Defense fired the Chairman of the Joint Chiefs of Staff, two Service Chairs,
|
||||
and three JAGS. There is precedent for firing the Chairman of the Joint Chiefs
|
||||
of Staff, for example Presidents Obama and Truman fired Generals McCrystal and
|
||||
MacCarther, respectively. However, there is not precedent for a mass firing of
|
||||
military leadership like this.
|
||||
|
||||
Under the hypothesis this that we are experiencing an autogolpe, the likelihood
|
||||
that we would see evidence like this is quite. Replacing top military officers
|
||||
is consistent with the behavior of an administration staging a coupe. So,
|
||||
let's say \( P( E \mid A ) = 0.9 \), or a 90% chance.
|
||||
|
||||
Under the alternate hypothesis that we are witnessing a coup, the probability
|
||||
of this event is rather low. Let's say \( P( E \mid \neg A ) = 0.05 \) or 5%
|
||||
chance.
|
||||
|
||||
We can put this together as
|
||||
|
||||
\[
|
||||
P(A \mid E) = \frac{0.9 \times 0.01}{0.9 \times 0.01 + 0.05 \times 0.99} \approx 0.15
|
||||
\]
|
||||
|
||||
or a 15% chance that the administration is staging an autogolpe.
|
||||
|
||||
|
||||
## Timeline of Evidence
|
||||
|
||||
```{r evidence, echo=FALSE, include=FALSE}
|
||||
library(tidyverse)
|
||||
knitr::opts_chunk$set(dev = 'svglite')
|
||||
|
||||
odds_prior <- 0.01
|
||||
|
||||
evidence <-
|
||||
tribble(
|
||||
~event, ~dtime, ~p_hypothesis, ~p_alternative,
|
||||
"Firing Inspector General", ymd("2025-01-24"), 0.9, 0.05,
|
||||
"Military", ymd("2025-02-23"), 0.9, 0.05,
|
||||
"Instagram King", ymd("2025-02-23"), 0.9, 0.05,
|
||||
) |>
|
||||
arrange(dtime) |>
|
||||
mutate(
|
||||
lr = p_hypothesis / p_alternative,
|
||||
lr_cum = cumprod(lr),
|
||||
odds_post = odds_prior * lr_cum,
|
||||
prob_post = odds_post / (1 + odds_post)
|
||||
)
|
||||
```
|
||||
|
||||
Let
|
||||
|
||||
[Bayes' Theorem as Odds]({{- relref "bayes-theorem-as-odds" -}})
|
||||
|
||||
|
||||
Firing Inspector Generals on
|
||||
`r evidence[evidence$event == "Firing Inspector Generals", "dtime"] |> pull()`:
|
||||
|
||||
- This
|
||||
- Sources: [PBS][PBS-IG]
|
||||
|
||||
Mass purging of civilian workers throughout the government
|
||||
|
||||
P(E1∣A)=0.90P(E1∣A)=0.90: If a self-coup is being attempted, a large-scale purge is highly likely.
|
||||
P(E1∣¬A)=0.05P(E1∣¬A)=0.05: In normal administrations, even with turnover, such a mass politically driven purge is very unlikely.
|
||||
Likelihood Ratio (LR11): 0.90/0.05=180.90/0.05=18.
|
||||
|
||||
Shutting Congressionally established agencies
|
||||
|
||||
P(E2∣A)=0.80P(E2∣A)=0.80: An authoritarian regime might seek to eliminate institutions that check its power.
|
||||
P(E2∣¬A)=0.01P(E2∣¬A)=0.01: Shutting down agencies that Congress has established is almost unheard of in standard governance.
|
||||
LR22: 0.80/0.01=800.80/0.01=80.
|
||||
|
||||
Appointing an FBI director that has vowed to hunt political enemies
|
||||
|
||||
P(E3∣A)=0.85P(E3∣A)=0.85: Under a self-coup scenario, appointing a politicized law enforcement head is very plausible.
|
||||
P(E3∣¬A)=0.02P(E3∣¬A)=0.02: Such an appointment would be extraordinarily unusual outside of an authoritarian context.
|
||||
LR33: 0.85/0.02≈42.50.85/0.02≈42.5.
|
||||
|
||||
Claiming only the president and the attorney general can interpret the law
|
||||
|
||||
P(E4∣A)=0.80P(E4∣A)=0.80: An authoritarian leader might openly claim such exclusive authority to undermine independent interpretation of laws.
|
||||
P(E4∣¬A)=0.05P(E4∣¬A)=0.05: In normal politics, such an overt claim is almost never made.
|
||||
LR44: 0.80/0.05=160.80/0.05=16.
|
||||
|
||||
Firing the Chairman of the Joint Chiefs of Staff
|
||||
|
||||
P(E5∣A)=0.75P(E5∣A)=0.75: Removing top military leadership can be a sign of consolidating control, especially if done for political reasons.
|
||||
P(E5∣¬A)=0.03P(E5∣¬A)=0.03: Although military leadership changes do occur, firing a long-established, nonpolitical figure for political reasons is very rare.
|
||||
LR55: 0.75/0.03=250.75/0.03=25.
|
||||
|
||||
Refusing to comply with several court orders
|
||||
|
||||
P(E6∣A)=0.90P(E6∣A)=0.90: An administration intent on a self-coup might ignore judicial rulings to eliminate checks on its power.
|
||||
P(E6∣¬A)=0.01P(E6∣¬A)=0.01: Refusal to comply with court orders is nearly unprecedented in a normally functioning government.
|
||||
LR66: 0.90/0.01=900.90/0.01=90.
|
||||
|
||||
Reworking the computing systems to give the White House stronger visibility and control
|
||||
|
||||
P(E7∣A)=0.70P(E7∣A)=0.70: While modern administrations update technology, doing so specifically to enhance control and surveillance is more likely if one is consolidating power.
|
||||
P(E7∣¬A)=0.10P(E7∣¬A)=0.10: There is a moderate chance that administrative modernization occurs for reasons unrelated to authoritarian control.
|
||||
LR77: 0.70/0.10=70.70/0.10=7.
|
||||
|
||||
Posting pictures of the president wearing a crown on the White House social media feeds
|
||||
|
||||
P(E8∣A)=0.70P(E8∣A)=0.70: Using provocative symbolism can be a tool to project a monarch-like or authoritarian image under a self-coup.
|
||||
P(E8∣¬A)=0.02P(E8∣¬A)=0.02: Such symbolic displays are extremely unusual in a normal democratic context.
|
||||
LR88: 0.70/0.02=350.70/0.02=35.
|
||||
|
||||
```{r evidence_tbl, echo=FALSE}
|
||||
|
||||
evidence |>
|
||||
select(
|
||||
event, dtime, p_hypothesis, p_alternative, lr
|
||||
) |>
|
||||
knitr::kable(
|
||||
col.names = c(
|
||||
"Event",
|
||||
"Date",
|
||||
"\\(P(E \\mid A)\\)",
|
||||
"\\(P(E \\mid \\neg A)\\)",
|
||||
"\\(LR\\)"
|
||||
),
|
||||
escape = FALSE
|
||||
)
|
||||
```
|
||||
|
||||
```{r post_tbl, echo=FALSE}
|
||||
|
||||
evidence |>
|
||||
select(
|
||||
event, dtime, odds_post, prob_post
|
||||
) |>
|
||||
knitr::kable(
|
||||
col.names = c(
|
||||
"Event",
|
||||
"Date",
|
||||
"Cumulative \\(O(A \\mid E)\\)",
|
||||
"Cumulative \\(P(A \\mid E)\\)"
|
||||
),
|
||||
escape = FALSE
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
In a plot:
|
||||
|
||||
```{r post_plot, echo=FALSE}
|
||||
|
||||
evidence |>
|
||||
arrange(dtime) |>
|
||||
ggplot(
|
||||
aes(x = dtime, y = prob_post)
|
||||
) +
|
||||
geom_line() +
|
||||
theme_minimal() +
|
||||
theme(
|
||||
plot.background = element_rect(fill = "transparent", color = NA),
|
||||
panel.background = element_rect(fill = "transparent", color = NA)
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
```{r init}
|
||||
prior <- 0.1
|
||||
prob_support <- 0.8
|
||||
prob_refute <- 0.05
|
||||
|
||||
( prob_support * prior ) / ( prob_support * prior + prob_refute * (1 - prior))
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
[PK]: https://paulkrugman.substack.com/p/autogolpe
|
||||
[RR]: https://robertreich.substack.com/p/say-what-it-is-a-coup
|
||||
[Wiki-Bayesian]: https://en.wikipedia.org/wiki/Bayesian_inference
|
||||
|
||||
[PBS-IG]: https://www.pbs.org/newshour/politics/trump-fires-more-than-a-dozen-independent-inspectors-general-at-government-agencies
|
77
hugo.yaml
77
hugo.yaml
@ -16,7 +16,7 @@ params:
|
||||
disableFingerprinting: true
|
||||
|
||||
# using Chroma highlighting...
|
||||
disableHLJS: true
|
||||
disableHLHS: true
|
||||
|
||||
# where to find articles
|
||||
# https://gohugo.io/functions/collections/where/#mainsections
|
||||
@ -63,36 +63,6 @@ params:
|
||||
- name: email
|
||||
url: "mailto:andrewjstryker@proton.me"
|
||||
|
||||
# sharing
|
||||
ShowShareButtons: true
|
||||
share:
|
||||
mastodon:
|
||||
include: true
|
||||
title: "Share on Mastodon"
|
||||
linkedin:
|
||||
include: false
|
||||
title: "Share on LinkedIn"
|
||||
url: "https://www.linkedin.com/shareArticle?mini=true&url={{ .pagePermalink | urlquery }}&title={{ .pageTitle | urlquery }}"
|
||||
twitter:
|
||||
include: false
|
||||
title: "Share on Twitter"
|
||||
url: "https://twitter.com/intent/tweet?text={{ .pageTitle | urlquery }}&url={{ .pagePermalink | urlquery }}"
|
||||
facebook:
|
||||
include: false
|
||||
title: "Share on Facebook"
|
||||
url: "https://www.facebook.com/sharer/sharer.php?u={{ .pagePermalink | urlquery }}"
|
||||
pinterest:
|
||||
include: false
|
||||
title: "Pin this on Pinterest"
|
||||
url: "https://pinterest.com/pin/create/button/?url={{ .pagePermalink | urlquery }}&description={{ .pageTitle | urlquery }}"
|
||||
whatsapp:
|
||||
include: false
|
||||
title: "Share on WhatsApp"
|
||||
url: "https://api.whatsapp.com/send?text={{ .pageTitle | urlquery }}%20{{ .pagePermalink | urlquery }}"
|
||||
|
||||
|
||||
tocWordCountThreshold: 300
|
||||
|
||||
markup:
|
||||
|
||||
# Chroma highlighting
|
||||
@ -104,35 +74,10 @@ markup:
|
||||
codeFences: true
|
||||
guessSyntax: true
|
||||
lineNos: true
|
||||
style: monokai
|
||||
#style: solarized-dark
|
||||
# noClasses: false
|
||||
# https://gohugo.io/content-management/syntax-highlighting/#generate-syntax-highlighter-css
|
||||
|
||||
goldmark:
|
||||
renderhooks:
|
||||
link:
|
||||
enableDefault: true
|
||||
extensions:
|
||||
passthrough:
|
||||
enable: true
|
||||
delimiters:
|
||||
block:
|
||||
- - \[
|
||||
- \]
|
||||
inline:
|
||||
- - \(
|
||||
- \)
|
||||
|
||||
permalinks:
|
||||
posts: "/:year/:month/:day/:slug/"
|
||||
|
||||
ignoreFiles:
|
||||
- \.Rmd$
|
||||
- \.Rmarkdown$
|
||||
- _cache$
|
||||
- \.knit\.md$
|
||||
- \.utf8\.md$
|
||||
style: solarized-dark
|
||||
# https://gohugo.io/getting-started/configuration-markup/#table-of-contents
|
||||
|
||||
# module:
|
||||
# imports:
|
||||
@ -146,6 +91,14 @@ menu:
|
||||
name: About
|
||||
url: /about/
|
||||
weight: 10
|
||||
#- identifier: categories
|
||||
# name: Categories
|
||||
# url: /categories/
|
||||
# weight: 20
|
||||
#- identifier: tags
|
||||
# name: Tags
|
||||
# url: /tags/
|
||||
# weight: 30
|
||||
- identifier: posts
|
||||
name: Posts
|
||||
url: /posts/
|
||||
@ -154,11 +107,3 @@ menu:
|
||||
name: Notes
|
||||
url: /notes/
|
||||
weight: 50
|
||||
- identifier: tags
|
||||
name: Tags
|
||||
url: /tags/
|
||||
weight: 90
|
||||
#- identifier: categories
|
||||
# name: Categories
|
||||
# url: /categories/
|
||||
# weight: 20
|
||||
|
@ -1,4 +0,0 @@
|
||||
{{ if .IsHome }}
|
||||
<!-- Mastodon verification link (visually hidden) -->
|
||||
<a rel="me" href="https://mastodon.sdf.org/@axs" style="position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap;"> </a>
|
||||
{{ end }}
|
@ -1,25 +0,0 @@
|
||||
<!-- Conditional TOC and post content -->
|
||||
{{ $threshold := .Site.Params.tocWordCountThreshold | default 300 }}
|
||||
{{ $showToc := false }}
|
||||
{{ if isset .Params "toc" }}
|
||||
{{ $showToc = .Params.xparams.toc }}
|
||||
{{ else }}
|
||||
{{ $wordCount := countwords .Content }}
|
||||
{{ $showToc = gt $wordCount $threshold }}
|
||||
{{ end }}
|
||||
|
||||
{{ if $showToc }}
|
||||
<nav class="table-of-contents">
|
||||
{{ .TableOfContents }}
|
||||
</nav>
|
||||
{{ end }}
|
||||
|
||||
<!-- KaTeX math -->
|
||||
{{ if .Params.xparams.math }}
|
||||
{{ partialCached "math.html" . }}
|
||||
{{ end }}
|
||||
|
||||
<!-- Mermaid diagrams -->
|
||||
{{ if .Params.xparams.mermaid }}
|
||||
{{ partialCached "mermaid.html" . }}
|
||||
{{ end }}
|
@ -1,35 +0,0 @@
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.css"
|
||||
integrity="sha384-zh0CIslj+VczCZtlzBcjt5ppRcsAmDnRem7ESsYwWwg3m/OaJ2l4x7YBZl9Kxxib"
|
||||
crossorigin="anonymous"
|
||||
>
|
||||
<script
|
||||
defer
|
||||
src="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.js"
|
||||
integrity="sha384-Rma6DA2IPUwhNxmrB/7S3Tno0YY7sFu9WSYMCuulLhIqYSGZ2gKCJWIqhBWqMQfh"
|
||||
crossorigin="anonymous">
|
||||
</script>
|
||||
<script
|
||||
defer
|
||||
src="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/contrib/auto-render.min.js"
|
||||
integrity="sha384-hCXGrW6PitJEwbkoStFjeJxv+fSOOQKOPbJxSfM6G5sWZjAyWhXiTIIAmQqnlLlh"
|
||||
crossorigin="anonymous"
|
||||
onload="renderMathInElement(document.body);">
|
||||
</script>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: '\\[', right: '\\]', display: true}, // block
|
||||
{left: '\\(', right: '\\)', display: false}, // inline
|
||||
],
|
||||
throwOnError : false
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
.katex {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
</style>
|
@ -1,5 +0,0 @@
|
||||
<!-- Mermaid JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid@11.4.1/dist/mermaid.min.js"></script>
|
||||
<script>
|
||||
mermaid.initialize({ startOnLoad: true });
|
||||
</script>
|
@ -1,23 +0,0 @@
|
||||
{{- /* layouts/partials/share-platform-defaults.html */ -}}
|
||||
{{- $raw := .Site.Params.share | default (slice) -}}
|
||||
{{- $defaults := slice -}}
|
||||
{{- if reflect.IsSlice $raw -}}
|
||||
{{- /* If .Site.Params.share is a slice, iterate over items */ -}}
|
||||
{{- range $item := $raw -}}
|
||||
{{- if eq (printf "%T" $item) "string" -}}
|
||||
{{- $defaults = $defaults | append $item -}}
|
||||
{{- else -}}
|
||||
{{- /* If the item is a map, extract its "platform" key */ -}}
|
||||
{{- $defaults = $defaults | append $item.platform -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- else -}}
|
||||
{{- /* If .Site.Params.share is a map, iterate over keys */ -}}
|
||||
{{- range $platform, $settings := $raw -}}
|
||||
{{- if $settings.include -}}
|
||||
{{- $defaults = $defaults | append $platform -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- return $defaults -}}
|
||||
|
@ -1,4 +0,0 @@
|
||||
<a href="{{ .url }}" title="{{ .title }}" target="_blank">
|
||||
<span class="icon">{{ partial "svg.html" (dict "name" .platform) }}</span>
|
||||
</a>
|
||||
|
@ -1,35 +0,0 @@
|
||||
{{ $mastodonTitle := default "Share on Mastodon" .Site.Params.share.mastodon.title }}
|
||||
<a href="#"
|
||||
class="mastodon-share-link"
|
||||
title="{{ $mastodonTitle }}">
|
||||
<span class="icon">{{ partialCached "svg.html" (dict "name" "mastodon") "mastodon-icon" }}</span>
|
||||
</a>
|
||||
<script>
|
||||
document.querySelectorAll('.mastodon-share-link').forEach(function(el) {
|
||||
el.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const text = encodeURIComponent('{{ .pageTitle }}');
|
||||
const url = encodeURIComponent('{{ .pagePermalink }}');
|
||||
|
||||
// Define the Mastodon URI
|
||||
const mastodonUri = `web+mastodon://share?text=${text}%20${url}`;
|
||||
|
||||
// Fallback URL
|
||||
const fallbackUrl = `https://toot.kytta.dev/?text=${text}&url=${url}`;
|
||||
|
||||
// Attempt to open Mastodon client, fallback after 500ms
|
||||
const timeout = setTimeout(() => {
|
||||
window.open(fallbackUrl, '_blank', 'noopener');
|
||||
}, 500);
|
||||
|
||||
// Set window location to Mastodon client URI
|
||||
window.location.href = mastodonUri;
|
||||
|
||||
// If Mastodon client opens, cancel the fallback
|
||||
window.addEventListener('blur', () => {
|
||||
clearTimeout(timeout);
|
||||
}, {once: true});
|
||||
});
|
||||
});
|
||||
</script>
|
@ -1,27 +0,0 @@
|
||||
{{- /* layouts/partials/share-render.html */ -}}
|
||||
{{- $parent := . -}}
|
||||
{{- $platforms := .platforms -}}
|
||||
{{- $ctx := .context -}}
|
||||
{{- if gt (len $platforms) 0 -}}
|
||||
<div class="social-sharing">
|
||||
{{- range $platformName := $platforms -}}
|
||||
{{- $cfg := index $ctx.Site.Params.share $platformName | default dict -}}
|
||||
{{- /* Merge dynamic elements with the explicit configuration */ -}}
|
||||
{{- $merged := merge
|
||||
(dict
|
||||
"pageTitle" $ctx.Title
|
||||
"pagePermalink" $ctx.Permalink
|
||||
"platform" $platformName
|
||||
)
|
||||
$cfg
|
||||
-}}
|
||||
{{- $partialName := printf "share-platform-%s.html" $platformName -}}
|
||||
{{- if templates.Exists (printf "partials/%s" $partialName) -}}
|
||||
{{- partial $partialName $merged -}}
|
||||
{{- else -}}
|
||||
{{- partial "share-platform-generic.html" $merged -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{ partialCached "share-style" "share-style.html" "share-style" }}
|
||||
</div>
|
||||
{{- end -}}
|
@ -1,20 +0,0 @@
|
||||
<style>
|
||||
.social-sharing {
|
||||
text-align: center;
|
||||
margin-top: var(--gap);
|
||||
}
|
||||
.social-sharing a {
|
||||
display: inline-flex;
|
||||
padding: 10px;
|
||||
margin: 0 0.5rem;
|
||||
}
|
||||
.social-sharing .icon {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
fill: currentColor;
|
||||
transition: fill 0.3s;
|
||||
}
|
||||
.social-sharing a:hover .icon {
|
||||
fill: var(--primary);
|
||||
}
|
||||
</style>
|
@ -1,16 +0,0 @@
|
||||
{{- /* layouts/partials/share_icons.html */ -}}
|
||||
{{- /* Check if share sharing is explicitly disabled on this page */ -}}
|
||||
{{- if eq (.Params.xparams.share | default true) false -}}
|
||||
{{- return -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- /* Get the default list of share sharing platforms */ -}}
|
||||
{{- $platforms := partialCached "share-platform-defaults.html" . "defaultPlatforms" -}}
|
||||
|
||||
{{- /* Override default list if the page provides its own list */ -}}
|
||||
{{- $pageSocial := .Params.xparams.share | default (slice) -}}
|
||||
{{- if and $pageSocial (reflect.IsSlice $pageSocial) -}}
|
||||
{{- $platforms = $pageSocial -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- partial "share-render.html" (dict "platforms" $platforms "context" .) -}}
|
@ -1,6 +0,0 @@
|
||||
{{ $align := .Get "align" | default "center" }}
|
||||
<div style="text-align: {{ $align }};">
|
||||
<blockquote class="mastodon-embed" data-lang="en">
|
||||
<a href="{{ .Get 0 }}">View Mastodon Post</a>
|
||||
</blockquote>
|
||||
</div>
|
@ -1,6 +0,0 @@
|
||||
{{ $align := .Get "align" | default "center" }}
|
||||
<div style="text-align: {{ $align }};">
|
||||
<div class="mermaid">
|
||||
{{ .Inner | safeHTML }}
|
||||
</div>
|
||||
</div>
|
@ -1,18 +0,0 @@
|
||||
{{ $align := .Get "align" | default "center" }}
|
||||
{{ $width := .Get "width" | default 640 }}
|
||||
{{ $height := .Get "height" | default 360 }}
|
||||
{{ $aspectRatio := mul (div (float $height) (float $width)) 100 }}
|
||||
|
||||
<div style="text-align: {{ $align }};">
|
||||
<div class="video-container" style="position: relative; padding-bottom: {{ printf "%.2f" $aspectRatio }}%; height: 0; overflow: hidden; max-width: {{ $width }}px;">
|
||||
<iframe
|
||||
src="https://player.vimeo.com/video/{{ .Get 0 }}"
|
||||
width="{{ $width }}"
|
||||
height="{{ $height }}"
|
||||
frameborder="0"
|
||||
allow="autoplay; fullscreen; picture-in-picture"
|
||||
allowfullscreen
|
||||
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;">
|
||||
</iframe>
|
||||
</div>
|
||||
</div>
|
@ -1,19 +0,0 @@
|
||||
{{ $align := .Get "align" | default "center" }}
|
||||
{{ $width := .Get "width" | default 560 }}
|
||||
{{ $height := .Get "height" | default 315 }}
|
||||
{{/* Calculate aspect ratio as a percentage. Convert to float for proper division. */}}
|
||||
{{ $aspectRatio := mul (div (float $height) (float $width)) 100 }}
|
||||
|
||||
<div style="text-align: {{ $align }};">
|
||||
<div class="video-container" style="position: relative; padding-bottom: {{ printf "%.2f" $aspectRatio }}%; height: 0; overflow: hidden; max-width: {{ $width }}px;">
|
||||
<iframe
|
||||
width="{{ $width }}"
|
||||
height="{{ $height }}"
|
||||
src="https://www.youtube.com/embed/{{ .Get 0 }}"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;">
|
||||
</iframe>
|
||||
</div>
|
||||
</div>
|
@ -1,2 +0,0 @@
|
||||
RewriteEngine Off
|
||||
DirectoryIndex index.html
|
@ -1 +1 @@
|
||||
Subproject commit e2e1011bdecaf84d59c70fa42ff3d2c29c537b65
|
||||
Subproject commit 9ea3bb0e1f3aa06ed7715e73b5fabb36323f7267
|
Loading…
x
Reference in New Issue
Block a user