PrevNext

Working With MDX

Author: Nathan Wang

Explanation of the frontmatter that precedes every module and solution, and a list of custom components that may be used within modules or solutions.

We're using MDX, a superset of Markdown, using the XDM compiler. HTML and React components are supported, so it is possible to add interactivity / custom components to each module.

Frontmatter

Frontmatter is the stuff in the beginning of each module that's surrounded by three dashes. Frontmatter is written in YAML. It stores the "metadata" for each module.

  • ID: Required. The ID of the module. Ex: getting-started, or containers. This ID is used to identify the module, so make sure it is unique and all lowercase with dashes only. The URL will be generated based off this.
  • Title: Required. The title of the module. Ex: Getting Started
  • Author: Required. The author of the module. Ex: Unknown
  • Contributors: Optional. The people who contributed code and/or short explanations to the module.
  • Description: Required. A short description of the module, similar to what codecademy has in their syllabus. Markdown/LaTeX does not work in the description field.
  • Prerequisites: Optional. Any prerequisites for this module. If you want to reference a module as a prerequisite, list it as a module ID. A link will be auto-generated.
  • Frequency: Optional. Takes a number 0-4 inclusive, where 0 = never shown up before and 4 = shows up ~once a contest. Leave this field out if you don't want to show the frequency.
  • Redirects: Optional. Takes a list of URLs that will redirect to the current module. Add a redirect whenever you change the module ID or move the module to a different division.

Example Frontmatter

---
id: getting-started
title: Getting Started
description: Welcome to the guide! We'll introduce what programming competitions are and how this guide is organized.
author: Nathan Wang
order: 1
prerequisites:
 - Dummy prerequisite
 - running-cpp
redirects:
  - /silver/bipartite
---

# Getting Started
...

Module Ordering

Located at content/ordering.ts, this file stores the ordering of the modules. The format should be self-explanatory (it matches based on the ID).

Linking to Modules

Linking to another module within the guide looks like this:

[insert text here](/general/practicing).

insert text here

Don't use relative links like practicing, as that will break our link checker.

Table of Contents

A table of contents will be auto-generated based off of the headings in the Markdown. Keep this in mind when formatting your module.

MDX and Custom Components

Optional: XDM and MDX

We use the XDM compiler, which has a few differences from MDX v1:

  • Markdown interleaved in JSX is fully supported; ie. this works as expected: <Info>some **markdown**</Info>
  • As an extension of (1), indentation is fully supported. You can indent the markdown nested in JSX tags. This also means that indenting text with four spaces doesn't make it a code block; explicitly wrap the code block with three backticks instead.
  • < and > need to be escaped with backslashes; ie. \<

Note that JSX comments ({/* ... */}) don't work well with Prettier, so use HTML comments instead. Internally we map HTML comments to JSX comments before passing the markdown to XDM. Don't worry if you don't understand all of this yet.

Some components are globally available in every module (without having to be imported):

  • <Spoiler>
  • <Info>
  • <Warning>
  • <Optional>
  • <Problems>
  • <FocusProblem>
  • <Resources>
  • <Resource>
  • <TextTooltip>
  • <LanguageSection>
  • <CPPSection>
  • <JavaSection>
  • <PySection>
  • <CPPOnly>
  • <JavaOnly>
  • <PyOnly>
  • <IncompleteSection>
  • <Asterisk>
  • <Quiz>

These are all documented below.

Spoilers

Spoilers are collapsible elements that only show themselves when the user clicks on it. It's useful when writing hints or solutions to problems. As a convention, we do not use spoilers for module solutions.

<Spoiler title="Show Hint">
- Insert hint here
</Spoiler>

Show Hint

Info Block

<Info title="Insert Title Here">
**Markdown is Supported!!**
</Info>

Insert Title Here

Markdown is Supported!!

Warning Block

<Warning title="Insert Title Here">
Fun fact: the title attribute is optional.
</Warning>

Warning: Insert Title Here

Fun fact: the title attribute is optional.

Optional Content

<Optional title="Insert Title Here">
Fun fact: the title attribute is optional.
</Optional>

Optional: Insert Title Here

Fun fact: the title attribute is optional.

Problem Lists

Each module has two corresponding files, a .mdx file and a .problems.json file. The .problems.json file stores the focus problems and problem lists used in that module; it is also indexed by Algolia for problem search.

The .problems.json file holds an object, where keys are problem list names (or focus problem names) and values are arrays of ProblemMetadata objects. For focus problems, the array should have length exactly one. Additionally, the .problems.json file should have a MODULE_ID key with value equal to a string that represents the module ID.

For more information on problem definitions, refer to src/models/problem.ts.

Example usage:

<Problems problems="problems" />

[module].problems.json should have a key of problems that maps to an array of ProblemMetadata.

There is a distinction between ProblemInfo and ProblemMetadata. ProblemMetadata is what is stored in [module].problems.json. Gatsby takes ProblemMetadata and converts it into ProblemInfo at build time; React components use ProblemInfo when interacting with problem information. The documentation below is for ProblemMetadata, which is what content authors will be writing.

ProblemMetadata fields:

uniqueId -- The uniqueId of the problem. Problem progress is linked to this, so don't change this (otherwise problem progress will be lost). By convention, it's [source]-[SlugifiedProblemNameCamelCased].

  • If the problem name is only one word, the word is lower cased.
  • If the problem is USACO or CSES, the unique ID is instead usaco-[USACO URL Number] or cses-[CSES number].
  • If the problem is Codeforces, the unique ID is cf-[contestNumber][problemLetter]. If it's CF Gym, it's cfgym-[gymNumber][problemLetter].
  • If the problem is an OI with a year, the unique ID is [oiName]-[twodigityear]-[slugifiedName].

Here are some example unique ID's:

cses-2177
poi-08-blockade
apio-18-duathlon
dmoj-investment
infoarena-xortransform
usaco-949
cses-1691
kattis-chineseremainder
cfgym-102538F
cf-1209H
spoj-LexicographicalStringSearch
ys-AssociativeArray

Problems with the same unique ID are expected to have identical names, sources, and URL's.

name -- The name of the problem. Should not include source.

Examples:

2009 - Beetle
Greedy Pie Eaters
Zuma
2014 - The Stables of Genghis Khan

source -- The source of the problem. Restricted to: todo, refer to src/models/problem.ts contests and probSources

difficulty -- The difficulty of the problem relative to the module it is in. Valid options are Very Easy, Easy, Normal, Hard, Very Hard, Insane

isStarred -- Whether this problem should be starred or not.

tags -- List of tags for this problem.

solutionMetadata -- Information about the solution.

export type ProblemMetadata = Omit<ProblemInfo, 'solution'> & {
  solutionMetadata:
    | {
        // auto generate problem solution label based off of the given site
        // For sites like Codeforces: "Check contest materials, located to the right of the problem statement."
        kind: 'autogen-label-from-site';
        // The site to generate it from. Sometimes this may differ from the source; for example, Codeforces could be the site while Baltic OI could be the source if Codeforces was hosting a Baltic OI problem.
        site: string;
      }
    | {
        // internal solution
        kind: 'internal';
      }
    | {
        // URL solution
        // Use this for links to PDF solutions, etc
        kind: 'link';
        url: string;
      }
    | {
        // Competitive Programming Handbook
        // Ex: 5.3 or something
        kind: 'CPH';
        section: string;
      }
    | {
        // USACO solution, generates it based off of the USACO problem ID
        // ex. 1113 is mapped to sol_prob1_gold_feb21.html
        kind: 'USACO';
        usacoId: string;
      }
    | {
        // IOI solution, generates it based off of the year
        // ex. Maps year = 2001 to https://ioinformatics.org/page/ioi-2001/27
        kind: 'IOI';
        year: number;
      }
    | {
        // no solution exists
        kind: 'none';
      }
    | {
        // for focus problems, when the solution is presented in the module of the problem
        kind: 'in-module';
        moduleId: string;
      }
    | {
        kind: 'sketch';
        sketch: string;
      };
};

Editorials are also written in MDX. The frontmatter has four fields:

---
id: cses-1621
source: CSES
title: Distinct Numbers
author: Nathan Wang
---

... solution

The ID of the solution frontmatter must be the same as the unique ID of the problem. Make sure to also update the kind of the solutionMetadata to 'internal' for any associated problems. We assume that if there is an internal solution, we should use it; therefore, the build will throw an error if there is an internal solution but the solutionMetadata's kind isn't set to

'internal'. The Adding Solutions module describes how to add a new solution.

Focus Problem

Displays a singular problem as a "focus problem."

<FocusProblem problem="genPermutations" />

[module].problems.json should have a key of genPermutations that maps to an array of length 1.

Resource Lists

<Resources>
  <Resource
    source="Errichto"
    title="Video - How to test your solution"
    url="https://www.youtube.com/watch?v=JXTVOyQpSGM"
    starred
  >
    using a script to stress test
  </Resource>
  ...
</Resources>
Resources
Errichto

using a script to stress test

Special functionality based on source:

  • If the source is a book, it'll automatically set the URL to point to the book.
    • Supported books:
      • GCP (Guide to Competitive Programming)
      • CPH (Competitive Programming Handbook)
      • PAPS (Principles of Algorithmic Problem Solving)
      • CP2 (Competitive Programming 2)
      • IUSACO (Darren's book; will auto-set URL based on user language; uses C++ for Python users)
  • Some sources will automatically have tooltips generated for them (listed here).

Tooltips

There are two main types of tooltips: text tooltips, which display a dotted underline under the text, and asterisk tooltips, which render an asterisk that can be hovered over.

<TextTooltip>

<TextTooltip content="Popup text goes here">short text goes here</TextTooltip>
short text goes here

<Asterisk>

<Asterisk>Popup text goes here</Asterisk>

Incomplete Section

<IncompleteSection>

- this list is optional and can be used to specify what is missing
- missing 32-bit integer explanation

</IncompleteSection>

This section is not complete.

Any help would be appreciated! Just submit a Pull Request on Github.
  • this list is optional and can be used to specify what is missing
  • missing 32-bit integer explanation

Code Blocks and Code Snippets

Code blocks are separated by three backticks, just like in normal markdown. Additionally, we have support for collapsible code snippets. An example for how to use them can be found below:

With title

// Before
// BeginCodeSnip{Optional Code Snippet Title}
// Code snippet goes here
// You can indent the entire BeginCodeSnip block (including the BeginCodeSnip line) and it will function as expected
// EndCodeSnip
// After
// Before
Code Snippet: Optional Code Snippet Title (Click to expand)

Without title:

// BeginCodeSnip{}
// My snippet code goes here
// EndCodeSnip
// My non-snippet code goes here
Code Snippet (Click to expand)
// My non-snippet code goes here

Some common snippets have shorthand notations, as defined in src/mdx-plugins/rehype-snippets.js. They can be accessed using CodeSnip{Snip ID}.

Kattio

CodeSnip{Kattio} gets replaced with an indented version (based off of indentation of CodeSnip):

import java.io.*;
import java.util.*;
public class myClass {
Code Snippet: Kattio (Click to expand)
public static void main...
}

C++ Short Template

CodeSnip{CPP Short Template} is replaced with

Code Snippet: C++ Short Template (Click to expand)

Language-Specific Content

<LanguageSection>
<CPPSection>
#### A heading that only appears in C++

```cpp
C++ code here
```

</CPPSection>
<JavaSection>
#### A heading that only appears in Java

```java
Java code here
```

</JavaSection>
<PySection />
</LanguageSection>

In the example above, nothing will be rendered for Python.

C++

A heading that only appears in C++

C++ code here

Java

A heading that only appears in Java

Java code here

Python

If you want to render content for only a single language, it is more convenient to use CPPOnly, JavaOnly, or PyOnly:

<CPPOnly>
#### A heading that only appears in C++

```cpp
C++ code here
```

</CPPOnly>

C++

A heading that only appears in C++

C++ code here

Java

Python

Quizzes

<Quiz>
	<Quiz.Question>
		Binary search

		<Quiz.Answer>
			$O(\log n)$

			<Quiz.Explanation>
				Almost. Prefer $\mathcal{O}$ over $O$.
			</Quiz.Explanation>
		</Quiz.Answer>

		<Quiz.Answer correct>
			$\mathcal{O}(\log n)$

			<Quiz.Explanation>
				That's correct!
			</Quiz.Explanation>
		</Quiz.Answer>
		<Quiz.Answer>
			O(log n)

			<Quiz.Explanation>
				That's not right. Latex is important...
			</Quiz.Explanation>
		</Quiz.Answer>
	</Quiz.Question>
	<Quiz.Question>
		```cpp
		for (int i = 0; i < 100; i++) {
			for (int j = 0; j < m; j++) {
				// constant time code here
			}
		}
		```

		<Quiz.Answer>
			$O(100m)$

			<Quiz.Explanation>
				That's not correct. Constant factors are ignored.
			</Quiz.Explanation>
		</Quiz.Answer>
		<Quiz.Answer correct>
			$O(m)$

			<Quiz.Explanation>
				That's correct!
			</Quiz.Explanation>
		</Quiz.Answer>
	</Quiz.Question>
</Quiz>

Binary search

Question 1 of 2

Module Progress:

Join the USACO Forum!

Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!

PrevNext