Something or other, whatever! Christian Lawson-Perfect's homepage 2026-04-07T15:01:25.487425Z Christian Lawson-Perfect https://somethingorotherwhatever.com/atom.xml Easter bunny surveillance https://somethingorotherwhatever.com/items/easter-bunny-surveillance 2026-04-04T16:53:07.532000Z A pretend 'app' I made to give the kids clues for their Easter egg hunt. Each sample is a short sound recording of something in the house.

]]>

A pretend 'app' I made to give the kids clues for their Easter egg hunt. Each sample is a short sound recording of something in the house.

]]>
Lawsolar-panelfect https://somethingorotherwhatever.com/items/lawsolar-panelfect 2026-03-29T14:47:40.865000Z A chart showing the status of our FoxESS solar panel and battery system. Needs an API token and device ID to work.

]]>

A chart showing the status of our FoxESS solar panel and battery system. Needs an API token and device ID to work.

]]>
DIG display screen https://somethingorotherwhatever.com/items/dig-display-screen 2026-03-24T10:05:28.121000Z A display screen for a Disability Interest Group conference stand.

]]>

A display screen for a Disability Interest Group conference stand.

]]>
Word domino maker https://somethingorotherwhatever.com/items/word-domino-maker 2026-02-23T10:49:12.927000Z A tool to make sets of dominoes with words on. My mum asked me to make a set of dominoes with words in French and English, which prompted a lot of maths thinking about whether you could make it work the same way as a standard set of dominoes.

]]>

A tool to make sets of dominoes with words on. My mum asked me to make a set of dominoes with words in French and English, which prompted a lot of maths thinking about whether you could make it work the same way as a standard set of dominoes.

]]>
Prime power factor graph https://somethingorotherwhatever.com/items/prime-power-factor-graph 2026-02-07T14:11:01.859000Z An attempt to draw the graph of natural numbers, where each number is linked to the result of dividing by its greatest prime power factor.

]]>

An attempt to draw the graph of natural numbers, where each number is linked to the result of dividing by its greatest prime power factor.

]]>
Number builder https://somethingorotherwhatever.com/items/number-builder 2026-02-06T07:51:57.546000Z How quickly can you get to the target number by building up from 1, using only arithmetic operations?

]]>

How quickly can you get to the target number by building up from 1, using only arithmetic operations?

]]>
Marking sets https://somethingorotherwhatever.com/items/marking-sets 2026-01-16T10:16:15.195000Z How should we mark (multi-)sets of objects given by the student?

]]>

How should we mark (multi-)sets of objects given by the student?

]]>
Random emoji https://somethingorotherwhatever.com/items/random-emoji 2026-01-15T12:23:23.118000Z A page which shows a randomly picked emoji.

]]>

From https://github.com/samhenrigold/emoji-metadata

Search for emoji

]]>
2026 memory https://somethingorotherwhatever.com/items/2026-memory 2026-01-01T08:43:19.824000Z A big matching pairs game with 2026 cards.

]]>

A big matching pairs game with 2026 cards.

]]>
Christmas clock https://somethingorotherwhatever.com/items/christmas-clock 2025-12-17T09:08:12.642000Z A clock for Christmas

]]>

A clock for Christmas

]]>
Proportional text https://somethingorotherwhatever.com/items/proportional-text 2025-12-12T14:55:54.061000Z Each character's size is proportional to its ASCII code.

]]>

Each character's size is proportional to its ASCII code.

]]>
Railway clock https://somethingorotherwhatever.com/items/railway-clock 2025-12-10T08:20:09.554000Z A pure CSS copy of the new Network Rail clock design.

]]>

A pure CSS copy of the new Network Rail clock design.

]]>
Triangulate π https://somethingorotherwhatever.com/items/triangulate 2025-12-04T14:09:39.117000Z Try your best to cover a unit circle with triangles and it'll show you how close you got to π.

]]>

Try your best to cover a unit circle with triangles and it'll show you how close you got to π.

]]>
beachspectres.com https://somethingorotherwhatever.com/items/beachspectres-com 2025-11-23T00:00:00Z Information about the Beach Spectres project.

]]>

Information about the Beach Spectres project.

]]>
MathsJam 5 minute timer https://somethingorotherwhatever.com/items/mathsjam-5-minute-timer 2025-11-19T17:47:47.330000Z A 5 minute timer for talks at Big MathsJam.

]]>

A 5 minute timer for talks at Big MathsJam.

]]>
Fuzzy graph shader https://somethingorotherwhatever.com/items/fuzzy-graph-shader 2025-11-14T08:14:15.603000Z A shader which shows points 'close' to a function. Made as a proof of concept to show that a shader can be much faster than plain JavaScript.

]]>

A shader which shows points 'close' to a function. Made as a proof of concept to show that a shader can be much faster than plain JavaScript.

]]>
Colour shuffle https://somethingorotherwhatever.com/items/colour-shuffle 2025-11-06T07:35:28.399000Z Rotates the hues in the webcam image to help me see differences between colours.

]]>

Rotates the hues in the webcam image to help me see differences between colours.

]]>
Beach Spectre practise https://somethingorotherwhatever.com/items/beach-spectre-practise 2025-10-13T08:57:41.724000Z A tool to practise laying out the spectre tiling on a beach.

]]>

A tool to practise laying out the spectre tiling on a beach.

]]>
Payton Asch's Herschel enneahedron construction https://somethingorotherwhatever.com/items/payton-asch-s-herschel-enneahedron-construction 2025-10-02T05:36:41.404000Z Shows how to construct the Herschel enneahedron by truncating the middle of a triangular bipyramid.

]]>

Shows how to construct the Herschel enneahedron by truncating the middle of a triangular bipyramid.

]]>
Accessible conferences and events https://somethingorotherwhatever.com/items/accessible-conferences-and-events 2025-09-15T23:00:00Z Guidance and case studies on running academic events that are accessible and inclusive.

]]>

Guidance and case studies on running academic events that are accessible and inclusive.

]]>
Pixel counting fixed point finder https://somethingorotherwhatever.com/items/pixel-counting-fixed-point-finder 2025-07-30T23:00:00Z Tools to find images which describe how many black pixels they contain. Made for Matt Parker to accompany a video.

]]>

Tools to find images which describe how many black pixels they contain. Made for Matt Parker to accompany a video.

]]>
Talks about Numbas https://somethingorotherwhatever.com/items/talks-about-numbas 2025-07-22T14:19:42Z Talks and presentations about Numbas

]]>
reveal.js Build Status Slides

A framework for easily creating beautiful presentations using HTML. Check out the live demo.

reveal.js comes with a broad range of features including nested slides, Markdown contents, PDF export, speaker notes and a JavaScript API. There's also a fully featured visual editor and platform for sharing reveal.js presentations at slides.com.

Table of contents

More reading

  • Changelog: Up-to-date version history.
  • Examples: Presentations created with reveal.js, add your own!
  • Browser Support: Explanation of browser support and fallbacks.
  • Plugins: A list of plugins that can be used to extend reveal.js.

Online Editor

Presentations are written using HTML or Markdown but there's also an online editor for those of you who prefer a graphical interface. Give it a try at https://slides.com.

Instructions

Markup

Here's a barebones example of a fully working reveal.js presentation: ```html

Slide 1
Slide 2

```

The presentation markup hierarchy needs to be .reveal > .slides > section where the section represents one slide and can be repeated indefinitely. If you place multiple section elements inside of another section they will be shown as vertical slides. The first of the vertical slides is the "root" of the others (at the top), and will be included in the horizontal sequence. For example:

```html

Single Horizontal Slide
Vertical Slide 1
Vertical Slide 2

```

Markdown

It's possible to write your slides using Markdown. To enable Markdown, add the data-markdown attribute to your <section> elements and wrap the contents in a <textarea data-template> like the example below. You'll also need to add the plugin/markdown/marked.js and plugin/markdown/markdown.js scripts (in that order) to your HTML file.

This is based on data-markdown from Paul Irish modified to use marked to support GitHub Flavored Markdown. Sensitive to indentation (avoid mixing tabs and spaces) and line breaks (avoid consecutive breaks).

```html

```

External Markdown

You can write your content as a separate file and have reveal.js load it at runtime. Note the separator arguments which determine how slides are delimited in the external file: the data-separator attribute defines a regular expression for horizontal slides (defaults to ^\r?\n---\r?\n$, a newline-bounded horizontal rule) and data-separator-vertical defines vertical slides (disabled by default). The data-separator-notes attribute is a regular expression for specifying the beginning of the current slide's speaker notes (defaults to notes?:, so it will match both "note:" and "notes:"). The data-charset attribute is optional and specifies which charset to use when loading the external file.

When used locally, this feature requires that reveal.js runs from a local web server. The following example customises all available options:

```html

```

Element Attributes

Special syntax (through HTML comments) is available for adding attributes to Markdown elements. This is useful for fragments, amongst other things.

```html

```

Slide Attributes

Special syntax (through HTML comments) is available for adding attributes to the slide <section> elements generated by your Markdown.

```html

```

Configuring marked

We use marked to parse Markdown. To customise marked's rendering, you can pass in options when configuring Reveal:

javascript Reveal.initialize({ // Options which are passed into marked // See https://github.com/chjj/marked#options-1 markdown: { smartypants: true } });

Configuration

At the end of your page you need to initialize reveal by running the following code. Note that all configuration values are optional and will default to the values specified below.

```javascript Reveal.initialize({

// Display presentation control arrows
controls: true,

// Help the user learn the controls by providing hints, for example by
// bouncing the down arrow when they first encounter a vertical slide
controlsTutorial: true,

// Determines where controls appear, "edges" or "bottom-right"
controlsLayout: 'bottom-right',

// Visibility rule for backwards navigation arrows; "faded", "hidden"
// or "visible"
controlsBackArrows: 'faded',

// Display a presentation progress bar
progress: true,

// Display the page number of the current slide
slideNumber: false,

// Push each slide change to the browser history
history: false,

// Enable keyboard shortcuts for navigation
keyboard: true,

// Enable the slide overview mode
overview: true,

// Vertical centering of slides
center: true,

// Enables touch navigation on devices with touch input
touch: true,

// Loop the presentation
loop: false,

// Change the presentation direction to be RTL
rtl: false,

// Randomizes the order of slides each time the presentation loads
shuffle: false,

// Turns fragments on and off globally
fragments: true,

// Flags whether to include the current fragment in the URL,
// so that reloading brings you to the same fragment position
fragmentInURL: false,

// Flags if the presentation is running in an embedded mode,
// i.e. contained within a limited portion of the screen
embedded: false,

// Flags if we should show a help overlay when the questionmark
// key is pressed
help: true,

// Flags if speaker notes should be visible to all viewers
showNotes: false,

// Global override for autoplaying embedded media (video/audio/iframe)
// - null: Media will only autoplay if data-autoplay is present
// - true: All media will autoplay, regardless of individual setting
// - false: No media will autoplay, regardless of individual setting
autoPlayMedia: null,

// Number of milliseconds between automatically proceeding to the
// next slide, disabled when set to 0, this value can be overwritten
// by using a data-autoslide attribute on your slides
autoSlide: 0,

// Stop auto-sliding after user input
autoSlideStoppable: true,

// Use this method for navigation when auto-sliding
autoSlideMethod: Reveal.navigateNext,

// Specify the average time in seconds that you think you will spend
// presenting each slide. This is used to show a pacing timer in the
// speaker view
defaultTiming: 120,

// Enable slide navigation via mouse wheel
mouseWheel: false,

// Hides the address bar on mobile devices
hideAddressBar: true,

// Opens links in an iframe preview overlay
// Add `data-preview-link` and `data-preview-link="false"` to customise each link
// individually
previewLinks: false,

// Transition style
transition: 'slide', // none/fade/slide/convex/concave/zoom

// Transition speed
transitionSpeed: 'default', // default/fast/slow

// Transition style for full page slide backgrounds
backgroundTransition: 'fade', // none/fade/slide/convex/concave/zoom

// Number of slides away from the current that are visible
viewDistance: 3,

// Parallax background image
parallaxBackgroundImage: '', // e.g. "'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg'"

// Parallax background size
parallaxBackgroundSize: '', // CSS syntax, e.g. "2100px 900px"

// Number of pixels to move the parallax background per slide
// - Calculated automatically unless specified
// - Set to 0 to disable movement along an axis
parallaxBackgroundHorizontal: null,
parallaxBackgroundVertical: null,

// The display mode that will be used to show slides
display: 'block'

}); ```

The configuration can be updated after initialization using the configure method:

```javascript // Turn autoSlide off Reveal.configure({ autoSlide: 0 });

// Start auto-sliding every 5s Reveal.configure({ autoSlide: 5000 }); ```

Presentation Size

All presentations have a normal size, that is, the resolution at which they are authored. The framework will automatically scale presentations uniformly based on this size to ensure that everything fits on any given display or viewport.

See below for a list of configuration options related to sizing, including default values:

```javascript Reveal.initialize({

// ...

// The "normal" size of the presentation, aspect ratio will be preserved
// when the presentation is scaled to fit different resolutions. Can be
// specified using percentage units.
width: 960,
height: 700,

// Factor of the display size that should remain empty around the content
margin: 0.1,

// Bounds for smallest/largest possible scale to apply to content
minScale: 0.2,
maxScale: 1.5

}); ```

If you wish to disable this behavior and do your own scaling (e.g. using media queries), try these settings:

```javascript Reveal.initialize({

// ...

width: "100%",
height: "100%",
margin: 0,
minScale: 1,
maxScale: 1

}); ```

Dependencies

Reveal.js doesn't rely on any third party scripts to work but a few optional libraries are included by default. These libraries are loaded as dependencies in the order they appear, for example:

```javascript Reveal.initialize({ dependencies: [ // Cross-browser shim that fully implements classList - https://github.com/eligrey/classList.js/ { src: 'lib/js/classList.js', condition: function() { return !document.body.classList; } },

    // Interpret Markdown in <section> elements
    { src: 'plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
    { src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },

    // Syntax highlight for <code> elements
    { src: 'plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },

    // Zoom in and out with Alt+click
    { src: 'plugin/zoom-js/zoom.js', async: true },

    // Speaker notes
    { src: 'plugin/notes/notes.js', async: true },

    // MathJax
    { src: 'plugin/math/math.js', async: true }
]

}); ```

You can add your own extensions using the same syntax. The following properties are available for each dependency object: - src: Path to the script to load - async: [optional] Flags if the script should load after reveal.js has started, defaults to false - callback: [optional] Function to execute when the script has loaded - condition: [optional] Function which must return true for the script to be loaded

To load these dependencies, reveal.js requires head.js (a script loading library) to be loaded before reveal.js.

Ready Event

A ready event is fired when reveal.js has loaded all non-async dependencies and is ready to start navigating. To check if reveal.js is already 'ready' you can call Reveal.isReady().

javascript Reveal.addEventListener( 'ready', function( event ) { // event.currentSlide, event.indexh, event.indexv } );

Note that we also add a .ready class to the .reveal element so that you can hook into this with CSS.

Auto-sliding

Presentations can be configured to progress through slides automatically, without any user input. To enable this you will need to tell the framework how many milliseconds it should wait between slides:

javascript // Slide every five seconds Reveal.configure({ autoSlide: 5000 });

When this is turned on a control element will appear that enables users to pause and resume auto-sliding. Alternatively, sliding can be paused or resumed by pressing »A« on the keyboard. Sliding is paused automatically as soon as the user starts navigating. You can disable these controls by specifying autoSlideStoppable: false in your reveal.js config.

You can also override the slide duration for individual slides and fragments by using the data-autoslide attribute:

```html

After 2 seconds the first fragment will be shown.

After 10 seconds the next fragment will be shown.

Now, the fragment is displayed for 2 seconds before the next slide is shown.

```

To override the method used for navigation when auto-sliding, you can specify the autoSlideMethod setting. To only navigate along the top layer and ignore vertical slides, set this to Reveal.navigateRight.

Whenever the auto-slide mode is resumed or paused the autoslideresumed and autoslidepaused events are fired.

Keyboard Bindings

If you're unhappy with any of the default keyboard bindings you can override them using the keyboard config option:

javascript Reveal.configure({ keyboard: { 13: 'next', // go to the next slide when the ENTER key is pressed 27: function() {}, // do something custom when ESC is pressed 32: null // don't do anything when SPACE is pressed (i.e. disable a reveal.js default binding) } });

Touch Navigation

You can swipe to navigate through a presentation on any touch-enabled device. Horizontal swipes change between horizontal slides, vertical swipes change between vertical slides. If you wish to disable this you can set the touch config option to false when initializing reveal.js.

If there's some part of your content that needs to remain accessible to touch events you'll need to highlight this by adding a data-prevent-swipe attribute to the element. One common example where this is useful is elements that need to be scrolled.

Lazy Loading

When working on presentation with a lot of media or iframe content it's important to load lazily. Lazy loading means that reveal.js will only load content for the few slides nearest to the current slide. The number of slides that are preloaded is determined by the viewDistance configuration option.

To enable lazy loading all you need to do is change your src attributes to data-src as shown below. This is supported for image, video, audio and iframe elements. Lazy loaded iframes will also unload when the containing slide is no longer visible.

```html

```

API

The Reveal object exposes a JavaScript API for controlling navigation and reading state:

```javascript // Navigation Reveal.slide( indexh, indexv, indexf ); Reveal.left(); Reveal.right(); Reveal.up(); Reveal.down(); Reveal.prev(); Reveal.next(); Reveal.prevFragment(); Reveal.nextFragment();

// Randomize the order of slides Reveal.shuffle();

// Toggle presentation states, optionally pass true/false to force on/off Reveal.toggleOverview(); Reveal.togglePause(); Reveal.toggleAutoSlide();

// Shows a help overlay with keyboard shortcuts, optionally pass true/false // to force on/off Reveal.toggleHelp();

// Change a config value at runtime Reveal.configure({ controls: true });

// Returns the present configuration options Reveal.getConfig();

// Fetch the current scale of the presentation Reveal.getScale();

// Retrieves the previous and current slide elements Reveal.getPreviousSlide(); Reveal.getCurrentSlide();

Reveal.getIndices(); // { h: 0, v: 0, f: 0 } Reveal.getSlidePastCount(); Reveal.getProgress(); // (0 == first slide, 1 == last slide) Reveal.getSlides(); // Array of all slides Reveal.getTotalSlides(); // Total number of slides

// Returns the speaker notes for the current slide Reveal.getSlideNotes();

// State checks Reveal.isFirstSlide(); Reveal.isLastSlide(); Reveal.isOverview(); Reveal.isPaused(); Reveal.isAutoSliding(); ```

Custom Key Bindings

Custom key bindings can be added and removed using the following Javascript API. Custom key bindings will override the default keyboard bindings, but will in turn be overridden by the user defined bindings in the keyboard config option.

javascript Reveal.addKeyBinding( binding, callback ); Reveal.removeKeyBinding( keyCode );

For example

```javascript // The binding parameter provides the following properties // keyCode: the keycode for binding to the callback // key: the key label to show in the help overlay // description: the description of the action to show in the help overlay Reveal.addKeyBinding( { keyCode: 84, key: 'T', description: 'Start timer' }, function() { // start timer } )

// The binding parameter can also be a direct keycode without providing the help description Reveal.addKeyBinding( 82, function() { // reset timer } ) ```

This allows plugins to add key bindings directly to Reveal so they can

  • make use of Reveal's pre-processing logic for key handling (for example, ignoring key presses when paused); and
  • be included in the help overlay (optional)

Slide Changed Event

A slidechanged event is fired each time the slide is changed (regardless of state). The event object holds the index values of the current slide as well as a reference to the previous and current slide HTML nodes.

Some libraries, like MathJax (see #226), get confused by the transforms and display states of slides. Often times, this can be fixed by calling their update or render function from this callback.

javascript Reveal.addEventListener( 'slidechanged', function( event ) { // event.previousSlide, event.currentSlide, event.indexh, event.indexv } );

Presentation State

The presentation's current state can be fetched by using the getState method. A state object contains all of the information required to put the presentation back as it was when getState was first called. Sort of like a snapshot. It's a simple object that can easily be stringified and persisted or sent over the wire.

```javascript Reveal.slide( 1 ); // we're on slide 1

var state = Reveal.getState();

Reveal.slide( 3 ); // we're on slide 3

Reveal.setState( state ); // we're back on slide 1 ```

Slide States

If you set data-state="somestate" on a slide <section>, "somestate" will be applied as a class on the document element when that slide is opened. This allows you to apply broad style changes to the page based on the active slide.

Furthermore you can also listen to these changes in state via JavaScript:

javascript Reveal.addEventListener( 'somestate', function() { // TODO: Sprinkle magic }, false );

Slide Backgrounds

Slides are contained within a limited portion of the screen by default to allow them to fit any display and scale uniformly. You can apply full page backgrounds outside of the slide area by adding a data-background attribute to your <section> elements. Four different types of backgrounds are supported: color, image, video and iframe.

Color Backgrounds

All CSS color formats are supported, including hex values, keywords, rgba() or hsl().

```html

Color

```

Image Backgrounds

By default, background images are resized to cover the full page. Available options:

| Attribute | Default | Description | | :------------------------------- | :--------- | :---------- | | data-background-image | | URL of the image to show. GIFs restart when the slide opens. | | data-background-size | cover | See background-size on MDN. | | data-background-position | center | See background-position on MDN. | | data-background-repeat | no-repeat | See background-repeat on MDN. | | data-background-opacity | 1 | Opacity of the background image on a 0-1 scale. 0 is transparent and 1 is fully opaque. |

```html

Image

This background image will be sized to 100px and repeated

```

Video Backgrounds

Automatically plays a full size video behind the slide.

| Attribute | Default | Description | | :--------------------------- | :------ | :---------- | | data-background-video | | A single video source, or a comma separated list of video sources. | | data-background-video-loop | false | Flags if the video should play repeatedly. | | data-background-video-muted | false | Flags if the audio should be muted. | | data-background-size | cover | Use cover for full screen and some cropping or contain for letterboxing. | | data-background-opacity | 1 | Opacity of the background video on a 0-1 scale. 0 is transparent and 1 is fully opaque. |

```html

Video

```

Iframe Backgrounds

Embeds a web page as a slide background that covers 100% of the reveal.js width and height. The iframe is in the background layer, behind your slides, and as such it's not possible to interact with it by default. To make your background interactive, you can add the data-background-interactive attribute.

```html

Iframe

```

Background Transitions

Backgrounds transition using a fade animation by default. This can be changed to a linear sliding transition by passing backgroundTransition: 'slide' to the Reveal.initialize() call. Alternatively you can set data-background-transition on any section with a background to override that specific transition.

Parallax Background

If you want to use a parallax scrolling background, set the first two properties below when initializing reveal.js (the other two are optional).

```javascript Reveal.initialize({

// Parallax background image
parallaxBackgroundImage: '', // e.g. "https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg"

// Parallax background size
parallaxBackgroundSize: '', // CSS syntax, e.g. "2100px 900px" - currently only pixels are supported (don't use % or auto)

// Number of pixels to move the parallax background per slide
// - Calculated automatically unless specified
// - Set to 0 to disable movement along an axis
parallaxBackgroundHorizontal: 200,
parallaxBackgroundVertical: 50

}); ```

Make sure that the background size is much bigger than screen size to allow for some scrolling. View example.

Slide Transitions

The global presentation transition is set using the transition config value. You can override the global transition for a specific slide by using the data-transition attribute:

```html

This slide will override the presentation transition and zoom!

Choose from three transition speeds: default, fast or slow!

```

You can also use different in and out transitions for the same slide:

```html

The train goes on …
and on …
and stops.
(Passengers entering and leaving)
And it starts again.

`` You can choose fromnone,fade,slide,convex,concaveandzoom`.

Internal links

It's easy to link between slides. The first example below targets the index of another slide whereas the second targets a slide with an ID attribute (<section id="some-slide">):

html <a href="#/2/2">Link</a> <a href="#/some-slide">Link</a>

You can also add relative navigation links, similar to the built in reveal.js controls, by appending one of the following classes on any element. Note that each element is automatically given an enabled class when it's a valid navigation route based on the current slide.

html <a href="#" class="navigate-left"> <a href="#" class="navigate-right"> <a href="#" class="navigate-up"> <a href="#" class="navigate-down"> <a href="#" class="navigate-prev"> <!-- Previous vertical or horizontal slide --> <a href="#" class="navigate-next"> <!-- Next vertical or horizontal slide -->

Fragments

Fragments are used to highlight individual elements on a slide. Every element with the class fragment will be stepped through before moving on to the next slide. Here's an example: http://revealjs.com/#/fragments

The default fragment style is to start out invisible and fade in. This style can be changed by appending a different class to the fragment:

```html

grow

shrink

fade-out

fade-up (also down, left and right!)

fades in, then out when we move to the next step

fades in, then obfuscate when we move to the next step

blue only once

highlight-red

highlight-green

highlight-blue

```

Multiple fragments can be applied to the same element sequentially by wrapping it, this will fade in the text on the first step and fade it back out on the second.

```html

I'll fade in, then out

```

The display order of fragments can be controlled using the data-fragment-index attribute.

```html

Appears last

Appears first

Appears second

```

Fragment events

When a slide fragment is either shown or hidden reveal.js will dispatch an event.

Some libraries, like MathJax (see #505), get confused by the initially hidden fragment elements. Often times this can be fixed by calling their update or render function from this callback.

javascript Reveal.addEventListener( 'fragmentshown', function( event ) { // event.fragment = the fragment DOM element } ); Reveal.addEventListener( 'fragmenthidden', function( event ) { // event.fragment = the fragment DOM element } );

Code syntax highlighting

By default, Reveal is configured with highlight.js for code syntax highlighting. To enable syntax highlighting, you'll have to load the highlight plugin (plugin/highlight/highlight.js) and a highlight.js CSS theme (Reveal comes packaged with the zenburn theme: lib/css/zenburn.css).

javascript Reveal.initialize({ // More info https://github.com/hakimel/reveal.js#dependencies dependencies: [ { src: 'plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } }, ] });

Below is an example with clojure code that will be syntax highlighted. When the data-trim attribute is present, surrounding whitespace is automatically removed. HTML will be escaped by default. To avoid this, for example if you are using <mark> to call out a line of code, add the data-noescape attribute to the <code> element.

```html


(def lazy-fib
  (concat
   [0 1]
   ((fn rfib [a b]
        (lazy-cons (+ a b) (rfib b (+ a b)))) 0 1)))
    

```

Slide number

If you would like to display the page number of the current slide you can do so using the slideNumber and showSlideNumber configuration values.

```javascript // Shows the slide number using default formatting Reveal.configure({ slideNumber: true });

// Slide number formatting can be configured using these variables: // "h.v": horizontal . vertical slide number (default) // "h/v": horizontal / vertical slide number // "c": flattened slide number // "c/t": flattened slide number / total slides Reveal.configure({ slideNumber: 'c/t' });

// Control which views the slide number displays on using the "showSlideNumber" value: // "all": show on all views (default) // "speaker": only show slide numbers on speaker notes view // "print": only show slide numbers when printing to PDF Reveal.configure({ showSlideNumber: 'speaker' }); ```

Overview mode

Press »ESC« or »O« keys to toggle the overview mode on and off. While you're in this mode, you can still navigate between slides, as if you were at 1,000 feet above your presentation. The overview mode comes with a few API hooks:

```javascript Reveal.addEventListener( 'overviewshown', function( event ) { / ... / } ); Reveal.addEventListener( 'overviewhidden', function( event ) { / ... / } );

// Toggle the overview mode programmatically Reveal.toggleOverview(); ```

Fullscreen mode

Just press »F« on your keyboard to show your presentation in fullscreen mode. Press the »ESC« key to exit fullscreen mode.

Embedded media

Add data-autoplay to your media element if you want it to automatically start playing when the slide is shown:

```html

```

If you want to enable or disable autoplay globally, for all embedded media, you can use the autoPlayMedia configuration option. If you set this to true ALL media will autoplay regardless of individual data-autoplay attributes. If you initialize with autoPlayMedia: false NO media will autoplay.

Note that embedded HTML5 <video>/<audio> and YouTube/Vimeo iframes are automatically paused when you navigate away from a slide. This can be disabled by decorating your element with a data-ignore attribute.

Embedded iframes

reveal.js automatically pushes two post messages to embedded iframes. slide:start when the slide containing the iframe is made visible and slide:stop when it is hidden.

Stretching elements

Sometimes it's desirable to have an element, like an image or video, stretch to consume as much space as possible within a given slide. This can be done by adding the .stretch class to an element as seen below:

```html

This video will use up the remaining space on the slide

```

Limitations: - Only direct descendants of a slide section can be stretched - Only one descendant per slide section can be stretched

postMessage API

The framework has a built-in postMessage API that can be used when communicating with a presentation inside of another window. Here's an example showing how you'd make a reveal.js instance in the given window proceed to slide 2:

javascript <window>.postMessage( JSON.stringify({ method: 'slide', args: [ 2 ] }), '*' );

When reveal.js runs inside of an iframe it can optionally bubble all of its events to the parent. Bubbled events are stringified JSON with three fields: namespace, eventName and state. Here's how you subscribe to them from the parent window:

javascript window.addEventListener( 'message', function( event ) { var data = JSON.parse( event.data ); if( data.namespace === 'reveal' && data.eventName ==='slidechanged' ) { // Slide changed, see data.state for slide number } } );

This cross-window messaging can be toggled on or off using configuration flags.

```javascript Reveal.initialize({ // ...

// Exposes the reveal.js API through window.postMessage
postMessage: true,

// Dispatches all reveal.js events to the parent window through postMessage
postMessageEvents: false

}); ```

PDF Export

Presentations can be exported to PDF via a special print stylesheet. This feature requires that you use Google Chrome or Chromium and to be serving the presentation from a webserver. Here's an example of an exported presentation that's been uploaded to SlideShare: http://www.slideshare.net/hakimel/revealjs-300.

Separate pages for fragments

Fragments are printed on separate slides by default. Meaning if you have a slide with three fragment steps, it will generate three separate slides where the fragments appear incrementally.

If you prefer printing all fragments in their visible states on the same slide you can set the pdfSeparateFragments config option to false.

Page size

Export dimensions are inferred from the configured presentation size. Slides that are too tall to fit within a single page will expand onto multiple pages. You can limit how many pages a slide may expand onto using the pdfMaxPagesPerSlide config option, for example Reveal.configure({ pdfMaxPagesPerSlide: 1 }) ensures that no slide ever grows to more than one printed page.

Print stylesheet

To enable the PDF print capability in your presentation, the special print stylesheet at /css/print/pdf.css must be loaded. The default index.html file handles this for you when print-pdf is included in the query string. If you're using a different HTML template, you can add this to your HEAD:

```html

```

Instructions

  1. Open your presentation with print-pdf included in the query string i.e. http://localhost:8000/?print-pdf. You can test this with revealjs.com?print-pdf.
  2. If you want to include speaker notes in your export, you can append showNotes=true to the query string: http://localhost:8000/?print-pdf&showNotes=true
  3. Open the in-browser print dialog (CTRL/CMD+P).
  4. Change the Destination setting to Save as PDF.
  5. Change the Layout to Landscape.
  6. Change the Margins to None.
  7. Enable the Background graphics option.
  8. Click Save.

Chrome Print Settings

Alternatively you can use the decktape project.

Theming

The framework comes with a few different themes included:

  • black: Black background, white text, blue links (default theme)
  • white: White background, black text, blue links
  • league: Gray background, white text, blue links (default theme for reveal.js < 3.0.0)
  • beige: Beige background, dark text, brown links
  • sky: Blue background, thin dark text, blue links
  • night: Black background, thick white text, orange links
  • serif: Cappuccino background, gray text, brown links
  • simple: White background, black text, blue links
  • solarized: Cream-colored background, dark green text, blue links

Each theme is available as a separate stylesheet. To change theme you will need to replace black below with your desired theme name in index.html:

html <link rel="stylesheet" href="proxy.php?url=https%3A%2F%2Fsomethingorotherwhatever.com%2Fcss%2Ftheme%2Fblack.css" id="theme">

If you want to add a theme of your own see the instructions here: /css/theme/README.md.

Speaker Notes

reveal.js comes with a speaker notes plugin which can be used to present per-slide notes in a separate browser window. The notes window also gives you a preview of the next upcoming slide so it may be helpful even if you haven't written any notes. Press the »S« key on your keyboard to open the notes window.

A speaker timer starts as soon as the speaker view is opened. You can reset it to 00:00:00 at any time by simply clicking/tapping on it.

Notes are defined by appending an <aside> element to a slide as seen below. You can add the data-markdown attribute to the aside element if you prefer writing notes using Markdown.

Alternatively you can add your notes in a data-notes attribute on the slide. Like <section data-notes="Something important"></section>.

When used locally, this feature requires that reveal.js runs from a local web server.

```html

Some Slide

```

If you're using the external Markdown plugin, you can add notes with the help of a special delimiter:

```html

Title

Sub-title

Here is some content...

Note: This will only display in the notes window. ```

Share and Print Speaker Notes

Notes are only visible to the speaker inside of the speaker view. If you wish to share your notes with others you can initialize reveal.js with the showNotes configuration value set to true. Notes will appear along the bottom of the presentations.

When showNotes is enabled notes are also included when you export to PDF. By default, notes are printed in a semi-transparent box on top of the slide. If you'd rather print them on a separate page after the slide, set showNotes: "separate-page".

Speaker notes clock and timers

The speaker notes window will also show:

  • Time elapsed since the beginning of the presentation. If you hover the mouse above this section, a timer reset button will appear.
  • Current wall-clock time
  • (Optionally) a pacing timer which indicates whether the current pace of the presentation is on track for the right timing (shown in green), and if not, whether the presenter should speed up (shown in red) or has the luxury of slowing down (blue).

The pacing timer can be enabled by configuring by the defaultTiming parameter in the Reveal configuration block, which specifies the number of seconds per slide. 120 can be a reasonable rule of thumb. Timings can also be given per slide <section> by setting the data-timing attribute. Both values are in numbers of seconds.

Server Side Speaker Notes

In some cases it can be desirable to run notes on a separate device from the one you're presenting on. The Node.js-based notes plugin lets you do this using the same note definitions as its client side counterpart. Include the required scripts by adding the following dependencies:

```javascript Reveal.initialize({ // ...

dependencies: [
    { src: 'socket.io/socket.io.js', async: true },
    { src: 'plugin/notes-server/client.js', async: true }
]

}); ```

Then:

  1. Install Node.js (4.0.0 or later)
  2. Run npm install
  3. Run node plugin/notes-server

Multiplexing

The multiplex plugin allows your audience to view the slides of the presentation you are controlling on their own phone, tablet or laptop. As the master presentation navigates the slides, all client presentations will update in real time. See a demo at https://reveal-js-multiplex-ccjbegmaii.now.sh/.

The multiplex plugin needs the following 3 things to operate:

  1. Master presentation that has control
  2. Client presentations that follow the master
  3. Socket.io server to broadcast events from the master to the clients

Master presentation

Served from a static file server accessible (preferably) only to the presenter. This need only be on your (the presenter's) computer. (It's safer to run the master presentation from your own computer, so if the venue's Internet goes down it doesn't stop the show.) An example would be to execute the following commands in the directory of your master presentation:

  1. npm install node-static
  2. static

If you want to use the speaker notes plugin with your master presentation then make sure you have the speaker notes plugin configured correctly along with the configuration shown below, then execute node plugin/notes-server in the directory of your master presentation. The configuration below will cause it to connect to the socket.io server as a master, as well as launch your speaker-notes/static-file server.

You can then access your master presentation at http://localhost:1947

Example configuration:

```javascript Reveal.initialize({ // other options...

multiplex: {
    // Example values. To generate your own, see the socket.io server instructions.
    secret: '13652805320794272084', // Obtained from the socket.io server. Gives this (the master) control of the presentation
    id: '1ea875674b17ca76', // Obtained from socket.io server
    url: 'https://reveal-js-multiplex-ccjbegmaii.now.sh' // Location of socket.io server
},

// Don't forget to add the dependencies
dependencies: [
    { src: '//cdn.socket.io/socket.io-1.3.5.js', async: true },
    { src: 'plugin/multiplex/master.js', async: true },

    // and if you want speaker notes
    { src: 'plugin/notes-server/client.js', async: true }

    // other dependencies...
]

}); ```

Client presentation

Served from a publicly accessible static file server. Examples include: GitHub Pages, Amazon S3, Dreamhost, Akamai, etc. The more reliable, the better. Your audience can then access the client presentation via http://example.com/path/to/presentation/client/index.html, with the configuration below causing them to connect to the socket.io server as clients.

Example configuration:

```javascript Reveal.initialize({ // other options...

multiplex: {
    // Example values. To generate your own, see the socket.io server instructions.
    secret: null, // null so the clients do not have control of the master presentation
    id: '1ea875674b17ca76', // id, obtained from socket.io server
    url: 'https://reveal-js-multiplex-ccjbegmaii.now.sh' // Location of socket.io server
},

// Don't forget to add the dependencies
dependencies: [
    { src: '//cdn.socket.io/socket.io-1.3.5.js', async: true },
    { src: 'plugin/multiplex/client.js', async: true }

    // other dependencies...
]

}); ```

Socket.io server

Server that receives the slideChanged events from the master presentation and broadcasts them out to the connected client presentations. This needs to be publicly accessible. You can run your own socket.io server with the commands:

  1. npm install
  2. node plugin/multiplex

Or you can use the socket.io server at https://reveal-js-multiplex-ccjbegmaii.now.sh/.

You'll need to generate a unique secret and token pair for your master and client presentations. To do so, visit http://example.com/token, where http://example.com is the location of your socket.io server. Or if you're going to use the socket.io server at https://reveal-js-multiplex-ccjbegmaii.now.sh/, visit https://reveal-js-multiplex-ccjbegmaii.now.sh/token.

You are very welcome to point your presentations at the Socket.io server running at https://reveal-js-multiplex-ccjbegmaii.now.sh/, but availability and stability are not guaranteed.

For anything mission critical I recommend you run your own server. The easiest way to do this is by installing now. With that installed, deploying your own Multiplex server is as easy running the following command from the reveal.js folder: now plugin/multiplex.

socket.io server as file static server

The socket.io server can play the role of static file server for your client presentation, as in the example at https://reveal-js-multiplex-ccjbegmaii.now.sh/. (Open https://reveal-js-multiplex-ccjbegmaii.now.sh/ in two browsers. Navigate through the slides on one, and the other will update to match.)

Example configuration:

```javascript Reveal.initialize({ // other options...

multiplex: {
    // Example values. To generate your own, see the socket.io server instructions.
    secret: null, // null so the clients do not have control of the master presentation
    id: '1ea875674b17ca76', // id, obtained from socket.io server
    url: 'example.com:80' // Location of your socket.io server
},

// Don't forget to add the dependencies
dependencies: [
    { src: '//cdn.socket.io/socket.io-1.3.5.js', async: true },
    { src: 'plugin/multiplex/client.js', async: true }

    // other dependencies...
]

```

It can also play the role of static file server for your master presentation and client presentations at the same time (as long as you don't want to use speaker notes). (Open https://reveal-js-multiplex-ccjbegmaii.now.sh/ in two browsers. Navigate through the slides on one, and the other will update to match. Navigate through the slides on the second, and the first will update to match.) This is probably not desirable, because you don't want your audience to mess with your slides while you're presenting. ;)

Example configuration:

```javascript Reveal.initialize({ // other options...

multiplex: {
    // Example values. To generate your own, see the socket.io server instructions.
    secret: '13652805320794272084', // Obtained from the socket.io server. Gives this (the master) control of the presentation
    id: '1ea875674b17ca76', // Obtained from socket.io server
    url: 'example.com:80' // Location of your socket.io server
},

// Don't forget to add the dependencies
dependencies: [
    { src: '//cdn.socket.io/socket.io-1.3.5.js', async: true },
    { src: 'plugin/multiplex/master.js', async: true },
    { src: 'plugin/multiplex/client.js', async: true }

    // other dependencies...
]

}); ```

MathJax

If you want to display math equations in your presentation you can easily do so by including this plugin. The plugin is a very thin wrapper around the MathJax library. To use it you'll need to include it as a reveal.js dependency, find our more about dependencies here.

The plugin defaults to using LaTeX but that can be adjusted through the math configuration object. Note that MathJax is loaded from a remote server. If you want to use it offline you'll need to download a copy of the library and adjust the mathjax configuration value.

Below is an example of how the plugin can be configured. If you don't intend to change these values you do not need to include the math config object at all.

```js Reveal.initialize({ // other options ...

math: {
    mathjax: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js',
    config: 'TeX-AMS_HTML-full'  // See http://docs.mathjax.org/en/latest/config-files.html
},

dependencies: [
    { src: 'plugin/math/math.js', async: true }
]

}); ```

Read MathJax's documentation if you need HTTPS delivery or serving of specific versions for stability.

Installation

The basic setup is for authoring presentations only. The full setup gives you access to all reveal.js features and plugins such as speaker notes as well as the development tasks needed to make changes to the source.

Basic setup

The core of reveal.js is very easy to install. You'll simply need to download a copy of this repository and open the index.html file directly in your browser.

  1. Download the latest version of reveal.js from https://github.com/hakimel/reveal.js/releases
  2. Unzip and replace the example contents in index.html with your own
  3. Open index.html in a browser to view it

Full setup

Some reveal.js features, like external Markdown and speaker notes, require that presentations run from a local web server. The following instructions will set up such a server as well as all of the development tasks needed to make edits to the reveal.js source code.

  1. Install Node.js (4.0.0 or later)

  2. Clone the reveal.js repository sh $ git clone https://github.com/hakimel/reveal.js.git

  3. Navigate to the reveal.js folder sh $ cd reveal.js

  4. Install dependencies sh $ npm install

  5. Serve the presentation and monitor source files for changes sh $ npm start

  6. Open http://localhost:8000 to view your presentation

You can change the port by using npm start -- --port=8001.

Folder Structure

  • css/ Core styles without which the project does not function
  • js/ Like above but for JavaScript
  • plugin/ Components that have been developed as extensions to reveal.js
  • lib/ All other third party assets (JavaScript, CSS, fonts)

License

MIT licensed

Copyright (C) 2018 Hakim El Hattab, http://hakim.se

]]>
Webcam Julia fractal https://somethingorotherwhatever.com/items/webcam-julia-fractal 2025-06-29T17:47:55.476000Z Apply the Julia transform to the image from your webcam. It's horrible!

]]>

Apply the Julia transform to the image from your webcam. It's horrible!

]]>
Julia sets to Mandelbrot https://somethingorotherwhatever.com/items/julia-sets-to-mandelbrot 2025-06-27T23:00:00Z Shows how the Mandelbrot set relates to the Julia set. Made for Matt Parker.

]]>

Shows how the Mandelbrot set relates to the Julia set. Made for Matt Parker.

]]>
Julia and Mandelbrot side-by-side https://somethingorotherwhatever.com/items/julia-and-mandelbrot-side-by-side 2025-06-18T07:30:01.058000Z Shows the Mandelbrot and Julia sets side-by-side, so you can see how they relate to each other.

]]>

Shows the Mandelbrot and Julia sets side-by-side, so you can see how they relate to each other.

]]>
Irrational Collatz function https://somethingorotherwhatever.com/items/irrational-collatz-function 2025-06-06T09:51:40.344000Z A quick investigation of how the Collatz function works if you extend it to irrational numbers, rounding down to an integer before applying the test.

]]>

Irrational Collatz

Davide Rotondo asked SeqFan what happens if you apply the Collatz rule to the integer part of irrational numbers?

This plots the number of steps to get back to 1 for values in the chosen range.

]]>
Numberphile: The 9-sided Enneahedron https://somethingorotherwhatever.com/items/numberphile-the-9-sided-enneahedron 2025-06-01T23:00:00Z I told Brady Haran about the Herschel enneahedron.

]]>

I told Brady Haran about the Herschel enneahedron.

]]>
Integer credits sequence https://somethingorotherwhatever.com/items/integer-credits-sequence 2025-06-01T14:04:44.430000Z What if the factorisation of an integer was presented like the credits at the end of a movie?

]]>

What if the factorisation of an integer was presented like the credits at the end of a movie?

]]>
Knop's game https://somethingorotherwhatever.com/items/knop-s-game 2025-05-22T06:24:00.165000Z

A game discussed on SeqFans on 2025-05-21, attributed to Konstantin Knop:

You have an infinite row of cells numbered with the integers (open in both directions). In the starting position, you have N counters on cell 0. At each move, you pick a starting cell, and move K counters from that starting cell to the cell K steps either to the right or left. The object of the game is to finish with all N counters on cell 1 in the smallest possible number of moves.

]]>
Magic Knight's tour tool https://somethingorotherwhatever.com/items/magic-knight-s-tour-tool 2025-05-15T10:57:31.335000Z An interactive tool for making a magic knight's tour of a chessboard.

]]>

Knight's tour explorer

Made by Christian Lawson-Perfect in 2025 - https://somethingorotherwhatever.com

This is an Elm app. To rebuild this, use https://elm-lang.org/. The build command is elm make src/App.elm --output=app.js

The necessary files for use are:

  • index.html
  • style.css
  • app.js
  • load-app.js
]]>
Aperiodic monotile reference https://somethingorotherwhatever.com/items/aperiodic-monotile-reference 2025-05-07T14:53:35.848000Z A thing to help me lay out the Spectre aperiodic monotile tiling.

]]>

A thing to help me lay out the Spectre aperiodic monotile tiling.

]]>
Numeral conversion https://somethingorotherwhatever.com/items/numeral-conversion 2025-04-11T05:45:40.256000Z A page that renders your chosen number in as many numeral systems as it can.

]]>

A page that renders your chosen number in as many numeral systems as it can.

]]>
3D Herschel enneahedron https://somethingorotherwhatever.com/items/3d-herschel-enneahedron 2025-04-06T07:11:56.375000Z An interactive 3D rendering of the Herschel enneahedron

]]>

An interactive 3D rendering of the Herschel enneahedron

]]>
Colour vision deficiency simulator https://somethingorotherwhatever.com/items/colour-vision-deficiency-simulator 2025-04-04T06:10:14.151000Z A tool which shows roughly how a given image will look with different kinds of colour vision deficiency.

]]>

A tool which shows roughly how a given image will look with different kinds of colour vision deficiency.

]]>
Improving accessibility of teaching and assessment material in maths, stats and physics https://somethingorotherwhatever.com/items/improving-accessibility-of-teaching-and-assessment-material-in-maths-stats-and-physics 2025-03-21T09:45:01.186000Z A poster presented at Newcastle University's learning and teaching conference.

]]>

A poster presented at Newcastle University's learning and teaching conference.

]]>
Hilbert clock https://somethingorotherwhatever.com/items/hilbert-clock 2025-03-16T09:14:49.516000Z A clock where the 'hands' follow the Hilbert curve

]]>

A clock where the 'hands' follow the Hilbert curve

]]>
Roman coin converter https://somethingorotherwhatever.com/items/roman-coin-converter 2025-03-13T12:56:57.638000Z A tiny tool to convert between denominations of Roman coins.

]]>

A tiny tool to convert between denominations of Roman coins.

]]>
Accessible teaching for Maths, Stats and Physics https://somethingorotherwhatever.com/items/accessible-teaching-for-maths-stats-and-physics 2025-02-19T14:36:13Z Guidance on accessible teaching maths, stats and physics

]]>

Accessible teaching for maths, stats and physics

This document was made by Scarlett Spackman and Christian Lawson-Perfect as part of a Summer project in 2024.

Scarlett is an undergraduate MMath student leaving Stage 3.

Christian is a senior learning software developer in the digital learning unit.

The purpose of this page is to show the importance of implementing reasonable adjustments in response to student needs and to offer you practical guidance on how to implement these adjustments efficiently. We argue that adopting a more inclusive teaching style using universal design principles is a good place to start and that embracing these changes will foster a supportive and fair learning environment that empowers each student, disabled or not, to reach their maximum potential.

Building

This is a Chirun package.

Licence

This work © 2024 by Scarlett Spackman and Christian Lawson-Perfect for Newcastle University is licensed under CC BY 4.0 Creative Commons Attribution required.

]]>
Thomson problem https://somethingorotherwhatever.com/items/thomson-problem 2025-02-18T13:08:49.889000Z Made for Matt Parker. A visualisation of the Thomson problem - distributing points on a sphere to minimise the repulsion energy.

]]>

Made for Matt Parker. A visualisation of the Thomson problem - distributing points on a sphere to minimise the repulsion energy.

]]>
Sorting game https://somethingorotherwhatever.com/items/sorting-game 2025-02-17T09:46:41.118000Z A few variations on sorting things in space. I made this for Helen but she didn't like it.

]]>

A few variations on sorting things in space. I made this for Helen but she didn't like it.

]]>
Accessibility demo day https://somethingorotherwhatever.com/items/accessibility-demo-day 2025-02-13T10:58:41.935000Z Material made to support an event I ran at Newcastle University.

]]>

Material made to support an event I ran at Newcastle University.

]]>
Fontsource font picker https://somethingorotherwhatever.com/items/fontsource-font-picker 2025-02-11T10:45:51.244000Z A page to browse through all the fonts available on fontsource.com, and to fiddle with the variable axes.

]]>

A page to browse through all the fonts available on fontsource.com, and to fiddle with the variable axes.

]]>
CLP's map https://somethingorotherwhatever.com/items/clp-s-map 2025-02-03T13:43:56.350000Z A map just for me. I realised that there were things I wanted to remember about certain places, but generic map apps show too much other information. I can make markers for new places and add relevant links or text.

]]>

A map just for me. I realised that there were things I wanted to remember about certain places, but generic map apps show too much other information. I can make markers for new places and add relevant links or text.

]]>
CSS Quest https://somethingorotherwhatever.com/items/css-quest 2025-01-31T19:21:57.477000Z I thought it might be fun to make a text adventure game where you navigate by writing CSS selectors. If you write a selector that matches exactly one element, it's shown.

]]>
I thought it might be fun to make a text adventure game where you navigate by writing CSS selectors. If you write a selector that matches exactly one element, it's shown.

]]>
QR code generator https://somethingorotherwhatever.com/items/qr-code-generator 2025-01-30T13:04:06.722000Z ]]> Hilbert dots https://somethingorotherwhatever.com/items/hilbert-dots 2025-01-29T06:16:33.884000Z Animation of dots moving along a Hilbert curve.

]]>

Animation of dots moving along a Hilbert curve.

]]>
Train track game https://somethingorotherwhatever.com/items/train-track-game 2025-01-19T11:12:54.391000Z The idea was to make a puzzle out of directing tokens along a train track diagram. I got as far as trying it with arithmetic operations and didn't really like it. Something with generic symbols and some restriction on the order they go through vertices might work better, but would be work.

]]>

The idea was to make a puzzle out of directing tokens along a train track diagram. I got as far as trying it with arithmetic operations and didn't really like it. Something with generic symbols and some restriction on the order they go through vertices might work better, but would be work.

]]>
Monthly MathsJam dates https://somethingorotherwhatever.com/items/monthly-mathsjam-dates 2025-01-12T08:45:04.310000Z A table showing when the monthly MathsJams are, for each month of the year.

]]>

A table showing when the monthly MathsJams are, for each month of the year.

]]>
Tiling the plane with one of each n-gon https://somethingorotherwhatever.com/items/tiling-the-plane-with-one-of-each-n-gon 2025-01-07T09:37:07.493000Z An animation showing how you can cover the plane using only one of each n-gon.

]]>

An animation showing how you can cover the plane using only one of each n-gon.

]]>
Emoji search https://somethingorotherwhatever.com/items/emoji-search 2025-01-04T08:54:56.414000Z A quick page to find emoji matching a search word.

]]>

From https://github.com/samhenrigold/emoji-metadata

Search for emoji

]]>
Draggy road game https://somethingorotherwhatever.com/items/draggy-road-game 2025-01-01T10:20:03.882000Z I thought it'd be nice to make a game out of connecting different places with roads and building things. I couldn't decide how much resource management was fun.

]]>

I thought it'd be nice to make a game out of connecting different places with roads and building things. I couldn't decide how much resource management was fun.

]]>
Wobble block https://somethingorotherwhatever.com/items/wobble-block 2024-12-18T16:40:03.546000Z ]]> Aperiodic monotile hoodie designer https://somethingorotherwhatever.com/items/aperiodic-monotile-hoodie-designer 2024-12-02T10:53:58.921000Z A tool to design a an all-over printed hoodie using the Spectre aperiodic monotile.

]]>

A tool to design a an all-over printed hoodie using the Spectre aperiodic monotile.

]]>
Hex-grid wallpaper https://somethingorotherwhatever.com/items/hex-grid-wallpaper 2024-11-22T09:56:26.434000Z A pattern to print out on a big vinyl sticker, to use as a whiteboard in my office.

]]>

A pattern to print out on a big vinyl sticker, to use as a whiteboard in my office.

]]>
Wobble on a hex grid https://somethingorotherwhatever.com/items/wobble-on-a-hex-grid 2024-10-18T11:35:08.876000Z Recreating a design I saw made by someone else, but on a hex grid.

]]>

Recreating a design I saw made by someone else, but on a hex grid.

]]>
Mandelbrot fractal https://somethingorotherwhatever.com/items/mandelbrot-fractal 2024-10-10T07:01:18.926000Z A Mandelbrot fractal visualiser written using WebGL.

]]>

A Mandelbrot fractal visualiser written using WebGL.

]]>
Dynamic system dot plot https://somethingorotherwhatever.com/items/dynamic-system-dot-plot 2024-10-04T11:02:43.803000Z ]]> Explain this grid sequence https://somethingorotherwhatever.com/items/explain-this-grid-sequence 2024-09-11T15:05:19.858000Z Made to accompany a video about an integer sequence I came up with.

]]>

Made to accompany a video about an integer sequence I came up with.

]]>
Automatic colour palette maker https://somethingorotherwhatever.com/items/automatic-colour-palette-maker 2024-08-30T13:59:09.588000Z A tool I made to help think about how to make a customisable, accessible colour palette.

]]>

A tool I made to help think about how to make a customisable, accessible colour palette.

]]>
Which colours are similar? https://somethingorotherwhatever.com/items/which-colours-are-similar 2024-08-08T13:44:06.147000Z A tool which plots a list of colours on polar coordinates, to help spot similar colours.

]]>

A tool which plots a list of colours on polar coordinates, to help spot similar colours.

]]>
Entropy animation https://somethingorotherwhatever.com/items/entropy-animation 2024-07-25T13:31:07.283000Z An animation of text diffusing.

]]>

An animation of text diffusing.

]]>
Unicode scroll https://somethingorotherwhatever.com/items/unicode-scroll 2024-07-17T11:56:59.708000Z Another iteration in my ongoing exploration of the Unicode character set.

]]>

Another iteration in my ongoing exploration of the Unicode character set.

]]>
Big Internet Math-Off vote plot https://somethingorotherwhatever.com/items/big-internet-math-off-vote-plot 2024-07-01T09:40:11.116000Z A tool to plot the votes for each Big Internet Math-Off match, over time

]]>

A tool to plot the votes for each Big Internet Math-Off match, over time

]]>
Add a TeX command to MathJax v3 https://somethingorotherwhatever.com/items/add-a-tex-command-to-mathjax-v3 2024-06-17T11:06:20.692000Z Shows how to add a TeX comand to MathJax 3, which parses its (non-TeX) input and returns TeX code to go be substituted for the macro.

]]>

Shows how to add a TeX comand to MathJax 3, which parses its (non-TeX) input and returns TeX code to go be substituted for the macro.

Tooted: https://mathstodon.xyz/@christianp/112631902685965806

]]>
Can Elm make arbitrary HTML in a custom element? https://somethingorotherwhatever.com/items/can-elm-make-arbitrary-html-in-a-custom-element 2024-06-11T16:02:58Z I worked out how to put arbitrary HTML inside an Elm app, using a custom element

]]>

I've been wondering for a while how to put arbitrary HTML inside an Elm app.

I wondered if I could register a custom HTML element which takes a string of HTML code as an attribute, and sets the innerHTML of its shadow root to that code. The Elm app could then create an instance of that element and pass a string of HTML to it.

It works!

]]>
Numbas poster https://somethingorotherwhatever.com/items/numbas-poster 2024-05-22T14:11:08Z A poster about Numbas.

]]>

A poster about Numbas, an open-source e-assessment system.

It's designed to be printed at A2 size.

The file numbas-poster.svg is the source file; the PDF and PNG files are created from it.

This work is licensed under CC BY 4.0. You are free to share and adapt this poster under the terms of the CC BY 4.0 licence.

Numbas poster

]]>
Order those numbers! https://somethingorotherwhatever.com/items/order-those-numbers 2024-05-16T19:07:10Z You'll be shown five numbers, between 100 and 999. Try to guess what order the numbers will go in, from smallest to biggest.

]]>

You'll be shown five numbers, between 100 and 999. Try to guess what order the numbers will go in, from smallest to biggest.

]]>
Eukleides editor https://somethingorotherwhatever.com/items/eukleides-editor 2024-05-04T08:06:56.238000Z An editor for Eukleides diagrams.

]]>

An editor for Eukleides diagrams.

]]>
Embedded Numbas question https://somethingorotherwhatever.com/items/embedded-numbas-question 2024-04-30T07:59:03.262000Z Shows how to embed a Numbas question in a page using an iframe tag

]]>

Shows how to embed a Numbas question in a page using an iframe tag

]]>
JME calculator https://somethingorotherwhatever.com/items/jme-calculator 2024-04-19T12:03:55.832000Z A calculator that uses JME expressions.

]]>

A calculator which takes JME expressions.

]]>
SVG animation https://somethingorotherwhatever.com/items/svg-animation 2024-03-22T11:41:27.073000Z A simple spinner using the SVG animate tag

]]>

A simple spinner animation using the SVG <animate> tag.

]]>
Nudging along implicit curves https://somethingorotherwhatever.com/items/nudging-along-implicit-curves 2024-03-22T08:05:48.758000Z Inspired by work of Elliot Vez on nudging a point along an implicitly-defined curve.

]]>

Trying to replicate Elliot's thing to nudge a point along a curve.

]]>
Binary clock https://somethingorotherwhatever.com/items/binary-clock 2024-03-05T09:44:37.363000Z A clock with a hand for each power of two seconds.

]]>

A clock with a hand for each power of two seconds.

]]>
Binary letter search https://somethingorotherwhatever.com/items/binary-letter-search 2024-03-05T09:44:37.363000Z Letters are positioned on a binary tree. How quickly can you visit every letter?

]]>

Letters are positioned on a binary tree. How quickly can you visit every letter?

]]>
Dig a hole game https://somethingorotherwhatever.com/items/dig-a-hole-game 2024-03-05T09:44:37.363000Z I wanted to make a game where you have to think a bit, but not too much.

]]>

I wanted to make a game where you have to think a bit, but not too much.

]]>
Make numbers more exciting https://somethingorotherwhatever.com/items/make-numbers-more-exciting 2024-03-05T09:44:37.363000Z A button that takes a number and makes it more complicated by expanding it to a mathematical operation.

]]>

A button that takes a number and makes it more complicated by expanding it to a mathematical operation.

]]>
Metro info https://somethingorotherwhatever.com/items/metro-info 2024-03-05T09:44:37.363000Z A page to show the next train times for the Tyne and Wear Metro. I made this because the official app is rubbish.

]]>

JSON files:

lines.json Maps line names ("GREEN" or "YELLOW") to a list of stations along that line, with properties "key" (string) and "position" (list of two floats).

platforms.json From https://github.com/danielgjackson/metro-rti/blob/main/data/platforms.json Maps station keys to objects:

"platformNumber": int "direction": string, "IN" or "OUT" "helperText": string, readable description of the direction of travel

station-directions.json Maps station keys to a dictionary mapping platform numbers to the angle of that platform on the map.

station-positions.json Maps line names ("green" or "yellow") to a list of pairs of floats, giving the position on the map of each station on the line.

stations.json From https://github.com/danielgjackson/metro-rti/blob/main/data/stations.json Maps station keys to readable station names.

]]>
Numbas theme written in Elm https://somethingorotherwhatever.com/items/numbas-theme-written-in-elm 2024-03-05T09:44:37.363000Z I'm working on writing display code for Numbas in Elm. This page shows a demo exam.

]]>
I'm working on writing display code for Numbas in Elm. This page shows a demo exam.

]]>
Reverse the list of integers https://somethingorotherwhatever.com/items/reverse-the-list-of-integers 2024-03-05T09:44:37.363000Z A puzzle invented by Alexandre Muñiz where you have to reverse a list of integers with a constrained set of moves.

]]>

A game invented by Alexandre Muñiz: https://mathstodon.xyz/@two_star/112242224494626411

Here's a puzzle game. I call it Reverse the List of Integers. How it works is, you start with a list of positive integers, (e.g. [7, 5, 3]) and your goal is to make the same list, in reverse ([3, 5, 7]). You have two moves you can make:

1) Split an integer into two smaller integers. (e.g. [7, 5, 3] → [6, 1, 5, 3]) 2) Combine (add) two integers into a larger one. (e.g. reverse the last e.g.)

There are two restrictions that seem natural for making this into an interesting game:

1) You can never make an integer greater than the largest integer in the original list. 2) You can never make a move that results in the same integer appearing in the list more than once.

]]>
Unix epoch clock https://somethingorotherwhatever.com/items/unix-epoch-clock 2024-03-05T09:44:37.363000Z A clock which shows the unix epoch - the number of seconds since new year, 1970. There is a hand for each power of 10 seconds.

]]>

A clock which shows the unix epoch - the number of seconds since new year, 1970. There is a hand for each power of 10 seconds.

]]>
Think server https://somethingorotherwhatever.com/items/think-server 2024-03-04T15:05:19Z A server for my code experiments, like glitch.com but under my own control.

]]>
I've moved this repository to my code forge: https://code.lawson-perfect.uk/clp/thinkserver

]]>
Hyperjumps knockoff https://somethingorotherwhatever.com/items/hyperjumps-knockoff 2024-02-18T16:56:24Z An implementation of Quanta Magazine's Hyperjumps game. There was some discussion on the Talking Maths in Public group about how difficult to understand Quanta's presentation is.

]]>

An implementation of Quanta Magazine's Hyperjumps game. There was some discussion on the Talking Maths in Public group about how difficult to understand Quanta's presentation is.

]]>
How should I colour the days? https://somethingorotherwhatever.com/items/how-should-i-colour-the-days 2024-02-14T14:15:14.238000Z I'd like to colour the days of the year by changing the hue parameter of an oklch colour with the day of the year. How do I have to shift the number so that summer is reddish and winter is blueish?

]]>

I'd like to colour the days of the year by changing the hue parameter of an oklch colour with the day of the year. How do I have to shift the number so that summer is reddish and winter is blueish?

]]>
Tiny Elvis https://somethingorotherwhatever.com/items/tiny-elvis 2024-01-15T13:08:15Z A JavaScript port of the Tiny Elvis application, created in 1994 for Windows 3.1 by Matthew T. Smith

]]>

Tiny Elvis in JavaScript

Christian Lawson-Perfect (https://somethingorotherwhatever.com, [email protected]), 2024, based on the original by Matthew T. Smith for Pegasus Development, 1994.

Tiny Elvis was a Windows 3.1 program written by Matthew T. Smith. It placed a tiny pixel-art Elvis on your desktop, who would occasionally comment on the enormity of the things around him.

I've recreated Tiny Elvis as a web page, using the original art and sounds. The README says the program is in the public domain, but asks us to only distribute the original files without disassembling the executable. There's a vague bit saying it's OK to extract the icons.

I think that extracting the picture files 30 years later is probably OK, but to be safe the git repository only includes the files from the original zip package, along with a Makefile to extract the art and convert it to png format, using wrestool and imagemagick's convert command.

I didn't do anything with the Easter Egg messages which you could activate in the original by double-clicking the E icon in the "About Tiny Elvis" dialog.

To recreate the files after cloning the repository, run make extract_icons and then make default resources.

]]>
Colourblind palette maker https://somethingorotherwhatever.com/items/colourblind-palette-maker 2024-01-12T14:39:30.668000Z A tool to help me, with limited colour vision, make accessible colour palettes.

]]>

A tool to help me, with limited colour vision, make accessible colour palettes.

]]>
Randomised permutation chart curves https://somethingorotherwhatever.com/items/randomised-permutation-chart-curves 2024-01-10T13:06:30.199000Z Experimenting with how the curves joining points in a permutation chart are chosen.

]]>

Experimenting with how the curves joining points in a permutation chart are chosen.

]]>
Double Back https://somethingorotherwhatever.com/items/double-back 2023-12-12T16:01:52Z A puzzle where you have to reverse the order of two lines of numbered baubles. Invented by Ed Kirkby.

]]>

Double back

This is a puzzle invented by Ed Kirkby, and shown to me at MathsJam Gathering in 2022.

There's a blog post about it at https://aperiodical.com/2023/12/the-double-back-puzzle-is-a-nice-mix-of-towers-of-hanoi-and-solitaire/.

]]>
Wordy Christmas cards https://somethingorotherwhatever.com/items/wordy-christmas-cards 2023-12-11T15:02:35Z A tool to make art consisting of text drawn over an image, avoiding a mask drawn by hand. Heavily inspired by Litographs, made for Christmas cards in 2023.

]]>

A tool to make art consisting of text drawn over an image, avoiding a mask drawn by hand. Heavily inspired by Litographs, made for Christmas cards in 2023.

]]>
Clip my face https://somethingorotherwhatever.com/items/clip-my-face 2023-11-25T13:35:59.223000Z The beginnings of an idea about quickly cutting out sprites from a drawing. I used a photo of myself as a toddler as the test image.

]]>

The beginnings of an idea about quickly cutting out sprites from a drawing. I used a photo of myself as a toddler as the test image.

]]>
Morse Key https://somethingorotherwhatever.com/items/morse-key 2023-06-19T11:46:26.325000Z A Morse code key made for Ayliean MacDonald.

]]>

A Morse code key made for Ayliean MacDonald.

]]>
GeoGebra custom element https://somethingorotherwhatever.com/items/geogebra-custom-element 2023-05-08T10:33:33Z A web component to embed a GeoGebra applet

]]>

geogebra-component.js

A web component to embed a GeoGebra applet.

It's a wrapper around deployggb.js provided by GeoGebra.

Usage

Construct a worksheet from scratch

Write GeoGebra commands inside the tag. These commands are evaluated immediately after the applet loads.

<geogebra-applet> A = (1,2) </geogebra-applet>

Load a worksheet from GeoGebra.org by ID

<geogebra-applet material="sA5Mb4vd" /> <geogebra-applet material="https://www.geogebra.org/m/sA5Mb4vd" />

You can give just the ID, or you can give the full URL of a geogebra material, because that's easier to think about!

Documentation

There's a full API reference and a page of examples.

]]>
QR code generator (Glitch) https://somethingorotherwhatever.com/items/qr-code-generator-glitch 2023-05-03T10:38:07.401000Z A really simple tool which generates a QR code containing the given text.

]]>

A really simple tool which generates a QR code containing the given text.

]]>
Keyboard bashing https://somethingorotherwhatever.com/items/keyboard-bashing 2023-04-10T03:53:16.982000Z For my toddler to bang away at the keyboard

]]>

For my toddler to bang away at the keyboard

]]>
Unicode math normalization https://somethingorotherwhatever.com/items/unicode-math-normalization 2023-03-29T14:46:40Z Data for normalizing mathematical expressions written in Unicode

]]>
Data for normalizing mathematical expressions written in Unicode

Unicode is the standard encoding for text. There are thousands of glyphs, representing letters, characters, symbols and marks from a huge variety of scripts and contexts.

There are many repeated, variant or combined characters. These can be normalized to a subset of characters, using standard normalization algorithms.

These algorithms are generic: when used in a mathematical context, they might not apply an equivalence between two characters, or omit some information that would be useful.

So this project aims to compile a dictionary of mappings from less-common Unicode characters to the symbols conventionally used in linear mathematical expressions.

The motivation is to support more characters in the JME language used by Numbas. The JME grammar has the following kinds of token:

  • Name (either variable name or function name)
  • Number
  • Operator (Binary or unary, prefix or postfix)
  • Punctuation (Brackets, parentheses, argument separators)

Any string of letter characters is acceptable for name tokens, but there are many equivalences that should be applied:

  • Greek letters and their Latin names, e.g. α and alpha.
  • Special symbols, such as and infinity.
  • Superscript/subscript symbols should be equivalent to the syntax for marking normal characters as sub/superscripts, e.g. is equivalent to x^2.
  • There are many Unicode symbols that correspond to named functions, e.g. is equivalent to sqrt, or to operations that are conventionally typed in ASCII, e.g. × is equivalent to *.
  • There are lots of mathematical letter glyphs representing Latin or Greek letters with some styling applied. These should be equivalent to the corresponding unstyled letters, with an annotation recording the styling.

Digit symbols should be normalized to the ASCII digits 0-9, where possible. Non-European scripts for representing numbers would need to be dealt with individually.

There are lots of varieties of brackets, which should normalize to the ASCII parentheses (), square brackets [] and curly brackets {}.

Contents of this repository

There is a Jupyter notebook, unicode-math-mapping.ipynb, which contains code for working through subsets of Unicode and producing mapping dictionaries.

There are some mappings that can be produced automatically, and some that had to be written out manually - these are defined by the .tsv files in the root of this repository.

Using the data

The mapping information is stored in .json files in the final_data directory. Each of these files contains a single dictionary mapping single Unicode characters to an equivalent string, and an array of annotations, which are themselves ASCII strings. For example, this is the entry in final_data/symbols.json for 𝒚, "MATHEMATICAL BOLD ITALIC SMALL Y":

"\ud835\udc9a": [ "y", [ "BOLD", "ITALIC" ] ],

There are five files:

  • greek.json - mapping Greek letters to their English names, e.g. α to alpha.
  • letters.json - mapping mathematical letters to their standard equivalents, with annotatoins.
  • subscripts.json - mapping superscript characters to their standard equivalents.
  • superscripts.json - mapping subscript characters to their standard equivalents.
  • symbols.json - mapping all sorts of mathematical symbols to common symbols, names, or sub-expressions. Some symbols are mapped to a string of the form not NAME - you might have to do some processing to interpret these correctly, instead of just substituting the mapped string into the expression being parsed.

The mappings must be applied as part of the tokenisation step when parsing a mathematical expression.

It is not correct to do a global substitution of characters before parsing: for example, in the expression α = "α", the second occurrence of α should be preserved because it's inside a string literal.

You will have to come up with a way of applying the produced mappings to a particular computer algebra system.

Contributing to this project

There were many decisions to make in producing the mapping of characters. I omitted most symbols relating to operations that are very unlikely to be used in an undergraduate maths course.

The function names for mappings were sometimes chosen arbitrarily - there might be standard names for these in some computer algebra systems.

If you use these mappings, please tell me!

]]>
Aperiodic monotile images https://somethingorotherwhatever.com/items/aperiodic-monotile-images 2023-03-21T09:43:34Z Smith, Myers, Kaplan and Goodman-Strauss's aperiodic monotile, in a variety of formats

]]>

The aperiodic monotile in a variety of formats

This repository contains code and vector image files to produce the aperiodic monotiles found by David Smith, Joseph Samuel Myers, Craig S. Kaplan, and Chaim Goodman-Strauss.

There are two monotiles, which each tile the plane aperiodically.

A 'hat':

A hat-like polygon

And a 'turtle':

A turtle-like polygon

Each file produces a single copy of the tile. Several copies of the tile, with some flipped or mirrored, fit together to tile the plane.

The files are:

]]>
Django ActivityPub bot https://somethingorotherwhatever.com/items/django-activitypub-bot 2023-03-17T11:37:27Z A Django project for serving ActivityPub actors, designed for bot accounts

]]>

A Django ActivityPub bot server

This is a Django project for serving ActivityPub actors, designed for bot accounts.

The aim is to provide just enough features to provide an account that other people can follow, and to manage followers and sending out new posts.

I'm sharing this code as-is, only because it doesn't cost me anything other than the time to write this README!

I hope it's useful, and you're very welcome to use it as a starting-point to build your own project.

If you're looking for a more extensible Python ActivityPub implementation, bovine is worth looking at first.

Installation

Assumptions:

  • You have an existing web server serving a site under a domain name that you'd like to use for an ActivityPub actor, with root (superuser) access.
  • These instructions are for a server running Ubuntu Linux, with the nginx web server.

You need Python 3.9 or later to run this.

Clone this repository (I cloned it into /srv/activitypub, so that's what these instructions will use), and install the requirements, with

pip install -r requirements.txt

It's a good idea to set up a virtual environment to do this in. I set up a virtual environment in /srv/activitypub/venv.

Make sure you activate the virtual environment after creating it!

Copy activitypub_bot/settings.py.dist to activitypub_bot/settings.py, and fill in the settings, following the instructions in that file.

Copy the files in systemd_services to /etc/systemd/system, and enable them:

Copy gunicorn.conf.py.dist to gunicorn.conf.py and change it if you used different paths for the repository or the virtual environment.

Run python manage.py migrate to set up the database.

Enable the services:

systemctl enable activitypub_huey.service activitypub.service activitypub.socket

For each domain you want to run ActivityPub on, the server needs to handle requests to the URL /.well-known/webfinger and anything under /activitypub. (You can replace /activitypub with something else if you want).

Add the following rules to each nginx config that handles domains you want to run ActivityPub on:

``` server { # ... your existing config

location ~ /activitypub/static {
    rewrite ^/activitypub/static/(.*)$ /$1 break;
    root /srv/activitypub/public/static;
}
location ~ /activitypub {
    include proxy_params;
    proxy_pass http://unix:/run/activitypub.sock;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
}
location = /.well-known/webfinger {
    include proxy_params;
    proxy_pass http://unix:/run/activitypub.sock;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
}

} ```

Reload nginx's config:

systemctl reload nginx

It's useful to create superuser login details for the admin interface:

python manage.py createsuperuser

If everything is set up properly, https://{DOMAIN}/activitypub/admin will show you the Django admin login screen.

Usage

You can create an actor on the command-line with the create_actor management command:

python manage.py create_actor

You'll be asked to choose the domain it should exist on, and to give a username. You can optionally create an API access token.

You can write a post through the admin interface: click on Local actors, then on the actor you want to create the post, and then click the Create a note link at the bottom of the page.

Alternately, if you created an API access token, you can make a POST request to https://{DOMAIN}/activitypub/accounts/{USERNAME}/create_note. The request should have the header Authorization: Bearer {ACCESS_TOKEN}, and a POST parameter content with the text of the post.

Inbox handlers

When an ActivityPub message is received, it's handled by a series of subclasses of bot.inbox.AbstractInboxHandler.

For an activity with Type: "ActivityType", the corresponding method handle_ActivityType(activity) on each inbox handler will be called.

Django apps can register a new inbox handler class with bot.inbox.register_inbox_handler(cls, spec). should_handle is either a callable of the form spec(actor, activity) which should return a boolean dictating whether the class should handle this activity received by this actor, or it should be a dictionary with keys username and domain specifying the usernames, domains, or both, whose inboxes this class should handle. If should_handle is not given, then the handler is called for every activity.

There is a built-in inbox handler, bot.inbox.InboxHandler, which manages Follow and Like activities.

You could define an inbox handler which sends you an email whenever a Mention activity is received.

Help with ActivityPub

The specs are good!

The ActivityPub protocol specification gives a description of how interactions work.

The Activity Streams Vocabulary

]]>
Numbas spreadsheets extension https://somethingorotherwhatever.com/items/numbas-spreadsheets-extension 2023-01-24T08:05:22Z An extension for Numbas providing editable table or spreadsheet widgets

]]>

Numbas spreadsheets extension

About

This extension adds a data type, spreadsheet, representing a 2D grid of text cells with styling information, similar to a spreadsheet in a program such as Microsoft Excel.

In the Numbas question editor, this extension adds a "Spreadsheet" variable template type which allows you to load a spreadsheet from an uploaded .xlsx file.

Internally, SheetJS is used to interpret spreadsheet files. Any format understood by SheetJS can be used, but style information is only loaded from .xlsx files.

When inserted into content areas, spreadsheet values are rendered as non-editable grids.

This extension adds a "Spreadsheet" answer input method for custom part types. The "expected answer" and "initial sheet" settings should be spreadsheet values with the same dimensions.

The file spreadsheet.npt defines a "Spreadsheet" custom part type which asks the student to enter values into a given spreadsheet and compares entries against a completed spreadsheet given by the question author.

What it doesn't do

  • Number formats such as currency, percentage, time

JME functions

spreadsheet(cells)

Construct a spreadsheet object from a 2D array of cell contents.

Example: spreadsheet([["Name","Points"], ["Alice", 1], ["Harrison", 5]])

spreadsheet_from_base64_file(filename, data)

Construct a spreadsheet from a .xlsx file whose contents have been encoded in base64. This function is used by the "spreadsheet" variable template type; it's unlikely you'll ever use it in any other context.

update_range(spreadsheet, range, changes)

Update the cells in the given range, following the settings in the dictionary changes. The changes dictionary can be constructed using the styling functions below.

Example: update_range(sheet, "B2:D2", border("bottom","thick"))

disable_cells(spreadsheet, ranges)

Disable cells in the given ranges, so they can't be edited by the student.

Example: disable_cells(sheet, ["A1", "C2", "B3:D5"])

fill_range(spreadsheet, range, contents)

Fill in the text contents of the cells in the given range with the values from the 2D array contents.

If the range is a single cell or all the cells are in a single row or column, contents can be a sim[ple list.

Examples:

  • fill_range(sheet, "A1:D2", [["a","b","c","d"],[1,2,3,4]])
  • fill_range(sheet, "A1:C1", ["a", "b", "c"])

parse_range(range)

Interpret a string representing a range, and return a list of the addresses of the cells it contains.

Example: parse_range("A1:B3")[ "A1", "B1", "A2", "B2", "A3", "B3" ]

slice(spreadsheet,range)

Make a copy of the given spreadsheet, containing only the cells in the given range.

Example: slice(sheet, "B2:D5")

spreadsheet[range]

Return the contents of the cells in the given range, or the contents of the cell at the given address. The contents are always returned as strings. The empty string is used for empty cells.

Examples:

  • sheet["A1:B3"][["a","b"],["1","2"],["","3"]]
  • sheet["A1"]"a"

encode_range(start_column, start_row, end_column, end_row)

Given the numerical indices of the top-left and bottom-right corners of a range, return a string representing that range. The rows and columns are both numbered starting from 0.

Example: encode_range(0,0,3,2)"A1:D3"

Cell styling functions

The following functions can be used with the update_range function to change the appearance of cells in a spreadsheet.

These functions can be chained together using the |> pipe operator. For example: font_style("bold") |> fill("lightgreen")

Functions that specify a colour can take any valid CSS color value.

You can easily cause accessibility problems when using colour. Try not to use colour as the sole means of conveying information, or to use colour combinations that can't be easily distinguished by colourblind people.

border(sides, styles)

Set cell border styles.

sides is a space-separated string giving the sides to style. The sides are named "top", "left", "bottom" and"right".

styles is a space-separated string giving the style information, in the format thickness color. thickness is one of thin, medium or thick.

Example: border("top bottom", "thin blue")

font_style(styles)

Style the text content of cells.

styles is a space-separated list of style names. The understood styles are bold, italic and underline.

Example: font_style("bold underline")

font_size(size)

Set the size of text in cells, as a multiple of the default size.

A size smaller than 1 can cause accessibility problems by making text hard to read; try to only make text the default size or bigger.

Example: font_size(1.2)

font_color(color)

Set the color of text in cells.

Example: font_color("blue")

bg_color(color)

Set the background colour of cells.

Example: bg_color("black")

horizontal_alignment(alignment)

Set the horizontal alignment of text inside cells.

Any value accepted by the CSS text-align property is understood.

Example: horizontal_alignment("center")

vertical_alignment(alignment)

Set the vertical alignment of text inside cells.

Any value accepted by the CSS vertical-align property is understood.

Example: vertical_alignment("middle")

]]>
Twitter archive generator https://somethingorotherwhatever.com/items/twitter-archive-generator 2023-01-06T10:59:33Z A Python script to convert the Twitter archive to something that can be published

]]>

CLP's Twitter archive generator

This Python script takes the archive you obtain from Twitter and produces a nice static site containing all the tweets, in a form suitable for publishing online.

Install the required packages with pip install -r requirements.txt.

Extract the .zip file you get from Twitter into the same directory as this script.

Run python twitter_archive.py.

The output is in a directory called output. Copy the data/tweets_media folder from your Twitter archive to output/media.

I just made this for my own Twitter archive, and I'm not hugely interested in maintaining a generic tool for everybody. If it's useful to you as it is, then that's lovely!

]]>
Birthday magic square https://somethingorotherwhatever.com/items/birthday-magic-square 2023-01-02T09:55:23Z An interactive page to make a magic square for your birthday. Made on request for James Grime

]]>

An interactive page to make a magic square for your birthday. Made on request for James Grime

]]>
Five talks about trains https://somethingorotherwhatever.com/items/five-talks-about-trains 2022-11-14T19:20:08Z My talk at Big MathsJam 2022: five talks about trains

]]>

My talk at Big MathsJam 2022: five talks about trains

]]>
Random trees in circles https://somethingorotherwhatever.com/items/random-trees-in-circles 2022-11-09T08:35:49.175000Z Generates a random tree by joining up points arranged around a circle

]]>

Generates a random tree by joining up points arranged around a circle

]]>
Can I also use? https://somethingorotherwhatever.com/items/can-i-also-use 2022-11-01T06:22:31Z A tool to work out which browsers support a combination of features

]]>

A tool to work out which browsers support a combination of features

]]>
Listen to a sequence https://somethingorotherwhatever.com/items/listen-to-a-sequence 2022-10-27T07:49:44.698000Z Plays an OEIS sequence as a tune

]]>
Plays an OEIS sequence as a tune

]]>
Numbas lockdown app for iOS https://somethingorotherwhatever.com/items/numbas-lockdown-app-for-ios 2022-10-12T13:25:43Z A version of the Numbas lockdown app made for iOS

]]>
Numbas lockdown iOS

This is an iOS app for loading Numbas exams which require a locked-down environment.

]]>
Written number extension for Numbas https://somethingorotherwhatever.com/items/written-number-extension-for-numbas 2022-09-21T07:34:28Z A Numbas extension providing a function to write out a number in words

]]>
Written number

Provides a function written_number which converts numbers to words.

Based on js-written-number by Pedro Tacla Yamada and others, used under the terms of the MIT license.

The following languages are supported:

| Language | code | |---------|--------| | English | en | | US English | en-us | | English (Indian) | en-in | | Portuguese (Brazil) | pt | | Portuguese (Portugal) | pt-br | | Spanish | es | | French | fr | | Esperanto | eo | | Vietnamese | vi | | Arabic | ar | | Azerbaijan | az | | Turkish | tr | | Ukrainian | uk | | Indonesian | id | | Russian | ru |

Usage

written_number(n)

Converts the given number to words, in the exam's preferred language (or English by default).

written_number(n,language_code)

Converts the given number to words in the given language.

]]>
watchmake https://somethingorotherwhatever.com/items/watchmake 2022-09-18T15:15:57Z A tool which runs make when a file in the current directory is changed.

]]>
WatchMake

This is a tool which runs make when a file in the current directory is changed.

You can configure it with a file called .watchmakerc in the directory you're running it from.

The file should contain some YAML in the following format:

default_make: # A list ofmake targets to run extensions: # A list of file extensions that should trigger make. If not given, all files trigger make. path: # A list of subdirectories to watch. If not given, all subdirectories under this one are watched.

I wrote this to learn Elixir, and to replace my existing Python script which is quite fiddly.

How to run it

Build a release by running mix release.

Then the folder _build/dev/rel/watchmake contains everything needed to run the program.

Run _build/dev/rel/watchmake/bin/watchmake start to start it.

Press Ctrl+C twice to end it.

]]>
Mathematical Guess Who? https://somethingorotherwhatever.com/items/mathematical-guess-who 2022-09-13T07:57:48Z A multiplayer mathematical Guess Who? game. Made for the 24 hour maths game show.

]]>

A multiplayer mathematical Guess Who? game. Made for the 24 hour maths game show.

]]>
Numbas lockdown app https://somethingorotherwhatever.com/items/numbas-lockdown-app 2022-09-01T12:01:33Z A locked-down browser for running Numbas exams in a controlled environment

]]>
Numbas lockdown browser

An Electron app which can be used to launch resources in the Numbas LTI provider, without access to developer tools or most other browser controls.

To build

You need NodeJS and yarn.

Once you've got NodeJS installed, install yarn.

Copy config.js.dist to config.js and fill it in.

To run the browser in development mode:

yarn start open <URL>

To build the executables:

yarn build_windows yarn build_linux yarn build_max

It's technically possible to build the Windows executable on Linux, using Wine, but it seems to produce a much bigger package than building on Windows.

]]>
The unintentionally useful consequences of playing games with maths https://somethingorotherwhatever.com/items/the-unintentionally-useful-consequences-of-playing-games-with-maths 2022-08-23T09:31:24Z A talk about Hamiltonian graphs, leading to the Herschel graph.

]]>

A talk about Hamiltonian graphs, leading to the Herschel graph.

]]>
CSS binary clock https://somethingorotherwhatever.com/items/css-binary-clock 2022-07-14T06:55:07.306000Z A binary clock entirely made in CSS

]]>

A binary clock entirely made in CSS

]]>
Maths blockbuster https://somethingorotherwhatever.com/items/maths-blockbuster 2022-07-09T14:12:28.186000Z The game board for Maths Blockbuster, part of the 24 Hour Maths Game Show

]]>

The game board for Maths Blockbuster, part of the 24 Hour Maths Game Show

]]>
Formula calculator template https://somethingorotherwhatever.com/items/formula-calculator-template 2022-07-06T05:12:57.554000Z A template to quickly whip up a page to calculate a formula

]]>

A template to quickly whip up a page to calculate a formula

]]>
Shunting-yard algorithm animation https://somethingorotherwhatever.com/items/shunting-yard-algorithm-animation 2022-06-05T09:06:55Z An animation of the shunting yard algorithm, with a little train

]]>

An animation of the shunting yard algorithm, with a little train

]]>
Didn't Graduate Texts in Mathematics meme generator https://somethingorotherwhatever.com/items/didn-t-graduate-texts-in-mathematics-meme-generator 2022-05-30T09:14:49Z A generator for memes, based on the Graduate Texts in Mathematics series

]]>

A generator for memes, based on the Graduate Texts in Mathematics series

]]>
OEISle https://somethingorotherwhatever.com/items/oeisle 2022-05-22T18:33:51Z A Wordle clone where you have to guess a sequence from the Online Encyclopedia of Integer Sequences

]]>

A Wordle clone where you have to guess a sequence from the Online Encyclopedia of Integer Sequences

]]>
Tractor Befunge https://somethingorotherwhatever.com/items/tractor-befunge 2022-05-09T07:10:44Z A happy image occurred to me of the Befunge instruction pointer as a tractor, driving around a field.

]]>

A happy image occurred to me of the Befunge instruction pointer as a tractor, driving around a field.

]]>
Prime Run https://somethingorotherwhatever.com/items/prime-run 2022-03-19T12:42:47Z A game about adding and subtracting prime numbers. You start at a random number, with a random target. Try to reach the target, by adding or removing any prime factor of your current number.

]]>

A game about adding and subtracting prime numbers. You start at a random number, with a random target. Try to reach the target, by adding or removing any prime factor of your current number.

]]>
A Tale of log(2) Cities https://somethingorotherwhatever.com/items/a-tale-of-log-2-cities 2022-03-17T07:55:43.980000Z Reduce a book to log(2) of its original length by alternately adding and removing 1/N of the words.

]]>

Reduce a book to log(2) of its original length by alternately adding and removing 1/N of the words.

]]>
WordPress interactive element plugin https://somethingorotherwhatever.com/items/wordpress-interactive-element-plugin 2022-03-05T13:43:37Z A WordPress plugin which provides a block to embed an interactive element. I made this to make it easier to include interactive thingies in posts on The Aperiodical.

]]>

A WordPress plugin which provides a block to embed an interactive element. I made this to make it easier to include interactive thingies in posts on The Aperiodical.

]]>
CReal.js https://somethingorotherwhatever.com/items/creal-js 2022-02-26T13:57:07Z Constructive real numbers, in JavaScript. Based on Hans-J. Boehm's Java implementation

]]>
CReal.js

Constructive real numbers for JavaScript.

Ported from Hans-J. Boehm's Java implementation to JavaScript by Christian Lawson-Perfect.

Each recursive real number is represented as an object that provides an approximation function for the real number. The approximation function guarantees that the generated approximation is accurate to the specified precision. Arithmetic operations on constructive reals produce new such objects; they typically do not perform any real computation. In this sense, arithmetic computations are exact: They produce a description which describes the exact answer, and can be used to later approximate it to arbitrary precision.

When approximations are generated, e.g. for output, they are accurate to the requested precision; no cumulative rounding errors are visible. In order to achieve this precision, the approximation function will often need to approximate subexpressions to greater precision than was originally demanded. Thus the approximation of a constructive real number generated through a complex sequence of operations may eventually require evaluation to very high precision. This usually makes such computations prohibitively expensive for large numerical problems. But it is perfectly appropriate for use in a desk calculator, for small numerical problems, for the evaluation of expressions computated by a symbolic algebra system, for testing of accuracy claims for floating point code on small inputs, or the like.

Usage

creal.js is an ECMAScript module. It exposes an object with a valueOf method to create a CReal from an ES number or string, and some constants.

``` import CReal from 'creal.js';

const one_seventh = CReal.valueOf(7).inverse(); console.log(one_seventh.toString(20)); ```

See the full documentation.

]]>
Rectangle pals https://somethingorotherwhatever.com/items/rectangle-pals 2022-02-24T11:53:05.355000Z Rectangle pals are randomly added or taken away, but after each step, all the rectangles have the same area.

]]>

Rectangle pals are randomly added or taken away, but after each step, all the rectangles have the same area.

]]>
Nulac https://somethingorotherwhatever.com/items/nulac 2022-02-18T20:01:35.837000Z This is a pen-and-paper game I invented in secondary school. Twenty years later, I've made a digital version of it!

]]>

This is a pen-and-paper game I invented in secondary school. Twenty years later, I've made a digital version of it!

]]>
Programming extension for Numbas https://somethingorotherwhatever.com/items/programming-extension-for-numbas 2022-02-03T14:45:29Z An extension for Numbas which provides a code editor and the ability to evaluate code written in Python and R.

]]>

Programming extension for Numbas

This extension adds a code editor input method, and the ability to run code.

There is built-in support for running:

There is a custom part type in code.npt, which marks code entered by the student by evaluating unit tests.

Running code

The extension provides a JME function run_code. Because the code might take a long time to run, it runs asynchronously; the function returns a promise value.

In order to use the results in marking, call run_code from the part's pre_submit note. The rest of the marking algorithm will run once the code has finished running.

Here's an example:

pre_submit: [ run_code( "pyodide", [ studentAnswer, "'x' in locals()", "x==1" ] ) ]

The code editor input method

The extension provides the Ace editor as an input method for custom part types. It has three options:

  • Code language - The language to use for syntax highlighting.
  • Placeholder - The initial content of the editor.
  • Editor theme - The Ace theme to use. Only textmate is bundled with the extension.

JME functions

run_code(language,codes)

  • language is a string containing the name of the code runner to use.
  • codes is a list of strings of code.

Run some blocks of code and return the results in a promise.

The blocks are run one after the other, in the same global scope, so variables assigned in one block are available in subsequent blocks.

When run in the pre_submit note, this task adds an entry code_result, a list containing the results of each of the code blocks. The result of a code block is represented in a dictionary of the following form:

  • result - The final value produced by the block.
  • success - true if the code ran without errors, otherwise false.
  • stdout - The contents of the program's STDOUT buffer. This typically contains any text printed by the program.
  • stderr - The contents of the program's STDERR buffer. This typically contains any error messages produced by the program.
  • error - If the code threw an error, the text of the error.

variables_as_code(language, variables)

Produce a block of code which assigns a series of variables in the given language. The variables argument is a dictionary mapping variable names to values.

code_block(code,options)

Display some code in a syntax-highlighted code area.

The options argument is an optional dictionary of options, or just the name of the language to use for syntax highlighting. The following options can be set:

  • language - The language to use for syntax highlighting.
  • theme - The Ace theme to use. Only the textmate theme is built in to this extension.
  • gutter - Show or hide the gutter, which shows line numbers.

language_synonym(runner)

Return the name of the language corresponding to the given runner.

"pyodide" returns "python"; "webr" returns "r".

Marking functions

There are a few functions to produce common marking tests:

  • py_mark_equal(name,value,[weight=1]) - Checks that the variable with the given name has the given value. The name should be a string, but the value can be any JME value. Example: py_mark_equal('x', 1)

Validation functions

There are a few functions to produce common validation tests:

  • py_valid_defined(name) - Checks that a variable with the given name has been defined - equivalent to 'name' in locals().
  • py_valid_callable(name) - Checks that the object with the given name has been defined and is callable - equivalent to 'name' in locals() and callable(name).
  • py_valid_isinstance(name,type) - Checks that the object with the given name has been defined and is an instance of the given type - equivalent to 'name' in locals() and isinstance(name, type).

Adding another language

The class Numbas.extensions.programming.CodeRunner contains methods for running code in a particular language. To add a new language, define a new class extending this one, implementing the run_code method.

Then call Numbas.extensions.programming.register_language_runner(name, runner) with the name of the runner and the class. Only one instance of the class will ever be created.

See the PyodideRunner and WebRRunner classes in this extension for examples of how to implement a runner.

Functions specific to R

r_load_files(files)

Read the contents of the given files and return the result in a promise, to be used by a pre-submit task.

When run in the pre_submit note, this task adds an entry r_files, a list containing information about each of the files:

  • exists - true if the file was loaded successfully, false if not.
  • text - if the file contains text, the contents of the file as a string.
  • blob - if the file is binary, a blob URL representing the file's contents. You can use a blob URL as the src attribute for an img or iframe tag.

At the moment, only PDF files are recognised as binary. You can register other file types as binary by adding an entry to the JavaScript object Numbas.extensions.programming.mime_types.

]]>
Find Dracula https://somethingorotherwhatever.com/items/find-dracula 2022-02-02T10:06:15Z Find all the Draculas in a castle.

]]>

A small game made in a morning, in Elm.

  • Try to find all the Draculas in the castle.
  • You can open one door for each Dracula in the castle.
  • If there was a Dracula in that room, you kill it.
  • If there was no Dracula in that room, you wake up another Dracula!
  • After each turn, all the Draculas move to an adjacent room.
  • When two Draculas meet, the scarier Dracula puts the other to sleep.
]]>
JIGGRAPH https://somethingorotherwhatever.com/items/jiggraph 2022-01-22T15:54:26Z A puzzle game about shaking hands

]]>

A puzzle game about shaking hands

]]>
Canvas LMS folder sync https://somethingorotherwhatever.com/items/canvas-lms-folder-sync 2022-01-13T12:49:10Z A command-line tool to synchronise a local folder with one in a Canvas LMS course

]]>
Canvas LMS folder sync

This is a command-line tool and Python package to synchronise a local folder with one in a Canvas LMS course.

In order to use this, you need a Canvas API token linked to an account which has permission to create files in your target course's Files section. See the Canvas API documentation for instructions on how to get a token.

Installation

Python 3.8 or newer is required.

To install the package, run:

pip install canvaslms_sync

This provides a shell command canvas_sync.

Usage

canvas_sync local_folder remote_url -t CANVAS_API_TOKEN

You can store your Canvas API token in a file like this:

[Canvas] canvas_api_token = TOKEN

By default, the script looks for this file in credentials.ini in the current working directory, but you can specify a different path with the -c option.

Hidden files and folders (those whose names start with .) are ignored by default. You can include them with the --include-hidden option.

Development

I followed the Python packaging tutorial to make this package.

To build this package, you need twine and build:

python3 -m pip install twine build

First, build the distributable files:

python3 -m build

That produces .tar.gz and .whl files in ./dist. You can try installing the package in a different virtualenv with pip install dist/canvaslms_sync-$VERSION-py3-none-any.whl.

To upload to PyPI:

python3 -m twine upload --repository pypi dist/*

]]>
This island is big enough for the both of us https://somethingorotherwhatever.com/items/this-island-is-big-enough-for-the-both-of-us 2022-01-10T10:46:00Z A game about dividing up an island

]]>

An implementation of the game Imparium, invented by Walter Joris.

Here’s a brief version of the rules: you start with a 6×6 grid of boxes. You and another player take turns removing pairs of adjacent boxes. Whenever there’s a group made up of an odd number less than 10 contiguous boxes, the last player to move can claim them. Once all boxes have been either claimed or removed, the game is over and the person who has claimed the most boxes wins.

Written in Elm.

]]>
Floating-point calculator https://somethingorotherwhatever.com/items/floating-point-calculator 2021-12-08T16:21:56Z An experiment in making a calculator out of pieces that float around.

]]>

An experiment in making a calculator out of pieces that float around.

I wanted something where you could easily repeat calculations with different numbers, while being easy to use on a touch-screen device.

It's a little bit too fiddly - it takes quite a while to enter a complicated calculation, and I think it would be easier to read if the connecting lines could be bent.

]]>
Chirun LTI in docker https://somethingorotherwhatever.com/items/chirun-lti-in-docker 2021-11-22T10:46:10Z A Docker container for running the Chirun LTI server.

]]>
Docker Compose Recipe for Chirun LTI Tool

This repository contains everything needed to run the Chirun LTI tool in Docker containers.

Documentation

There's documentation for administrators, instructors and students at TBD.

Installation

Prerequisites

Install Docker and Docker Compose on your server.

Setup

Clone this repo somewhere on your server and cd into the directory.

Copy the file settings.env.dist to settings.env and write your own values each of the variables inside.

Obtain an SSL certificate and key for the domain you will access the CB LTI tool from. Copy the key to files/ssl/cblti.key and the certificate to files/ssl/cblti.pem.

Starting

Run the following command in the directory where docker-compose.yml resides:

docker-compose up

Stopping

Stop the containers with docker-compose down

LTI Setup

To use the Chirun LTI tool with your VLE, an administrator will need to add the tool to your own instance of the VLE. To do this, the VLE needs to be setup beforehand as a tool consumer in the admin panel accessible on your web server at https://chirun-lti.institution.tld/lti/admin/. Login with the administrator account setup in the file settings.env.

Create a Name, Key, and Secret for your VLE using the Add New Consumer form on the admin page, and then forward that information on to your VLE administrator to be added as an external LTI tool.

They might also need the URL for the LTI XML configuration, https://chirun-lti.institution.tld/lti/xml/ or the LTI launch URL, https://chirun-lti.institution.tld/lti/connect.php.

Landing Page

A simple landing page for the root of the webserver at https://chirun-lti.institution.tld has been included in files/cblti/index.html. This file is bind mounted by Docker at launch and so can be directly edited by the server administrator as required.

Running in the cloud

Docker Compose files can also be used to deploy to the cloud. See the following documents for more information about deploying Docker to the cloud: - Compose for Amazon ECS - Compose for Microsoft ACI

Upgrade instructions

To upgrade to a new version, fetch the latest version of this repo and then,

docker-compose up --build

]]>
Chirun LTI server https://somethingorotherwhatever.com/items/chirun-lti-server 2021-11-22T10:21:35Z A web interface to process and serve documents with Chirun.

]]>
Chirun LTI Tool

The Chirun LTI tool provides a simple to use interface for instructors to upload content to a VLE to be automatically converted into accessible and flexible documents with Chirun. With this tool, the instructor does not need to have any knowledge of running Unix software or uploading content to a web-server in order to share the web-based output generated by Chirun.

Installation

Prerequisites

  • A web server supporting PHP, such as Apache.
  • PHP must be configured to allow calling the exec() function and have at least the following extensions enabled:
    • pdo
    • pdo_mysql or pdo_sqlite
    • yaml
  • The following system packages must be installed:
    • curl
    • rsync
    • libyaml
    • docker
  • Write access to an empty MySQL/SQLite database

LTI Tool Setup

Clone this repo and copy the software into an install directory (referred to as INSTALLDIR) visible to your web server. Copy the file config.dist.php to config.php and then edit the file to include your own site settings. Take particular note of the following variables,

Name | Description | Example -------------|-------------|--------- WEBDIR | The intended web path for accessing the tool | /lti INSTALLDIR | The full file system path to the tool's install directory | /var/www/webroot/lti PROCESSUSER | The "processing user" that will run the Chirun build tools via docker | programs DB_NAME | A database DSN specifying a database host and name | mysql:dbname=chirun;host=database.example.com DB_USERNAME | Database username | DB_PASSWORD | Database password |

User Permission Setup

Uploaded documents are compiled by running the Chirun software in a docker container. Since allowing access to docker is equivalent to giving root access to a user, this must be handled carefully. For separation of privileges a new Unix user must be created to be used as the Chirun processing user. This user should have access to docker via membership of the docker group.

Assuming your processing user will be named programs, the following commands creates the user and adds it to the docker group, ```

adduser programs

usermod -aG docker programs

```

Directory Permission Setup

The user running the web server process should be able to write to UPLOADDIR, CONTENTDIR and PROCESSDIR/logs, but not permitted to write to anything else in INSTALLDIR. As such, ensure directory permissions are setup as follows, where programs is your processing user and www-data is the primary unix group for the user running the web server process.

Directory | Mode | Owner:Group ----------|------|-------------- INSTALLDIR | 755 | programs:programs UPLOADDIR | 775 | programs:www-data CONTENTDIR | 775 | programs:www-data PROCESSDIR/logs |775 | programs:www-data

Sudo Permission Setup

The sudo command should be configured so that the user running the web server process (e.g. www-data) can start the Chirun processing script as the processing user with some particular environment variables populated. This can be setup by adding the following lines to the /etc/sudoers file,

``` www-data ALL = (programs) NOPASSWD: [PROCESSDIR]/process.sh Defaults env_keep += "PROCESSDIR" Defaults env_keep += "CONTENTDIR" Defaults env_keep += "UPLOADDIR" Defaults env_keep += "DOCKER_PROCESSING_VOLUME"

```

replacing [PROCESSDIR] with the full path to the processing directory.

Docker Setup

Prepare the docker daemon by pulling the Chirun image on the server. For example, log into the server as the processing user and run the command: $ docker pull chirun/chirun-docker:latest

Admin Directory Setup

The web server's rewriting engine should be used to direct all requests of the form lti/content/[...] to lti/index.php?req_content=[...]. In addition, the following directories should be made forbidden for public access:

  • UPLOADIR
  • PROCESSDIR
  • INSTALLDIR/lib

The path WEBPATH/admin should also be protected and allow only server administrator access. An example Apache setup using Basic Authentication is shown below.

<Location /> Require all granted DirectorySlash Off RewriteEngine on RewriteRule /lti/content/(.*)$ /lti/index.php?req_content=$1 [L,QSA] </Location> <Location /lti/upload> Require all denied </Location> <Location /lti/process> Require all denied </Location> <Location /lti/lib> Require all denied </Location> <Location /lti/admin> AuthType Basic AuthName "Restricted admin section" AuthUserFile /etc/apache2/.htpasswd Require user admin </Location>

In this example a username and password for admin access can be setup by running the following command on the server,

```

htpasswd /etc/apache2/.htpasswd admin

```

LTI Setup

To use the Chirun LTI tool with your VLE, an administrator will need to add the tool to your own instance of the VLE. To do this, the VLE needs to be setup beforehand as a tool consumer in the admin panel accessible on your web server at https://chirun.example.com/lti/admin/.

Create a Name, Key, and Secret for your VLE using the Add New Consumer form on the admin page, and then forward that information on to your VLE administrator to be added as an external LTI tool. They might also need the URL for the LTI XML configuration: https://chirun.example.com/lti/xml/ or the LTI launch URL, https://chirun.example.com/lti/connect.php.

Build Process Information

When content is uploaded to the LTI tool for processing, the following series of steps occurs.

  • First, a file is uploaded to the UPLOADDIR by the web server process. On upload a GUID is generated for the uploaded bundle of files. .zip files are extracted in-place.

  • The processing script is started. The script runs partially in a container, and so sudo is used to start the script as the processing user with permission to use to docker.

  • The source content is copied from the UPLOADDIR directory to the PROCESSDIR directory.

  • When uploading raw .tex or .md files a standalone Chirun compatible course.yml file is created. If a Chirun config.yml file already exists as part of the upload, it is modified to inject the correct content web path and GUID.

  • Chirun is run in a docker container using the newly prepared course.yml in the PROCESSDIR directory.

  • If successful, the output is copied from the PROCESSDIR directory into the CONTENTDIR directory with the required directory permissions.

  • Clean up is performed and the copy of the uploaded files in PROCESSDIR are deleted.

  • Finally, the output of the process script is written to a log file at PROCESSDIR/logs/<guid>.log and the log is shown to the user.

Other Information

The UPLOADDIR directory should be emptied periodically to avoid filling the disk. For example, this can be handled by adding a cron job or systemd timer for the programs user.

An example command that clears the upload directory of all files could be,

find [INSTALLDIR]/upload/ -mindepth 1 -maxdepth 1 -exec rm -r -- {} +

replacing [INSTALLDIR] with the full path to the install directory. The find command can be tweaked with arguments such as -mtime to more finely tune what files are deleted.

]]>
Each Edge Peach Pear Plum https://somethingorotherwhatever.com/items/each-edge-peach-pear-plum 2021-11-20T00:00:00Z I've made another baby, so it's time for another talk about baby maths. Each Peach Pear Plum is a classic picture book for babies, with a beautifully simple rhyming scheme. But I've always wished it was more complete. Join me for an Eulerian tour through fantasy land!

]]>

I've made another baby, so it's time for another talk about baby maths. Each Peach Pear Plum is a classic picture book for babies, with a beautifully simple rhyming scheme. But I've always wished it was more complete. Join me for an Eulerian tour through fantasy land!

]]>
Graph theory extension for Numbas https://somethingorotherwhatever.com/items/graph-theory-extension-for-numbas 2021-11-04T14:32:15Z An extension for Numbas which adds tools for generating and drawing random graphs.

]]>

Graph theory extension for Numbas

This extension provides some functions for working with and drawing graphs in Numbas.

JME functions

Many of these functions take an adjacency matrix as an argument. A value of 0 in position [i][j] means that there is no edge from vertex i to j; a positive value means that there is an edge, with any value less than 1 being drawn as a dashed line, and a value of 1 being drawn as a solid line.

adjacency_matrix(edges)

Given a list of edges, in the form [v1,v2], where v1 and v2 are indices of vertices, produce an adjacency matrix for the graph with those edges and no extra vertices.

draw_graph_from_adjacency(adjacency, labels)

Given an adjacency matrix and an optional list of string labels for the vertices, produce a drawing of a graph.

draw_graph(adjacency, vertices, labels)

Given an adjacency matrix, a list of vectors giving the positions of the vertices, and an optional list of string labels for the vertices, produce a drawing of a graph.

layout_graph(adjacency)

Given an adjacency matrix, lay the graph out, trying to separate vertices reasonably and avoid crossing edges.

Returns a list of vectors giving the positions of the vertices.

vertex_degrees(adjacency)

Given an adjacency matrix, return a list giving the degree of each vertex.

graph_union(a,b)

Given adjacency matrices a and b, return an adjacency matrix representing the union of the two graphs.

cartesian_product(a,b)

Given adjacency matrices a and b, return an adjacency matrix representing the cartesian product of the two graphs.

direct_product(a,b)

Given adjacency matrices a and b, return an adjacency matrix representing the direct product of the two graphs.

adjacency_permutation(p,m)

Given a permutation p (produced by the permutations extension) and an adjacency matrix m, return an adjacency matrix representing the graph with the vertices permuted according to p.

is_graph_isomorphism(p,m)

Given a permutation p (produced by the permutations extension) and an adjacency matrix m, return true if p is an isomorphism of the graph represented by m, and false otherwise.

JavaScript functions

All JavaScript functions are available under Numbas.extensions['graph-theory'].

Many of these functions take an adjacency matrix as an argument. An adjacency matrix is a 2D array (an array of arrays), with added integer properties rows and columns giving the number. A value of 0 in position [i][j] means that there is no edge from vertex i to j; a positive value means that there is an edge, with any value less than 1 being drawn as a dashed line, and a value of 1 being drawn as a solid line.

connected_components(adjacency)

Given an adjacency matrix, find the connected components. Returns a list of components, each represented as a list of the indices of the vertices in that component.

is_connected(adjacency)

Return true if the graph represented by the given adjacency matrix has a single connected component.

subgraph(adjacency,vertices)

Given a graph represented by an adjacency matrix, and a list of indices of vertices, return the adjacency matrix of the subgraph containing only those vertices.

largest_connected_component(adjacency, labels)

Given a graph represented as an adjacency matrix, and a list of labels for the vertices, return the largest connected component of the graph and the labels of its vertices.

Returns an object {adjacency, labels}.

(I'm not sure if this function is needed)

adjacency_matrix_from_edges(edges,directed)

Given a list of edges, produce the corresponding adjacency matrix.

edges is a list of values [v1,v2], where v1 and v2 are indices of vertices.

If directed is true, then the adjacency matrix will be made symmetric about its diagonal. So for an undirected edge between vertices i and j, you only need to include [i,j] in edges.

If directed is false, then [i,j] and [j,i] are different directed edges.

from_adjacency_matrix(adjacency)

Given an adjacency matrix, return lists of vertices and edges, to be used by the cola layout engine.

Returns an object {vertices, edges}.

draw_graph(graph)

graph is an object {vertices, adjacency, labels}.

  • vertices is a list of objects {x,y}.
  • adjacency is an adjacency matrix: 0 means no edge; 1 means an edge; and any number between 0 and 1 means a dashed edge. If there are edges i to j and j to i, the edge is drawn as undirected; otherwise if there is just an edge i to j it is drawn as directed with an arrow.
  • labels is a list of string labels for the vertices.

Returns an SVG element containing a drawing of the graph.

layout_graph(graph)

graph is an object {vertices, edges}.

  • vertices is a list of objects {x,y}.
  • edges is a list of objects {source, target, weight}, where source and target are indices of vertices, and weight is a scalar controlling how long the edge should be.

Returns a list of positions for the vertices, as objects {x,y}.

vertex_degrees(adjacency)

Given a graph represented as an adjacency matrix, return a list giving the degree of each vertex.

graph_union(m1, m2, ...)

Given arbitrarily many adjacency matrices representing graphs, return an adjacency matrix representing the union of those graphs.

cartesian_product(m1, m2, ...)

Given arbitrarily many adjacency matrices representing graphs, return an adjacency matrix representing the cartesian product of those graphs.

direct_product(m1, m2, ...)

Given arbitrarily many adjacency matrices representing graphs, return an adjacency matrix representing the direct product of those graphs.

adjacency permutation(p,m)

Apply the given permutation p, represented as a list where p[i] gives the image of i under p, to the vertices of the graph represented by the adjacency matrix m.

Returns an adjacency matrix.

is_graph_isomorphism(p,m)

Returns true if the permutation p is an isomorphism of the graph represented by the adjacency matrix m.

edges_from_weight_matrix(weights)

weights is a 2D array, where weights[i][j] gives the weight of the edge between vertices i and j, or -1 if there's no edge.

Returns a list of edges represented as objects {from, to, weight}.

kruskals_algorithm(weights)

Find a minimum spanning forest of the graph represented by weights, using Kruskal's algorithm.

weights is a 2D array representing the weights of edges in a graph, which will be passed to edges_from_weight_matrix to produce a list of edges.

Returns a list of edges, each represented by an object {from, to, weight}.

prims_algorithm(weights)

Find a minimum spanning tree of the graph represented by weights, using Prim's algorithm. The graph must be connected.

weights is a 2D array representing the weights of edges in a graph, which will be passed to edges_from_weight_matrix to produce a list of edges.

Returns a list of edges, each represented by an object {from, to, weight}.

]]>
What colour is that? https://somethingorotherwhatever.com/items/what-colour-is-that 2021-10-30T06:56:22.867000Z Point your camera at something, nad this tells you what colour it is.

]]>

I'm really colourblind. There are quite a few apps that let you point your camera at something and tell you what colour it is, but they're either too erratic or too precise in the names of colours they give.

After years of frustration, I decided to make my own. This does a few things:

  • it averages the sample over a second or two, so the colour it's matching doesn't flicker with camera noise.
  • it uses a simple list of colours, because anything more specific is useless to me, and gives the top 5 closest matches in case it's between a few named colours, along with bars showing how confident it is.
  • I weighted the colour names, so you have to be really close to 'teal' for it to say 'teal'.
  • it uses the CIEDE2000 metric to calculate the closest colours, which matches perceived colour better than Euclidean distance in RGB space.
  • most of the screen is filled with the colour it's thinking about, with a small peephole for the camera view, so you can see the colour it's naming.
]]>
Line-by-line derivation https://somethingorotherwhatever.com/items/line-by-line-derivation 2021-10-21T11:34:55.274000Z A thing for writing out line-by-line mathematical derivations more conveniently than just TeX allows

]]>
A thing for writing out line-by-line mathematical derivations more conveniently than just TeX allows

]]>
Behind the design of Numbas https://somethingorotherwhatever.com/items/behind-the-design-of-numbas 2021-08-25T12:18:52Z A collection of articles about the motivation and research behind the design of the Numbas system

]]>
Behind the design of Numbas

In this repository I'm collecting essays and documentation on the design decisions behind the Numbas system.

Building

The notes are written using Sphinx. Install it using pip:

pip install -r requirements.txt

To build the HTML version, run:

make html

]]>
QTI to Numbas https://somethingorotherwhatever.com/items/qti-to-numbas 2021-08-17T14:00:12Z A tool to convert a bank of QTI items to Numbas

]]>
QTI to Numbas

A tool to convert QTI packages to Numbas exams.

This is an ambitious goal! At the moment, it can convert the following kinds of packages:

  • a bank of multiple choice questions exported from Blackboard in QTI 2.1 format.
  • a Canvas quiz created using the old quiz engine, exported in QTI 1.2 format.

It could be expanded to support more of the QTI specification.

There is no real error handling: packages containing unsupported items will fail.

I (Christian Lawson-Perfect) don't have access to Blackboard, so if you have a QTI package that doesn't work, please send it to me and I'll try to work out how to support it.

Installation

This is a Python 3 script which requires a couple of packages to be installed.

To install the packages, run:

pip install -r requirements.txt

Usage

To convert a package called question_bank.zip, run:

python qti_to_numbas.py question_bank.zip

A .exam file containing all of the questions in the question bank will be created in the current directory. You can upload this file to the Numbas editor.

To do

  • Deal with generic/correct/incorrect feedback in Canvas quizzes.
]]>
A lullaby sequence https://somethingorotherwhatever.com/items/a-lullaby-sequence 2021-07-14T08:48:17Z My son was born last September. While he doesn’t hate sleep as much as his sister did, he still needs a bit of help to drop off. I’m not at all musically inclined, and I seem unable to …

]]>

My son was born last September. While he doesn’t hate sleep as much as his sister did, he still needs a bit of help to drop off. I’m not at all musically inclined, and I seem unable to …

]]>
WhyStartAt.xyz https://somethingorotherwhatever.com/items/whystartat-xyz 2021-07-04T23:00:00Z A collaborative site collecting ambiguities, inconsistencies and other unpleasantness in the conventions of mathematical notation.

]]>

A collaborative site collecting ambiguities, inconsistencies and other unpleasantness in the conventions of mathematical notation.

]]>
The Unicode guessing game https://somethingorotherwhatever.com/items/the-unicode-guessing-game 2021-06-24T11:05:01.917000Z A game where you're shown a Unicode character and have to work out its name

]]>

A game where you're shown a Unicode character and have to work out its name

]]>
Wordsearch generator mk 2 https://somethingorotherwhatever.com/items/wordsearch-generator-mk-2 2021-06-15T07:52:14.968000Z A wordsearch generator, written in Elm

]]>

A wordsearch generator, written in Elm

]]>
Elm on Glitch https://somethingorotherwhatever.com/items/elm-on-glitch 2021-05-14T13:27:51.203000Z A starter Glitch.com project for things written in Elm.

]]>
A starter Glitch.com project for things written in Elm.

]]>
Pentagonal spirals https://somethingorotherwhatever.com/items/pentagonal-spirals 2021-05-13T06:01:29.344000Z Can you make a rule for laying out a pentagonal spiral, so it goes on forever?

]]>

Can you make a rule for laying out a pentagonal spiral, so it goes on forever?

]]>
Your laptop knows more than Euler https://somethingorotherwhatever.com/items/your-laptop-knows-more-than-euler 2021-05-12T19:17:05Z A Jupyter notebook to accompany a post on The Aperiodical by Connor Krill. It shows that computers can find Mersenne primes much faster than Édouard Lucas (Connor got the wrong mathematician originally).

]]>

A Jupyter notebook to accompany a post on The Aperiodical by Connor Krill. It shows that computers can find Mersenne primes much faster than Édouard Lucas (Connor got the wrong mathematician originally).

]]>
My robot draws TeX https://somethingorotherwhatever.com/items/my-robot-draws-tex 2021-04-08T13:32:44Z For my birthday I got an EleksDraw pen plotter. It’s a cheap and cheerful example of the form: a pair of orthogonal metal rods with a pen on the end, attached to electric motors. The idea is …

]]>

For my birthday I got an EleksDraw pen plotter. It’s a cheap and cheerful example of the form: a pair of orthogonal metal rods with a pen on the end, attached to electric motors. The idea is …

]]>
Postcard maker https://somethingorotherwhatever.com/items/postcard-maker 2021-04-08T12:49:30Z A web page to create a postcard, for my pen plotter to draw. The text can include mathematical notation, rendered using MathJax.

]]>

A web page to create a postcard, for my pen plotter to draw. The text can include mathematical notation, rendered using MathJax.

]]>
Which One Doesn't Belong? maker https://somethingorotherwhatever.com/items/which-one-doesn-t-belong-maker 2021-04-01T05:54:51.186000Z A tool to make 'Which One Doesn't Belong?' grids - a 2×2 square of images.

]]>

A tool to make 'Which One Doesn't Belong?' grids - a 2×2 square of images.

]]>
Extract data from a Numbas exam https://somethingorotherwhatever.com/items/extract-data-from-a-numbas-exam 2021-03-31T08:17:34.214000Z A page made to show how to embed a Numbas exam and extract the attempt data from it.

]]>

A page made to show how to embed a Numbas exam and extract the attempt data from it.

]]>
Plotter tools https://somethingorotherwhatever.com/items/plotter-tools 2021-02-15T08:13:46Z This is a web-based controller for my pen plotter, an EleksDraw.

]]>

plotterweb

This is a web-based controller for my pen plotter, an EleksDraw.

It uses vpype to read in SVG files and produce a load of line segments, then sends GCode to a plotter device connected on a serial port, which it tries to detect.

There are two processes that need to run: the web server, and the worker which talks to the plotter.

To run the web server:

python manage.py runserver

To run the worker:

python manage.py runworker plotter-manager

]]>
MathsKlatch 2020 camera operator https://somethingorotherwhatever.com/items/mathsklatch-2020-camera-operator 2020-11-14T12:08:21Z Some bits to help record talks delivered in gather.town.

]]>
MathsKlatch 2020 camera operator stuff

This repository contains files for the camera operator at MathsKlatch 2020.

bookmarklet.js contains a JavaScript bookmarklet which will toggle the intruding bits of the gather.town UI off, so you can capture just the speaker's video.

MathsJam_2020.obs is an OBS scene collection. One scene is configured to capture a window, and there are two other scenes containing images to switch to while fiddling with things. I don't think this will copy across to another device well, but at least it's a starting point.

]]>
Download text file extension for Numbas https://somethingorotherwhatever.com/items/download-text-file-extension-for-numbas 2020-10-29T10:00:27Z This Numbas extension adds functions to create links for students to download randomly-generated files.

]]>
Download text file

This extension provides a function download_link(filename,content,link_text), which creates an HTML link tag with the given link tag. When the student clicks on the link, a file with the given filename and content is downloaded.

There's a demo question showing how to use this extension.

download_link(filename,content,link_text)

Creates an HTML link tag which downloads a file with the given filename and text content. If you don't give link_text, the link reads "Download filename".

csv(data,headers)

Format a set of data as a CSV file.

  • If data is a list of lists, The second argument headers is an optional list of strings to use as column headers.
  • If data is a list of dictionaries, the output contains a column for each distinct key in those dictionaries.
  • If data is a dictionary, it's assumed to map headers to columns of data.
]]>
Gaussian origami https://somethingorotherwhatever.com/items/gaussian-origami 2020-10-22T10:43:19Z Inspired by a question on math-fun.

]]>

Inspired by a question on math-fun.

]]>
Lean Blockly https://somethingorotherwhatever.com/items/lean-blockly 2020-10-09T12:42:23.073000Z I had a thought about using Blockly to construct proofs, which would be translated to Lean code for evaluation.

]]>

I had a thought about using Blockly to construct proofs, which would be translated to Lean code for evaluation.

]]>
Fix the maths on wordpress.com https://somethingorotherwhatever.com/items/fix-the-maths-on-wordpress-com 2020-10-01T09:05:11.010000Z A bookmarklet to replace all the maths rendered as images on wordpress.com blogs with a better rendering using MathJax.

]]>
A bookmarklet to replace all the maths rendered as images on wordpress.com blogs with a better rendering using MathJax.

]]>
The enormous difficulty of telling the truth about escalators with statistics https://somethingorotherwhatever.com/items/the-enormous-difficulty-of-telling-the-truth-about-escalators-with-statistics 2020-09-02T13:25:35Z Earlier this year, when getting the train to work was still a thing for me, I noticed this statistic: 95% of the time escalators were working in the last four weeks.

]]>

Earlier this year, when getting the train to work was still a thing for me, I noticed this statistic: 95% of the time escalators were working in the last four weeks.

]]>
Unix permutation clock https://somethingorotherwhatever.com/items/unix-permutation-clock 2020-08-28T14:22:37.494000Z A clock which shows a different permutation of a deck of cards each second, for the next 10^60 years

]]>

A clock which shows a different permutation of a deck of cards each second, for the next 10^60 years

]]>
The permutation clock https://somethingorotherwhatever.com/items/the-permutation-clock 2020-08-26T12:19:16.141000Z A different permutation of the cards every second.

]]>

A different permutation of the cards every second.

]]>
transcriptpage https://somethingorotherwhatever.com/items/transcriptpage 2020-08-03T11:08:12Z A tool to create a page showing a video next to its transcript

]]>

transcriptpage

transcriptpage is a tool which takes a video and a captions file, and creates a web page which displays the video alongside the transcript.

Each sentence in the transcript is displayed on a separate line, along with a timestamp; clicking on the timestamp jumps the video to that sentence.

How to use it

transcriptpage is a Python 3 script. It has been tested with python 3.8.

At the moment, it only supports videos on Vimeo. Soon, it will support YouTube as well.

It requires a few Python packages, which can be installed with pip:

python pip install -r requirements.txt

To create a page, you need a captions file in .srt format and the address of the video. The command takes two arguments: the local path of the .srt file, and the address of the video.

./transcriptpage captions.srt https://vimeo.com/442721457

]]>
Inclusive e-assessment https://somethingorotherwhatever.com/items/inclusive-e-assessment 2020-06-25T10:50:09Z A talk given at EAMS 2020. Presented both as a video and a series of slides with accompanying transcript.

]]>

A talk given at EAMS 2020. Presented both as a video and a series of slides with accompanying transcript.

]]>
Absolutely huge memory https://somethingorotherwhatever.com/items/absolutely-huge-memory 2020-04-26T07:59:47.309000Z A memory game that is bigger than you'll ever be able to deal with

]]>

A memory game that is bigger than you'll ever be able to deal with

]]>
Wobbly clock! https://somethingorotherwhatever.com/items/wobbly-clock 2020-04-16T06:13:10.410000Z A wobbly clock

]]>

A wobbly clock

]]>
Moodle SCORM report for Numbas https://somethingorotherwhatever.com/items/moodle-scorm-report-for-numbas 2020-04-03T13:01:32Z This Moodle plugin provides a special report for Moodle's SCORM player, for use with Numbas exams.

]]>
Numbas report for Moodle SCORM

This Moodle plugin provides a special report for Moodle's SCORM player, for use with Numbas exams.

For each attempt, it shows the student's answers and scores against the correct answer for each part, in an easier to read form than Moodle's built-in "track details" view.

Installation

Clone this repository into the folder mod/scorm/report/numbas inside your Moodle folder, then go to Site administration → Notifications and click to install it.

Usage

Click on a Numbas SCORM package, then click Reports → Numbas report.

Click on the attempt number for the attempt you want to look at. You'll be shown a breakdown of the student's answers and scores for that attempt.

Licence

Copyright (C) 2020-2021 Newcastle University

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.

]]>
Make it rain, Bloomberg! https://somethingorotherwhatever.com/items/make-it-rain-bloomberg 2020-03-06T19:31:56.888000Z If you wanted to give the same amount to everyone in a place, how much would each person get?

]]>

If you wanted to give the same amount to everyone in a place, how much would each person get?

]]>
Chirun in Docker https://somethingorotherwhatever.com/items/chirun-in-docker 2020-03-06T14:11:39Z A Docker container for running Chirun.

]]>
To build, run make, which runs this:

docker build . --build-arg VERSION=(latest commit hash)

]]>
Chirun https://somethingorotherwhatever.com/items/chirun 2020-03-05T14:41:09Z A tool to produce accessible lecture notes from LaTeX or Markdown source. I took over development from George Stagg.

]]>

Chirun produces flexible and accessible course notes, in a variety of formats, from LaTeX or Markdown source. It is aimed primarily at notes in the mathematical sciences.

This repository, chirun, is the source code of the Chirun Python package, providing the command line interface for building content.

Documentation

The Chirun documentation, including infromation about the Chirun Public Content Builder and Chirun LTI Provider can be found at,

https://chirun.readthedocs.io/en/latest/

How it works

A set of course notes are provided in either Markdown or LaTeX along with a configuration file config.yml. The chirun command then builds the requested outputs based on the contents of the configuration file.


Prerequisites

Linux (Ubuntu 18.10+)

  • Ensure a system TeX distribution is installed, such as TeX Live (apt install texlive-full).
  • Install pdf2svg, pdftoppm, pdftk and libyaml using your standard package manager (apt install pdf2svg poppler-utils libyaml-dev pdftk-java).
  • Ensure the virtualenv python package is installed (apt install python3-virtualenv).

MacOS

  • Install a system TeX distribution, such as MacTeX from https://tug.org/mactex/.
  • Install Homebrew by following the instructions at https://brew.sh and once installed use the brew command to install pdf2svg, pdftoppm, pdftk and libyaml:
  • brew install poppler
  • brew install pdf2svg
  • brew install libyaml
  • brew install pdftk-java
  • Install virtualenv by running pip3 install virtualenv.
  • If you are not using the default Apple-provided build of Python 3 ( e.g. Python is installed under /Applications/Python 3.X, where 3.X is the version), ensure that the SSL CA certificates are installed by running:
    • sudo /Applications/Python\ 3.X/Install\ Certificates.command

Quick Installation

  • Create a Python3 virtualenv: virtualenv -p python3 chirun_env and activate it: source ./chirun_env/bin/activate
  • Install chirun: pip install git+https://github.com/chirun-ncl/chirun.git

The command chirun is now available for use. You should now compile the sample course and ensure everything works.

Upgrade Instructions

  • Run the following command with the virtualenv active to upgrade the installed version of chirun:
  • pip install --upgrade git+https://github.com/chirun-ncl/chirun.git
  • You may need to run the above command with an extra --force-reinstall argument if the version number has not been changed between updates.

Development installation

  • Create a Python3 virtualenv: virtualenv -p python3 chirun_env and activate it: source ./chirun_env/bin/activate
  • Clone the repository: git clone https://github.com/chirun-ncl/chirun.git
  • cd chirun
  • Install all the requirements: pip install -r requirements.txt
  • Install the chirun tool into your environment: pip install -e .

The command chirun is now available for use. You should now compile the sample course and ensure everything works.

Development Upgrade Instructions

  • To upgrade the development installation pull the latest changes from this git repository and install any new requirements, e.g.
  • cd chirun
  • git pull
  • pip install -r requirements.txt

Upgrading from makecourse

The project has recently been renamed from "makecourse" to "chirun". To upgrade, first remove the older makecourse package with,

pip uninstall makecourse

Then follow the installation or upgrade instructions above.


Demo

Sample course, and its source code.

Compile the Sample Course

  • Install the chirun package using the instructions above
  • Clone the sample course: git clone https://github.com/chirun-ncl/sample_course.git
  • Change into the directory you just cloned to and run make to build and view a local version of the sample course.
  • The finished website output will be in ./sample_course/build

]]>
Animations https://somethingorotherwhatever.com/items/animations 2020-03-03T18:57:04Z Some looping animations that I made.

]]>

Some looping animations that I made.

]]>
SAMDOB - The order of operations https://somethingorotherwhatever.com/items/samdob-the-order-of-operations 2020-02-20T13:21:37Z A tool to play around with the order of operations

]]>

SAMDOB

A tool to play around with the order of operations.

Why?

Pretty much everyone is taught a mnemonic for the order of arithmetic operations.

Some people are taught BODMAS, some are taught BIMDAS, while PEMDAS is popular in other parts of the world.

They describe the order in which you should carry out operations, but you need some more rules as well, that don't fit into a snappy mnemonic:

  • Consider each operation in turn, reading the mnemonic from left to right.
  • Read the expression from left to right. When you encounter the current operation, replace it with its numerical result.
  • When you get to the end of the expression, go back to the start and move to the next operation in the mnemonic.

Except multiplication and division, and addition and subtraction, have the same precedence: you consider them both at the same time, rather than one after the other. The mnemonic doesn't mention this.

It's actually quite fiddly, but the fiddliness rarely makes a difference, if you've got common sense.

What if you didn't have any common sense?

So

SAMDOB lets you see how the order of operations is applied. When you write an expression in the right-hand box, the steps taken to evaluate it to a number are shown underneath.

You can change the order of operations by writing a mnemonic in the left-hand box. Once you've done that, the sequence is described underneath.

Letters grouped in brackets have the same precedence.

]]>
A paper version of the Seven Triples puzzle https://somethingorotherwhatever.com/items/a-paper-version-of-the-seven-triples-puzzle 2020-02-20T11:25:04Z Last year I wrote about a 3D-printed puzzle I’d designed, called Seven Triples. At work we want to use this puzzle during an A-Level enrichment day, which means we need about twenty copies of…

]]>

Last year I wrote about a 3D-printed puzzle I’d designed, called Seven Triples. At work we want to use this puzzle during an A-Level enrichment day, which means we need about twenty copies of…

]]>
Triangular squares https://somethingorotherwhatever.com/items/triangular-squares 2020-02-12T12:24:14.404000Z A nice looping animation showing a triangular lattice morphing to a square grid

]]>

A nice looping animation showing a triangular lattice morphing to a square grid

]]>
Triangular square 1 https://somethingorotherwhatever.com/items/triangular-square-1 2020-02-11T15:26:15.655000Z A nice looping animation showing a triangular lattice morphing to a square grid

]]>

A nice looping animation showing a triangular lattice morphing to a square grid

]]>
Draggy box https://somethingorotherwhatever.com/items/draggy-box 2020-01-24T09:39:11.880000Z Game/puzzle to do with shuffling boxes

]]>

Game/puzzle to do with shuffling boxes

]]>
The Conant gasket https://somethingorotherwhatever.com/items/the-conant-gasket 2020-01-15T09:06:12.051000Z Draws the Conant gasket, a fractal which ought to be better known.

]]>

Draws the Conant gasket, a fractal which ought to be better known.

]]>
Numbas parts graph https://somethingorotherwhatever.com/items/numbas-parts-graph 2019-12-19T09:37:54.259000Z I was trying to make something to visualise the flow of parts in a Numbas explore mode question.

]]>

I was trying to make something to visualise the flow of parts in a Numbas explore mode question.

]]>
TikZJax demo https://somethingorotherwhatever.com/items/tikzjax-demo 2019-12-10T09:15:05.386000Z Jim Fowler's TikZJax is incredible, but it needed an easy way of trying it out. So I made one.

]]>

Jim Fowler's TikZJax is incredible, but it needed an easy way of trying it out. So I made one.

]]>
Automatic Namesby https://somethingorotherwhatever.com/items/automatic-namesby 2019-11-18T15:01:23.515000Z Uses some word lists to come up with random fake place names and show them in street signs. Prompted by the thought that glitch's automatic project URLs would be cuter if they were place names.

]]>

Uses some word lists to come up with random fake place names and show them in street signs. Prompted by the thought that glitch's automatic project URLs would be cuter if they were place names.

]]>
My adventures in 3D printing: Seven Triples puzzle https://somethingorotherwhatever.com/items/my-adventures-in-3d-printing-seven-triples-puzzle 2019-11-07T11:36:59Z At work we’ve got a 3D printer. In this series of posts I’ll share some of the designs I’ve made. There are seven kinds of shape. There are three copies of each shape. The pieces …

]]>

At work we’ve got a 3D printer. In this series of posts I’ll share some of the designs I’ve made. There are seven kinds of shape. There are three copies of each shape. The pieces …

]]>
Baked sudoku https://somethingorotherwhatever.com/items/baked-sudoku 2019-11-05T00:00:00Z You can impose on Sudoku puzzles a physical system which works surprisingly well. It has phase transitions, and when you reduce the heat it settles into a solved state!

]]>

You can impose on Sudoku puzzles a physical system which works surprisingly well. It has phase transitions, and when you reduce the heat it settles into a solved state!

]]>
Flock paths https://somethingorotherwhatever.com/items/flock-paths 2019-11-04T11:23:42Z An arty thing inspired by the Herschel enneahedron.

]]>

An arty thing inspired by the Herschel enneahedron.

The genesis of this was thinking about how to show that the Herschel graph is non-Hamiltonian: there's no path that visits every vertex once.

This simulates flocking gliders, who move between the points on the graph. Because the graph is non-Hamiltonian, every glider is bound to re-visit a vertex before they've completed the tour.

]]>
The homologist's nightmare https://somethingorotherwhatever.com/items/the-homologist-s-nightmare 2019-10-15T09:44:30.712000Z Lots and lots and lots of overlapping rings

]]>

Lots and lots and lots of overlapping rings

]]>
Get the coins out of the bank https://somethingorotherwhatever.com/items/get-the-coins-out-of-the-bank 2019-10-07T07:56:54.470000Z A puzzle from the maths-fun mailing list.

]]>

A puzzle from the maths-fun mailing list.

]]>
Number dress-up party https://somethingorotherwhatever.com/items/number-dress-up-party 2019-09-18T10:24:44.792000Z All the numbers have come to a party in fancy dress.

]]>

All the numbers have come to a party in fancy dress.

]]>
Sierpinski interpolation https://somethingorotherwhatever.com/items/sierpinski-interpolation 2019-09-16T23:00:00Z This is known in some places as the chaos game: if you repeatedly move halfway towards a randomly chosen vertex of an equilateral triangle, the positions you can end up together make the Sierpiński triangle. In this one, press the keys 1, 2 and 3 to move to each vertex.

]]>

This is known in some places as the chaos game: if you repeatedly move halfway towards a randomly chosen vertex of an equilateral triangle, the positions you can end up together make the Sierpiński triangle. In this one, press the keys 1, 2 and 3 to move to each vertex.

]]>
S.O.X. https://somethingorotherwhatever.com/items/s-o-x 2019-08-31T23:00:00Z An adaptation of the book Solo Noughts and Crosses

]]>

An adaptation of the book Solo Noughts and Crosses

]]>
TMiP 2019 - The Big Internet Math-Off https://somethingorotherwhatever.com/items/tmip-2019-the-big-internet-math-off 2019-08-11T23:00:00Z About the Big Internet Math-Off, a competition I ran on The Aperiodical. Given at Talking Maths in Public.

]]>

About the Big Internet Math-Off, a competition I ran on The Aperiodical. Given at Talking Maths in Public.

]]>
Incident counter https://somethingorotherwhatever.com/items/incident-counter 2019-06-17T06:00:38.792000Z Inspired by the 'paralellepiped incident' joke that some friends make. You reocrd an incident, and when you come back later it tells you how long since the last incident.

]]>

Inspired by the 'paralellepiped incident' joke that some friends make. You reocrd an incident, and when you come back later it tells you how long since the last incident.

]]>
CLP's Nice Calculator https://somethingorotherwhatever.com/items/clp-s-nice-calculator 2019-05-16T09:26:27Z An RPN calculator with some nice features

]]>

CLP's Nice calculator

An RPN calculator with some nifty features.

  • The operation history is kept, and you can change input numbers to automatically recalculate the result.
  • When you duplicate numbers, both copies are linked so a change to one is applied to the other simultaneously.
]]>
Eukleides extension for Numbas https://somethingorotherwhatever.com/items/eukleides-extension-for-numbas 2019-05-02T13:19:14Z An extension for Numbas which provides the Eukleides geometrical drawing language.

]]>

Eukleides extension for Numbas

This extension for Numbas contains a port of the Eukleides geometrical drawing language by Christian Obrecht, with extensions to make diagrams interactive and accessibility improvements.

Documentation

There's documentation on how the extension works and a full function reference.

See the demo page for a gallery of examples, and the interactive playground to draw your own diagrams.

Development

The extension is written using ES6 syntax and features. This is compiled with babeljs to ES5, which is supported by lots more browsers.

dev_demo.html and dev_playground.html load the source scripts directly, on browsers which support ES6.

To install the babeljs tools, first install nodejs and then run:

npm install

Then, when you make a change to the source, run

make

to compile the scripts in the dist folder.

You might need to set the environment variable NUMBAS_RUNTIME_PATH to the location of your Numbas compiler directory.

License

© 2019 Christian Lawson-Perfect for Newcastle University.

The original Eukleides is © 2004-2010 Christian Obrecht.

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.

Some code is taken from g9, and used under the terms of the MIT license.

Data from ColorBrewer2 is used under the terms of the Apache 2.0 license.

]]>
My RedBubble shop https://somethingorotherwhatever.com/items/my-redbubble-shop 2019-03-11T00:00:00Z I've made a few mathsy t-shirt designs.

]]>

I've made a few mathsy t-shirt designs.

]]>
Statistics extension for Numbas https://somethingorotherwhatever.com/items/statistics-extension-for-numbas 2019-02-25T12:44:46Z A Numbas extension providing a wrapper around the jStat library

]]>
Statistics extension for Numbas

This extension provides a load of statistical functions, wrapping the jStat library.

There's documentation at docs.numbas.org.uk.

Functions

This list of functions contains descriptions copied from the jStat documentation. Click on the function name to see the original documentation.

Descriptive statistics of a list of numbers

sum(array)

Returns the sum of the array vector.

sumsqrd(array)

Returns the sum squared of the array vector.

sumsqerr(array)

Returns the sum of squared errors of prediction of the array vector.

product(array)

Returns the product of the array vector.

min(array)

Returns the minimum value of the array vector.

max(array)

Returns the maximum value of the array vector.

mean(array)

Returns the mean of the array vector.

meansqerr(array)

Returns the mean squared error of the array vector.

geomean(array)

Returns the geometric mean of the array vector.

median(array)

Returns the median of the array vector.

cumsum(array)

Returns an array of partial sums in the sequence.

diff(array)

Returns an array of the successive differences of the array.

range(array)

Returns the range of the array vector.

variance(array)

Returns the variance of the array vector. By default, the population variance is calculated. Passing true to flag indicates to compute the sample variance instead.

stdev(array)

Returns the standard deviation of the array vector. By default, the population standard deviation is returned. Passing true to flag returns the sample standard deviation.

meandev(array)

Returns the mean absolute deviation of the array vector.

meddev(array)

Returns the median absolute deviation of the array vector.

coeffvar(array)

Returns the coefficient of variation of the array vector.

quartiles(array)

Returns the quartiles of the array vector.

Correlation of two samples

covariance(array1, array2)

Returns the covariance of the array1 and array2 vectors.

corrcoeff(array1, array2)

Returns the population correlation coefficient of the array1 and array2 vectors (Pearson's Rho).

stdev(array, is_sample)

Returns the standard deviation of the array vector. By default, the population standard deviation is returned. Passing true to flag returns the sample standard deviation.

variance(array, is_sample)

Returns the variance of the array vector. By default, the population variance is calculated. Passing true to flag indicates to compute the sample variance instead.

mode(array)

Returns the mode of the array vector. If there are multiple modes then mode() will return all of them.

Distributions

betapdf(x, alpha, beta)

Returns the value of x in the Beta distribution with parameters alpha and beta.

betacdf(x, alpha, beta)

Returns the value of x in the cdf for the Beta distribution with parameters alpha and beta.

betainv(p, alpha, beta)

Returns the value of p in the inverse of the cdf for the Beta distribution with parameters alpha and beta.

betamean(alpha, beta)

Returns the mean of the Beta distribution with parameters alpha and beta.

betamedian(alpha, beta)

Returns the median of the Beta distribution with parameters alpha and beta.

betamode(alpha, beta)

Returns the mode of the Beta distribution with parameters alpha and beta.

betasample(alpha, beta)

Returns a random number whose distribution is the Beta distribution with parameters alpha and beta.

betavariance(alpha, beta)

Returns the variance of the Beta distribution with parameters alpha and beta.

centralFpdf(x, df1, df2)

Given x in the range [0, infinity), returns the probability density of the (central) F distribution at x.

centralFcdf(x, df1, df2)

Given x in the range [0, infinity), returns the cumulative probability density of the central F distribution. That is, jStat.centralF.cdf(2.5, 10, 20) will return the probability that a number randomly selected from the central F distribution with df1 = 10 and df2 = 20 will be less than 2.5.

centralFinv(p, df1, df2)

Given p in [0, 1), returns the value of x for which the cumulative probability density of the central F distribution is p. That is, jStat.centralF.inv(p, df1, df2) = x if and only if jStat.centralF.inv(x, df1, df2) = p.

centralFmean(df1, df2)

Returns the mean of the (Central) F distribution.

centralFmode(df1, df2)

Returns the mode of the (Central) F distribution.

centralFsample(df1, df2)

Returns a random number whose distribution is the (Central) F distribution.

centralFvariance(df1, df2)

Returns the variance of the (Central) F distribution.

cauchypdf(x, local, scale)

Returns the value of x in the pdf of the Cauchy distribution with a location (median) of local and scale factor of scale.

cauchycdf(x, local, scale)

Returns the value of x in the cdf of the Cauchy distribution with a location (median) of local and scale factor of scale.

cauchyinv(p, local, scale)

Returns the value of p in the inverse of the cdf for the Cauchy distribution with a location (median) of local and scale factor of scale.

cauchymedian(local, scale)

Returns the value of the median for the Cauchy distribution with a location (median) of local and scale factor of scale.

cauchymode(local, scale)

Returns the value of the mode for the Cauchy distribution with a location (median) of local and scale factor of scale.

cauchysample(local, scale)

Returns a random number whose distribution is the Cauchy distribution with a location (median) of local and scale factor of scale.

chisquarepdf(x, dof)

Returns the value of x in the pdf of the Chi Square distribution with dof degrees of freedom.

chisquarecdf(x, dof)

Returns the value of x in the cdf of the Chi Square distribution with dof degrees of freedom.

chisquareinv(p, dof)

Returns the value of x in the inverse of the cdf for the Chi Square distribution with dof degrees of freedom.

chisquaremean(dof)

Returns the value of the mean for the Chi Square distribution with dof degrees of freedom.

chisquaremedian(dof)

Returns the value of the median for the Chi Square distribution with dof degrees of freedom.

chisquaremode(dof)

Returns the value of the mode for the Chi Square distribution with dof degrees of freedom.

chisquaresample(dof)

Returns a random number whose distribution is the Chi Square distribution with dof degrees of freedom.

chisquarevariance(dof)

Returns the value of the variance for the Chi Square distribution with dof degrees of freedom.

exponentialpdf(x, rate)

Returns the value of x in the pdf of the Exponential distribution with the parameter rate (lambda).

exponentialcdf(x, rate)

Returns the value of x in the cdf of the Exponential distribution with the parameter rate (lambda).

exponentialinv(p, rate)

Returns the value of p in the inverse of the cdf for the Exponential distribution with the parameter rate (lambda).

exponentialmean(rate)

Returns the value of the mean for the Exponential distribution with the parameter rate (lambda).

exponentialmedian(rate)

Returns the value of the median for the Exponential distribution with the parameter rate (lambda)

exponentialmode(rate)

Returns the value of the mode for the Exponential distribution with the parameter rate (lambda).

exponentialsample(rate)

Returns a random number whose distribution is the Exponential distribution with the parameter rate (lambda).

exponentialvariance(rate)

Returns the value of the variance for the Exponential distribution with the parameter rate (lambda).

gammapdf(x, shape, scale)

Returns the value of x in the pdf of the Gamma distribution with the parameters shape (k) and scale (theta). Notice that if using the alpha beta convention, scale = 1/beta.

gammacdf(x, shape, scale)

Returns the value of x in the cdf of the Gamma distribution with the parameters shape (k) and scale (theta). Notice that if using the alpha beta convention, scale = 1/beta.

gammainv(p, shape, scale)

Returns the value of p in the inverse of the cdf for the Gamma distribution with the parameters shape (k) and scale (theta). Notice that if using the alpha beta convention, scale = 1/beta.

gammamean(shape, scale)

Returns the value of the mean for the Gamma distribution with the parameters shape (k) and scale (theta). Notice that if using the alpha beta convention, scale = 1/beta.

gammamode(shape, scale)

Returns the value of the mode for the Gamma distribution with the parameters shape (k) and scale (theta). Notice that if using the alpha beta convention, scale = 1/beta.

gammasample(shape, scale)

Returns a random number whose distribution is the Gamma distribution with the parameters shape (k) and scale (theta). Notice that if using the alpha beta convention, scale = 1/beta.

gammavariance(shape, scale)

Returns the value of the variance for the Gamma distribution with the parameters shape (k) and scale (theta). Notice that if using the alpha beta convention, scale = 1/beta.

invgammapdf(x, shape, scale)

Returns the value of x in the pdf of the Inverse-Gamma distribution with parametres shape (alpha) and scale (beta).

invgammacdf(x, shape, scale)

Returns the value of x in the cdf of the Inverse-Gamma distribution with parametres shape (alpha) and scale (beta).

invgammainv(p, shape, scale)

Returns the value of p in the inverse of the cdf for the Inverse-Gamma distribution with parametres shape (alpha) and scale (beta).

invgammamean(shape, scale)

Returns the value of the mean for the Inverse-Gamma distribution with parametres shape (alpha) and scale (beta).

invgammamode(shape, scale)

Returns the value of the mode for the Inverse-Gamma distribution with parametres shape (alpha) and scale (beta).

invgammasample(shape, scale)

Returns a random number whose distribution is the Inverse-Gamma distribution with parametres shape (alpha) and scale (beta).

invgammavariance(shape, scale)

Returns the value of the variance for the Inverse-Gamma distribution with parametres shape (alpha) and scale (beta).

kumaraswamypdf(x, alpha, beta)

Returns the value of x in the pdf of the Kumaraswamy distribution with parameters a and b.

kumaraswamycdf(x, alpha, beta)

Returns the value of x in the cdf of the Kumaraswamy distribution with parameters alpha and beta.

kumaraswamyinv(p, alpha, beta)

Returns the value of p in the inverse of the pdf for the Kumaraswamy distribution with parametres alpha and beta.

kumaraswamymean(alpha, beta)

Returns the value of the mean of the Kumaraswamy distribution with parameters alpha and beta.

kumaraswamymedian(alpha, beta)

Returns the value of the median of the Kumaraswamy distribution with parameters alpha and beta.

kumaraswamymode(alpha, beta)

Returns the value of the mode of the Kumaraswamy distribution with parameters alpha and beta.

kumaraswamyvariance(alpha, beta)

Returns the value of the variance of the Kumaraswamy distribution with parameters alpha and beta.

lognormalpdf(x, mu, sigma)

Returns the value of x in the pdf of the Log-normal distribution with paramters mu (mean) and sigma (standard deviation).

lognormalcdf(x, mu, sigma)

Returns the value of x in the cdf of the Log-normal distribution with paramters mu (mean) and sigma (standard deviation).

lognormalinv(p, mu, sigma)

Returns the value of x in the inverse of the cdf for the Log-normal distribution with paramters mu (mean of the Normal distribution) and sigma (standard deviation of the Normal distribution).

lognormalmean(mu, sigma)

Returns the value of the mean for the Log-normal distribution with paramters mu (mean of the Normal distribution) and sigma (standard deviation of the Normal distribution).

lognormalmedian(mu, sigma)

Returns the value of the median for the Log-normal distribution with paramters mu (mean of the Normal distribution) and sigma (standard deviation of the Normal distribution).

lognormalmode(mu, sigma)

Returns the value of the mode for the Log-normal distribution with paramters mu (mean of the Normal distribution) and sigma (standard deviation of the Normal distribution).

lognormalsample(mu, sigma)

Returns a random number whose distribution is the Log-normal distribution with paramters mu (mean of the Normal distribution) and sigma (standard deviation of the Normal distribution).

lognormalvariance(mu, sigma)

Returns the value of the variance for the Log-normal distribution with paramters mu (mean of the Normal distribution) and sigma (standard deviation of the Normal distribution).

normalpdf(x, mean, std)

Returns the value of x in the pdf of the Normal distribution with parameters mean and std (standard deviation).

normalcdf(x, mean, std)

Returns the value of x in the cdf of the Normal distribution with parameters mean and std (standard deviation).

normalinv(p, mean, std)

Returns the value of p in the inverse cdf for the Normal distribution with parameters mean and std (standard deviation).

normalmean(mean, std)

Returns the value of the mean for the Normal distribution with parameters mean and std (standard deviation).

normalmedian(mean, std)

Returns the value of the median for the Normal distribution with parameters mean and std (standard deviation).

normalmode(mean, std)

Returns the value of the mode for the Normal distribution with parameters mean and std (standard deviation).

normalsample(mean, std)

Returns a random number whose distribution is the Normal distribution with parameters mean and std (standard deviation).

normalvariance(mean, std)

Returns the value of the variance for the Normal distribution with parameters mean and std (standard deviation).

paretopdf(x, scale, shape)

Returns the value of x in the pdf of the Pareto distribution with parameters scale (x<sub>m</sub>) and shape (alpha).

paretocdf(x, scale, shape)

Returns the value of x in the cdf of the Pareto distribution with parameters scale (x<sub>m</sub>) and shape (alpha).

paretoinv(p, scale, shape)

Returns the inverse of the Pareto distribution with probability p, scale, shape.

paretomean(scale, shape)

Returns the value of the mean of the Pareto distribution with parameters scale (x<sub>m</sub>) and shape (alpha).

paretomedian(scale, shape)

Returns the value of the median of the Pareto distribution with parameters scale (x<sub>m</sub>) and shape (alpha).

paretomode(scale, shape)

Returns the value of the mode of the Pareto distribution with parameters scale (x<sub>m</sub>) and shape (alpha).

paretovariance(scale, shape)

Returns the value of the variance of the Pareto distribution with parameters scale (x<sub>m</sub>) and shape (alpha).

studenttpdf(x, dof)

Returns the value of x in the pdf of the Student's T distribution with dof degrees of freedom.

studenttcdf(x, dof)

Returns the value of x in the cdf of the Student's T distribution with dof degrees of freedom.

studenttinv(p, dof)

Returns the value of p in the inverse of the cdf for the Student's T distribution with dof degrees of freedom.

studenttmean(dof)

Returns the value of the mean of the Student's T distribution with dof degrees of freedom.

studenttmedian(dof)

Returns the value of the median of the Student's T distribution with dof degrees of freedom.

studenttmode(dof)

Returns the value of the mode of the Student's T distribution with dof degrees of freedom.

studenttsample(dof)

Returns a random number whose distribution is the Student's T distribution with dof degrees of freedom.

studenttvariance(dof)

Returns the value of the variance for the Student's T distribution with dof degrees of freedom.

weibullpdf(x, scale, shape)

Returns the value x in the pdf for the Weibull distribution with parameters scale (lambda) and shape (k).

weibullcdf(x, scale, shape)

Returns the value x in the cdf for the Weibull distribution with parameters scale (lambda) and shape (k).

weibullinv(p, scale, shape)

Returns the value of x in the inverse of the cdf for the Weibull distribution with parameters scale (lambda) and shape (k).

weibullmean(scale, shape)

Returns the value of the mean of the Weibull distribution with parameters scale (lambda) and shape (k).

weibullmedian(scale, shape)

Returns the value of the median of the Weibull distribution with parameters scale (lambda) and shape (k).

weibullmode(scale, shape)

Returns the mode of the Weibull distribution with parameters scale (lambda) and shape (k).

weibullsample(scale, shape)

Returns a random number whose distribution is the Weibull distribution with parameters scale (lambda) and shape (k).

weibullvariance(scale, shape)

Returns the variance of the Weibull distribution with parameters scale (lambda) and shape (k).

uniformpdf(x, a, b)

Returns the value of x in the pdf of the Uniform distribution from a to b.

uniformcdf(x, a, b)

Returns the value of x in the cdf of the Uniform distribution from a to b.

uniforminv(p, a, b)

Returns the inverse of the uniform.cdf function; i.e. the value of x for which uniform.cdf(x, a, b) == p.

uniformmean(a, b)

Returns the value of the mean of the Uniform distribution from a to b.

uniformmedian(a, b)

Returns the value of the median of the Uniform distribution from a to b.

uniformmode(a, b)

Returns the value of the mode of the Uniform distribution from a to b.

uniformsample(a, b)

Returns a random number whose distribution is the Uniform distribution from a to b.

uniformvariance(a, b)

Returns the variance of the Uniform distribution from a to b.

binomialpdf(x, n, p)

Returns the value of k in the pdf of the Binomial distribution with parameters n and p.

binomialcdf(x, n, p)

Returns the value of k in the cdf of the Binomial distribution with parameters n and p.

geometricpdf(x, p)

geometriccdf(x, p)

geometricmean(p)

geometricmedian(p)

geometricmode(p)

geometricsample(p)

geometricvariance(p)

negbinpdf(x, r, p)

Returns the value of k in the pdf of the Negative Binomial distribution with parameters n and p.

negbincdf(x, r, p)

Returns the value of x in the cdf of the Negative Binomial distribution with parameters n and p.

hypgeompdf(x, population_size, success_rate, num_draws)

Returns the value of k in the pdf of the Hypergeometric distribution with parameters N (the population size), m (the success rate), and n (the number of draws).

hypgeomcdf(x, population_size, success_rate, num_draws)

Returns the value of x in the cdf of the Hypergeometric distribution with parameters N (the population size), m (the success rate), and n (the number of draws).

poissonpdf(x, l)

Returns the value of k in the pdf of the Poisson distribution with parameter l (lambda).

poissoncdf(x, l)

Returns the value of x in the cdf of the Poisson distribution with parameter l (lambda).

poissonmean(l)

poissonsample(l)

Returns a random number whose distribution is the Poisson distribution with rate parameter l (lamda)

poissonvariance(l)

triangularpdf(x, a, b, c)

Returns the value of x in the pdf of the Triangular distribution with the parameters a, b, and c.

triangularcdf(x, a, b, c)

Returns the value of x in the cdf of the Triangular distribution with the parameters a, b, and c.

triangularinv(p, a, b, c)

triangularmean(a, b, c)

Returns the value of the mean of the Triangular distribution with the parameters a, b, and c.

triangularmedian(a, b, c)

Returns the value of the median of the Triangular distribution with the parameters a, b, and c.

triangularmode(a, b, c)

Returns the value of the mode of the Triangular distribution with the parameters a, b, and c.

triangularsample(a, b, c)

Returns a random number whose distribution is the Triangular distribution with the parameters a, b, and c.

triangularvariance(a, b, c)

Returns the value of the variance of the Triangular distribution with the parameters a, b, and c.

Statistical Tests

zScore(value, mean, sd)

Returns the z-score of value given the data from array. flag===true denotes use of the sample standard deviation.

zScore(value, array)

Returns the z-score of value given the data from array. flag===true denotes use of the sample standard deviation.

zTest(value, mean, sd, sides)

Returns the p-value of value given the data from array. sides is an integer value 1 or 2 denoting a one or two sided z-test. If sides is not specified the test defaults to a two sided z-test. flag===true denotes the use of the sample standard deviation.

zTest(zscore, sides)

Returns the p-value of value given the data from array. sides is an integer value 1 or 2 denoting a one or two sided z-test. If sides is not specified the test defaults to a two sided z-test. flag===true denotes the use of the sample standard deviation.

tScore(value, mean, sd, n)

Returns the t-score of value given the data from array.

tScore(value, array)

Returns the t-score of value given the data from array.

tTest(value, mean, sd, n, sides)

Returns the p-value of value given the data in array. sides is an integer value 1 or 2 denoting a one or two sided t-test. If sides is not specified the test defaults to a two sided t-test.

tTest(tscore, n, sides)

Returns the p-value of value given the data in array. sides is an integer value 1 or 2 denoting a one or two sided t-test. If sides is not specified the test defaults to a two sided t-test.

tTest(value, array, sides)

Returns the p-value of value given the data in array. sides is an integer value 1 or 2 denoting a one or two sided t-test. If sides is not specified the test defaults to a two sided t-test.

anovaFScore(array1, ..., arrayN)

Returns the f-score of an ANOVA on the arrays.

anovaFTest(array1, ..., arrayN)

Returns the p-value of the f-statistic from the ANOVA test on the arrays.

ftest(fscore, df1, df2)

Returns the p-value for the fscore f-score with a df1 numerator degrees of freedom and a df2 denominator degrees of freedom.

Confidence intervals

normalci(value, alpha, sd, n)

Returns a 1-alpha confidence interval for value given a normal distribution in the data from array.

normalci(value, alpha, array)

Returns a 1-alpha confidence interval for value given a normal distribution in the data from array.

tci(value, alpha, sd, n)

Returns a 1-alpha confidence interval for value given the data from array.

tci(value, alpha, array)

Returns a 1-alpha confidence interval for value given the data from array.

Special functions

betafn(x, y)

Evaluates the Beta function at (x,y).

betaln(x, y)

Evaluates the log Beta function at (x,y).

betacf(x, a, b)

Returns the continued fraction for the incomplete Beta function with parameters a and b modified by Lentz's method evaluated at x.

ibetainv(p, a, b)

Returns the inverse of the incomplete Beta function evaluated at (p,a,b).

ibeta(x, a, b)

Returns the incomplete Beta function evaluated at (x,a,b).

gammaln(x)

Returns the Log-Gamma function evaluated at x.

gammafn(x)

Returns the Gamma function evaluated at x. This is sometimes called the 'complete' gamma function.

gammap(a, x)

Returns the lower incomplete gamma function evaluated at (a,x). This function is usually written with a lower case greek gamma character, and is one of the two incomplete gamma functions.

factorialln(n)

Returns the natural log factorial of n.

factorial(n)

Returns the factorial of n.

combination(n, m)

Returns the number of combinations of n, m.

permutation(permutation)

Returns the number of permutations of n, m.

gammapinv(p, a)

Returns the inverse of the lower regularized incomplete Gamma function evaluated at (p,a). This function is the inverse of lowerRegularizedGamma(x, a).

erf(x)

Returns the error function evaluated at x.

erfc(x)

Returns the complementary error function evaluated at x.

erfcinv(p)

Returns the inverse of the complementary error function evaluated at p.

randn(n, m)

Returns a normal deviate (mean 0 and standard deviation 1).

randg(shape, n, m)

Returns a Gamma deviate by the method of Marsaglia and Tsang.

]]>
JSXGraph extension for Numbas https://somethingorotherwhatever.com/items/jsxgraph-extension-for-numbas 2019-02-25T12:36:06Z This extension for Numbas adds the ability to generate diagrams using JSXGraph.

]]>

JSXGraph extension for Numbas

This extension provides the JSXGraph library and functions to create diagrams inside a Numbas question.

Examples

The JSXGraph demo exam contains a collection of questions demonstrating different techniques to do with JSXGraph.

Creating a diagram

The preferred method to create a diagram is one of the jsxgraph or jessiecode functions. These produce a value with the type jsxgraphboard, which can be inserted into content areas by substitution with curly braces.

You should create the board in a question variable, so that its state can be saved and restored in case the student leaves and resumes their attempt.

Linking a diagram to marking and part inputs

The jxg_ functions described below can be used to access properties of a JSXGraph diagram inside a part's marking algorithm.

To link a part's input field to a JSXGraph diagram, you must describe how the link will work in each direction: from the input to the diagram, and vice versa. This is achieved by defining two notes in the part's marking algorithm, jxg_input and jxg_output.

jxg_input

The jxg_input note describes how to take input from the student and modify the JSXGraph diagram. It is a list of operations to perform. Since this is a marking note, all the other notes and variables in the algorithm are available.

The available operations are as follows:

jxg_set_position(object,position)

Set the position of object to the given position, which should be a 2D vector.

jxg_show(object,visible)

If visible = true, then show object, otherwise hide it.

jxg_set(object,property,arguments)

Call the JSXGraph set<property> on the given object, with the given arguments.

For example, jxg_set(c, "radius", 5) calls the JSXGraph method c.setRadius(5).

jxg_set_attribute(object,attributes)

attributes should be a dictionary mapping attribute names to values.

This calls the JSXGraph method setAttribute on the given object.

jxg_output

The jxg_output note describes how to take the state of the diagram to fill in the part's input field.

The note should return a value of the same type as the marking algorithm's studentAnswer variable. For example, for a "number entry" part this note should produce a string, representing what the student should write.

JME functions

jsxgraph(width, height, [boundingBox], objects, [options])

Create a JSXGraph board.

  • width: number - the displayed width in pixels of the board.
  • height: number - the displayed height in pixels of the board.
  • boundingBox: [number, number, number, number] - an optional list of four numbers defining the bounding box of the diagram, in the format [x1,y1,x2,y2]. The first point is mappted to the top-left of the board, and the second point to the bottom-right.
  • objects: list or dict - a list of object definitions, or a dictionary mapping object names to definitions.
  • options: dict - a dictionary of options for the board. See the documentation for JSXGraph.initBoard

An object definition is a list in the format [type, parents, attribute].

  • type: string - the type of object to create. Available types are listed in the 'Elements' section of the JSXGraph' documentation.
  • parents: list - a list of 'parent' values for the object. The format of this list depends on the type of the object being created. Any values of data type expression are replaced with functions which take a single parameter.
  • attributes: dict - an optional dictionary of attributes for the object. The available attributes dpeend on the type of the object.
  • events: dict - an optional dictionary of events produced by the object to react to. Each event name should correspond to a string of JessieCode.

JSXGraph will often interpret string values in the parents list as JavaScript expressions. You can refer to other objects by name. Alternately, you can provide JME expression values to evaluate expressions in terms of JME variables and functions. JSXGraph objects are not available in these expressions, and they're quite a bit slower than JavaScript.

Example

This creates a board with a line and a glider point on that line:

jsxgraph( 500,500, [ "l": ['line', [[0,1], [1,2]]], "p": ['glider', ['l']] ] )

This creates a board with a polar plot of the function r(phi) = sin(5phi) centred at the origin:

jsxgraph( 500,500, [ ['curve', [expression('sin(5phi)'),[0,0],0,2pi], ["curveType": "polar"]] ] )

jessiecode(width, height, [boundingBox], script, [options])

Create a JSXGraph board defined by a JessieCode script.

JessieCode is a languaged designed for efficiently creating diagrams in JSXGraph. There is some documentation about JessieCode syntax. The available object types and their construction options are the same as in the JavaScript API.

  • width: number - the displayed width in pixels of the board.
  • height: number - the displayed height in pixels of the board.
  • boundingBox: [number, number, number, number] - an optional list of four numbers defining the bounding box of the diagram, in the format [x1,y1,x2,y2]. The first point is mappted to the top-left of the board, and the second point to the bottom-right.
  • script: string - a JessieCode script defining the objects in the board.
  • options: dict - a dictionary of options for the board. See the documentation for JSXGraph.initBoard

Example

This creates a board with two points and a dashed line between them, and no background grid or axes:

``` jessiecode( 500,500, """ A = point(0,1); B = point(4,0);

    line(A,B) << dash: 4 >>;
""",
[
    "axis": false
]

) ```

jxg_add_objects(board, objects)

Add a list of objects to the given board.

The format for objects is the same as in the jsxgraph() function. Use this to add extra objects to a board - if you want to produce several similar boards, you might define a function which produces a generic board and then use this to add extra objects.

jxg_run_jessiecode(board, code)

Run a JessieCode script, given as a string, on the given board. You could use this to add objects, or modify some aspect of the board.

board[name]

Boards created by the jsxgraph and jessiecode functions work like dictionaries: the keys are the IDs of objects in the board.

JSXGraph assigns automatic IDs to objects, but these aren't predictable, so if you want to access an object later you have to explicitly set its id attribute.

For example, board["A"] gets the object with the ID "A".

To access properties of an object in a board, use one of the jxg_ functions.

The following is a brief description of what the jxg_ functions do. Refer to the JSXGraph documentation for more information.

jxg_angle(object)

Defined only on lines.

Returns the angle between the line and the x-axis.

jxg_area(object)

Defined only on circles and polygons.

Returns the area of the object.

jxg_attribute(object,key)

Get the value of an arbitrary attribute of an object.

Example: jxg_attribute(board["A"],"size")

jxg_bounding_box(object)

Defined only on polygons.

Returns the coordinates of the smallest box containing the polygon, as a list of four numbers [minX,minY,maxX,maxY].

jxg_bounds(object)

Returns the coordinates of the smallest box containing the polygon, as a list of four numbers [minX,minY,maxX,maxY].

jxg_distance(a,b)

Defined only on points, text and images.

Returns the distance between two points.

jxg_has_point(object,x,y) or jxg_has_point(object,position)

Returns true if the point with the given coordinates is contained in object.

You can either give the coordinates as two separate numbers, or as a 2D vector.

jxg_has_point_sector(object,x,y)

Defined only on arcs and sectors.

Returns true if the point with coordinates (x,y) is contained in the sector defined by object.

jxg_length(object)

Defined only on lines.

Returns the length of the line.

jxg_max_x(object)

Defined only on circles, curves, lines and turtle graphics.

Treating the object as a parametric curve, returns the maximum value of the parameter.

jxg_min_x(object)

Defined only on circles, curves, lines and turtle graphics.

Treating the object as a parametric curve, returns the maximum value of the parameter.

jxg_name(object)

Returns the name of the object.

jxg_parents(object)

Returns a list of the IDs of the object's parents.

jxg_perimeter(object)

Defined only on polygons.

Returns the length of the object's perimeter.

jxg_position(object)

Returns the object's position as a vector.

jxg_position_at(object,t)

Defined only on circles, curves, lines and turtle graphics.

Returns the coordinates of the point at parameter t on the object, as a vector.

jxg_radius(object)

Defined only on arcs, sectors and circles.

Returns the radius of the object.

jxg_rise(object)

Defined only on lines.

Returns the y-coordinate at which the line crosses the y-axis.

jxg_size(object)

Defined only on text objects.

Returns the size of the text.

jxg_slope(object)

Defined only on lines.

Returns the gradient of the line, or infinity if it is parallel to the y-axis.

jxg_type(object)

Returns the type of the object as a string.

jxg_value(object)

The returned value depends on the type of the object:

  • angle - the angle, as a number in radians.
  • arc - the length of the arc, as a number.
  • input - the content of the input element, as a string.
  • slider - the value the slider is currently set to, as a number.
  • checkbox - whether the checkbox is ticked, as a boolean.
  • tapemeasure - the length of the tape measure.
  • integral - the value of the integral.
  • riemannsum - the sum of the rectangles.

jxg_width(object)

Defined only on images.

Returns the width of the image, as a number.

JavaScript functions

All JavaScript functions are properties of the object Numbas.extensions.jsxgraph.

makeBoardPromise(width, height, options)

Make a JSXGraph board with the given dimensions and options, and attach it to a <div> element. The board is only initialised once the container element has been attached to the page.

An object of the format {element, promise} is returned. The element is a container <div> element that the board will be created under. The promise resolves to the JSXGraph Board object once the container has been attached to the page and the board initialised.

The options object is passed to JSXGraph.initBoard, with some defaults applied. The default options are:

{ boundingBox:[-5,5,5,-5], showCopyright:false, showNavigation:false, axis:true }

Example

This creates a board with the default options and a single point at the coordinates (1,2).

var result = Numbas.extensions.jsxgraph.makeBoardPromise(500,500); result.promise.then(function(board) { board.create('point',[1,2]); }); return result.element;

makeBoard(width, height, options)

Make a JSXGraph board with the given dimensions and options, and attach it to a <div> element. The div element is returned. The JSXGraph board object is available as div.board.

The options object is passed to JSXGraph.initBoard, with some defaults applied. The default options are the same as for makeBoardPromise.

Note: This function initialises the board immediately, and is kept for backwards compatibility. It's better to wait until the container element is attached to the page, using makeBoardPromise.

Example

This creates a board with the default options and a single point at the coordinates (1,2).

var div = Numbas.extensions.jsxgraph.makeBoard(500,500); div.board.create('point',[1,2]); return div;

]]>
Glass Sudoku https://somethingorotherwhatever.com/items/glass-sudoku 2019-02-11T08:26:37.279000Z Following the paper "the paramagnetic and glass transitions in sudoku"

]]>

Following the paper "the paramagnetic and glass transitions in sudoku"

]]>
Zeckendorf cup arithmetic https://somethingorotherwhatever.com/items/zeckendorf-cup-arithmetic 2018-11-19T09:39:51Z My 5-minute talk at the big MathsJam conference this weekend was about some stacking cups that my daughter is too young to appreciate. Here’s the really quick version, in just over a minute: …

]]>

My 5-minute talk at the big MathsJam conference this weekend was about some stacking cups that my daughter is too young to appreciate. Here’s the really quick version, in just over a minute: …

]]>
MathsJam countdown https://somethingorotherwhatever.com/items/mathsjam-countdown 2018-11-18T09:18:53.638000Z A five-minute timer for MathsJam Gathering talks.

]]>

A five-minute timer for MathsJam Gathering talks.

]]>
Distance to postcodes https://somethingorotherwhatever.com/items/distance-to-postcodes 2018-11-14T10:14:02Z Calculates the straight-line distances from a source postcode to a list of other postcodes. Made in response to someone at a university asking how many of their students they could expect to travel in for a day event.

]]>

Find the distance between a 'home' postcode and a list of other postcodes.

Uses data from https://www.getthedata.com/open-postcode-geo

]]>
MathsJam retweeter https://somethingorotherwhatever.com/items/mathsjam-retweeter 2018-11-01T10:04:43Z MathsJam Retweeter bot code

]]>
MathsJam Retweeter

This repository contains Python code that makes the @MathsJam Twitter account automatically retweet local MathsJams on the day of and the day before events.

Running this code

Before running this code, you will need to:

  1. Make a copy of config.py.template called config.py and fill in the Twitter API keys for the MathsJam account.
  2. Install the required Python libraries by running bash pip install -r requirements.txt

Once you've done this you can run the code using: bash python tweet.py

If you want to test the code without actually sending and tweets, you can do this using: bash python tweet.py test

]]>
Truchet polygons https://somethingorotherwhatever.com/items/truchet-polygons 2018-10-26T15:14:46Z Each tile is a regular polygon with an even number of sides. The vertices are painted in alternating colours. The tiles are lined up so that the colours on every edge match.

]]>

Truchet polygons

Truchet tiles are square tiles with quarter-circles on opposite vertices. When you put several tiles together, the circles line up. You can extend the idea to any even-sided regular polygon.

There are, as far as I know, only four tilings of the plane with even-sided regular polygons.

This was inspired by Colin Beveridge's article in Chalkdust magazine, Too Good to be Truchet. I haven't actually read the article yet, only the title...

]]>
Spontaneous Venning https://somethingorotherwhatever.com/items/spontaneous-venning 2018-10-17T09:16:13.457000Z An attempt to simulate people spontaneously forming a Venn diagram

]]>

An attempt to simulate people spontaneously forming a Venn diagram

]]>
Categorised Esoterica https://somethingorotherwhatever.com/items/categorised-esoterica 2018-10-12T14:41:17.434000Z A tool I made to help quickly categorise all the things in my Interesting Esoterica collection.

]]>
A tool I made to help quickly categorise all the things in my Interesting Esoterica collection.

]]>
This matrix joke is only barely worth your time https://somethingorotherwhatever.com/items/this-matrix-joke-is-only-barely-worth-your-time 2018-10-01T08:33:38Z If you see me doing a maths thing, I’m probably wearing one of my maths t-shirts. I’ve got quite a few, but the one that reliably produces the much-sought-after look of total indifferen…

]]>

If you see me doing a maths thing, I’m probably wearing one of my maths t-shirts. I’ve got quite a few, but the one that reliably produces the much-sought-after look of total indifferen…

]]>
Unit fractions are all you need https://somethingorotherwhatever.com/items/unit-fractions-are-all-you-need 2018-09-20T08:18:02.491000Z Every rational number can be written as the sum of unit fractions

]]>

Every rational number can be written as the sum of unit fractions

]]>
Reciprocals https://somethingorotherwhatever.com/items/reciprocals 2018-09-15T12:39:04.856000Z A never-ending list of reciprocals

]]>

A never-ending list of reciprocals

]]>
Factorisation list https://somethingorotherwhatever.com/items/factorisation-list 2018-09-15T06:44:32.434000Z A never-ending list of factorisations of the natural numbers.

]]>

A never-ending list of factorisations of the natural numbers.

]]>
A big countdown https://somethingorotherwhatever.com/items/a-big-countdown 2018-08-29T06:09:59.699000Z Shows a big timer counting down from 10 minutes.

]]>

Shows a big timer counting down from 10 minutes.

]]>
A big clock https://somethingorotherwhatever.com/items/a-big-clock 2018-08-28T08:18:58.970000Z A page showing a big HH:MM:SS time display and nothing else

]]>

A page showing a big HH:MM:SS time display and nothing else

]]>
Chemistry extension for Numbas https://somethingorotherwhatever.com/items/chemistry-extension-for-numbas 2018-08-16T09:24:05Z Data and functions to help with calculations in chemistry

]]>
Chemistry extension for Numbas

Provides data and functions to make calculations in chemistry easier.

Functions and data are being added as needed.

This has been written by a non-chemist, in collaboration with some non-coding chemists.

JME functions

atom(symbol, [mass number]) or atom(atomic number, [mass number])

Construct an atom of the element with the given symbol or atomic number. Give mass number to specify a particular isotope.

Example:

  • atom("Na")
  • atom("Na",19)
  • atom(11)

name(atom)

The IUPAC name of the atom, with the mass number appended if it's a particular isotope.

Examples:

  • name(atom("Na"))"sodium"
  • name(atom("Na",19))"sodium-19"

symbol(atom)

The symbol of the atom.

Example:

  • symbol(atom(11))"Na"

string(atom)

A plaintext string representation of the atom. For isotopes, the mass number is shown in superscript.

Example:

  • string(atom("Na",19))"¹⁹Na"

atom[property]

Get the given property of the atom, from the periodic_table_data or isotope_data dictionaries.

Examples:

  • atom("Na")["electronegativity"]0.93
  • atom("C",13)["Isotopic Composition"]"0.0107(8)"

atomic_number(atom)

The atomic number of the atom.

Example:

  • atomic_number(atom("C"))6

mass_number(atom)

The mass number of the given atom. If no isotope is specified, the most abundant isotope is used.

Example:

  • mass_number(atom("Na"))23

neutrons(atom)

The number of neutrons in the atom Equivalent to mass_number(atom) - atomic_number(atom).

Example:

  • neutrons(atom("Na"))12

relative_mass(atom)

The relative atomic mass of the atom. If no isotope is specified, the standard atomic weight is used.

Example:

  • relative_mass(atom("C"))12.0107

isotopes(atom)

List the mass number of known isotopes of the element.

Example:

  • isotopes(atom("H"))[ 1, 2, 3, 4, 5, 6, 7 ]

abundance(atom)

Abundance of the given isotope. If no isotope specified, returns 1.

Example:

  • abundance(atom("C",13))0.0107

formula(string)

Construct a compound from the given formula.

Examples:

  • formula("H2O")
  • formula("C(CH3)4")
  • formula("2(N2)")

string(formula)

A plain text display representation of the given formula.

Example:

  • string(formula("H2O"))"H₂O"

plain_string(formula)

A plain text display representation of the given formula.

Example:

  • string(formula("H2O"))"H₂O"

atom_counts(formula)

Returns a dictionary containing the number of atoms of each element present in the compound.

Example:

  • atom_counts(formula("C(CH3)4"))[ "C": 5, "H": 12 ]

mass(formula)

The relative atomic mass of the compound specified by the formula.

Example:

  • mass(formula("C(CH3)4"))72.14878

thermodynamic_data(name,state)

Returns data from the thermodynamic_data dictionary for the chemical with the given name or symbol, in the given state. Common values of state are "g" (gas), "l" (liquid), "c" (crystalline), or "amorphous". Some other states are also listed; see thermodynamic_data.

Data

Some data sets are available as variables.

periodic_table

Based on https://github.com/andrejewski/periodic-table, which is itself based on https://web.archive.org/web/20161203095654/http://php.scripts.psu.edu/djh300/cmpsc221/p3s11-pt-data.htm.

A list of dictionaries providing data on elements in the periodic table. periodic_table[n] give data for the element with atomic number n.

Each dictionary has the following keys:

  • atomicNumber
  • symbol
  • name
  • atomicMass - Standard atomic weight, with precision (e.g. "1.00794(4)")
  • cpkHexColor - Hex representation of the element's CPK colour
  • electronicConfiguration - Electron configuration
  • electronegativity - Pauling electronegativity
  • atomicRadius - Atomic radius in pm
  • ionRadius - Ion radius in pm
  • vanDerWaalsRadius - van der Waals radius in pm
  • ionizationEnergy - IE-1 in kJ/mol
  • electronAffinity - EA in kJ/mol
  • oxidationStates - Oxidation states
  • standardState - Standard state, one of "gas", "solid", "liquid" or ""
  • bondingType - Bonding type, one of "diatomic", "atomic", "metallic", "covalent network" or ""
  • meltingPoint - Melting point in K
  • boilingPoint - Boiling point in K
  • density - Density in g/mL
  • groupBlock - Group, one of "nonmetal", "noble gas", "alkali metal", "alkaline earth metal", "metalloid", "halogen", "metal", "transition metal", "lanthanoid", "actinoid", "post-transition metal"
  • yearDiscovered

isotope_data

Based on https://www.nist.gov/pml/atomic-weights-and-isotopic-compositions-relative-atomic-masses

Data on properties of isotopes. A dictionary of the form {atomic_number: {mass_number: data}}.

Each dictionary has the following keys:

  • "Isotopic Composition" - Abundance of this isotope as a proportion between 0 and 1, with precision (e.g. "0.524(1)")
  • "Notes" - See the NIST column description
  • "Standard Atomic Weight" - Standard atomic weight of the element, with precision
  • "Atomic Number"
  • "Atomic Symbol"
  • "Relative Atomic Mass" - Relative atomic mass of this isotope
  • "Mass Number

thermodynamic_data

Based on Newcastle University's thermodynamic data card.

Data on thermodynamic properties of some chemicals in different states. Most easily accessed with thermodynamic_data(name,state).

A list of dictionaries with the following keys:

  • "name"
  • "formula"
  • "state"
  • "Hfg" - Enthalpy of formation, in kJ/mol
  • "Gfg" - Gibbs free energy, in kJ/mol
  • "Smg" - Entropy, in J/mol/K
  • "Cpm" - Specific heat capacity, in J/mol/K
]]>
The People Shuffler https://somethingorotherwhatever.com/items/the-people-shuffler 2018-08-10T15:19:58.507000Z A tool to decide who goes first: everyone loads this on their phone, and presses the screen at the same time. The phones will all ping at different times. A knock-off of an app I saw someone use. Contains a QR code so everyone else can load it easily.

]]>

A tool to decide who goes first: everyone loads this on their phone, and presses the screen at the same time. The phones will all ping at different times. A knock-off of an app I saw someone use. Contains a QR code so everyone else can load it easily.

]]>
Quantities extension for Numbas https://somethingorotherwhatever.com/items/quantities-extension-for-numbas 2018-07-25T08:58:33Z A Numbas extension providing functions to handle amounts with units

]]>
Quantities extension for Numbas

This extension wraps the js-quantities library to provide a "quantity with units" data type to Numbas.

It provides a quantity data type, which represents a scalar amount and a list of units.

A note about precision: Amounts are represented with JavaScript floating-point numbers, which are only precise to around 30 decimal places. It's our intention to add support for more precise number representations to Numbas; when that happens, this extension could be updated to use that.

JME functions

quantity([number], units) or qty([number], units)

Create a quantity with the given units. If the number is not given, the returned quantity represents 1 of the given units. Use * and / to combine units, and ^ for powers of units. An empty units string will produce a unitless quantity.

Examples:

  • quantity("kg")
  • qty("kg")
  • quantity(1.2, "kg")
  • quantity("kg*m/s^2")
  • quantity("1/s")
  • quantity("kg*m^-2")

units_of_kind(kind)

Returns a list of recognised units of the given kind.

Example:

  • units_of_kind("length")[ "angstrom", "AU", "datamile", "fathom", "foot", "furlong", "inch", "league", "light-minute", "light-second", "light-year", "meter", "mil", "mile", "naut-mile", "parsec", "pica", "point", "redshift", "rod", "yard", "m" ]

aliases(unit)

Returns a list of accepted names for the given unit.

Example:

  • aliases("meter")[ "m", "meter", "meters", "metre", "metres" ]

compatible(q1, q2)

Are the two given quantities compatible? That is, are they of the same kindm, so one can be converted to the other?

Examples:

  • compatible(qty("m"), qty("ft"))true
  • compatible(qty("m"), qty("kg"))false

kind(quantity)

What kind of unit is quantity measured in? Returns a string code corresponding to the kind. For combinations of units that don't correspond to a built-in kind, an empty string is returned.

Examples:

  • kind(qty("m"))"length"
  • kind(qty("N*s"))"momentum"
  • kind(qty("W/s"))""

unitless(quantity)

Does the given quantity have no associated units? Note that a dimensionless quantity is not necessarily unitless - for example, a quantity measured in meters per foot has no dimension but is not unitless.

  • unitless(qty(1,""))true
  • unitless(qty(1,"m"))false
  • unitless(qty(1,"m/ft"))false

isbase(quantity)

Is the given quantity in base units, as defined in the International System of Units (SI)?

Examples:

  • isbase(qty("kg"))true
  • isbase(qty("lb"))false

tobase(quantity)

Convert the given quantity to base SI units.

Example:

  • tobase(qty(1, "inch"))quantity(0.0254, "m")

q_from in units or q_from in q_to

Convert quantity q_from to the units specified by the given string, or the same units as q_to. If the desired units are not compatible with q_from, an error is thrown.

Examples:

  • qty(1.5, "m") in "cm"quantity(150, "cm")
  • qty(100,"g") in qty("kg")quantity(0.1, "kg")

as_si(quantity)

Convert quantity to SI units.

Example:

  • as_si(quantity(1, "lb*ft"))quantity(0.1382549544, "m*kg")

inverse(quantity)

Return the reciprocal of the given quantity.

Example:

  • inverse(qty(2, "m/s"))quantity(0.5, "s/m")

same(a, b)

Are a and b both exactly the same quantity, measured in the same units?

Examples:

  • same(qty(1, "m"), qty(100, "cm"))false
  • same(qty(1, "m"), qty(2, "m"))false
  • same(qty(1, "m"), qty(1, "m"))true

a < b, a <= b, a > b, a >= b

Compare quantities a and b. If their units are not compatible, an error is thrown.

Examples:

  • qty(1, "cm") < qty(1, "m")true
  • qty(4, "feet") > qty(1, "m")true
  • qty(1, "cm") > qty(1, "cm")false
  • qty(1, "cm") >= qty(1, "cm")true

a = b

Quantities a and b are equal if their units are compatible and they represent exactly the same amount.

Examples:

  • qty(2.54, "cm") = qty(1, "inch")true
  • qty(1, "cm") = qty(1, "second")false

a + b, a - b, a * b, a / b

Arithmetic on units is supported. When adding or subtracting units, the result is given in the same units as the left-hand argument, and if the two quantities being combined are in incompatible units an error is thrown. When multiplying or dividing, units are not automatically converted to their common names. For example, The division of a quantity in Newtons by a quantity in m^2 returns a quantity in N/m^2, not in Pa.

Examples:

  • qty(1, "cm") + qty(1, "m")quantity(101, "cm")
  • qty(100, "cm") - qty(1, "m")quantity(0, "cm")
  • qty(100, "cm") * qty(1, "s")quantity(100, "cm*s")
  • qty(100, "N") / qty(4, "m^2")quantity(25, "N/m^2")

-q

The negative of the given quantity.

Example:

  • -qty(1,"N")quantity(-1, "N")

n * quantity or quantity * n

Multiply a quantity by a scalar.

Example:

  • 5 * quantity(6, "g")quantity(30, "g")

round(quantity, precision)

Round quantity to the nearest multiple of precision, given either as a string in the form "amount units", or another quantity. If precision is not given, the quantity is rounded to the nearest whole unit.

Examples:

  • round(qty(123, "cm"), "1 m")quantity(100, "cm")
  • round(qty(0.1697, "m"), qty(5, "cm"))quantity(0.15, "m")
  • round(qty(6.32, "kg"))quantity(6, "kg")

precround(quantity,dp)

Round quantity to dp decimal places.

Example:

  • precround(qty(123.456,"cm"), 1)quantity(123.5, "cm")

siground(quantity,sf)

Round quantity to sf significant figures.

Example:

  • siground(qty(123.456,"cm"), 1)quantity(100, "cm")

abs(quantity)

The absolute value of the quantity.

Example:

  • abs(qty(-5, "N"))quantity(5, "N")

scalar(quantity)

The scalar amount of the quantity, as a number - in other words, strip off the units information.

Example:

  • scalar(qty(53, "s"))53

sign(quantity)

Returns 1 if the quantity is positive, -1 if it's negative, and 0 otherwise.

Examples:

  • sign(qty(20,"kg"))1
  • sign(qty(-10,"kg"))-1
  • sign(qty(0,"kg"))0

string(quantity, [notation style])

A string representing the given quantity, in the given notational style (plain English is the default) The units are presented using "nice" characters: a dot for multiplication, and exponents are displayed in superscript.

Examples:

  • string(qty(23, "kg*s^-1"))"23 kg/s"
  • string(qty(1000.235, "kg*m^2"), "si-fr")"1 000,235 kg⋅m²"

plain_string(quantity, [notation style])

A string representing the given quantity, in the given notational style (plain English is the default). The units are given in a form that is easy to type: * is used for multiplication, and ^ marks an exponent.

Examples:

  • plain_string(qty(23, "kg/s"))"23 kg/s"
  • plain_string(qty(1000.235, "kg*m^2"), "si-fr")"1 000,235 kg*m^2"

units_numerator(quantity) and units_denominator(quantity)

The units of a quantity can be written as a fraction whose numerator and denominator both consist of a list of units. When a squared or cubed unit is used, the base unit is repeated. These functions return the lists of units in the numerator and denominator, respectively, for a given quantity. Any order-of-magnitude prefixes are included as separate items in the list

Examples:

  • units_numerator(qty(1, "m"))[ "meter" ]
  • units_denominator(qty(1, "m"))[ "1" ]
  • units_numerator(qty(1, "kg*cm^2/s^2"))[ "kilogram", "centi", "meter", "centi", "meter" ]
  • units_denominator(qty(1, "m^2/s^2"))[ "second", "second" ]

units(quantity)

Return a quantity representing one unit of the same kind as the given quantity.

Example:

  • units(qty(23, "m^2/s"))quantity(1, "m^2/s")

units_string(quantity)

Return a string describing the units of the given quantity, suitable for display. Powers are displayed in superscript, and is used for multiplication. The units are presented using "nice" characters: a dot for multiplication, and exponents are displayed in superscript.

Example:

  • units_string(qty("kg*cm^2/s^2"))"kg⋅cm²/s²"

plain_units_string(quantity)

Return a string describing the units of the given quantity, suitable for display. Powers are displayed in superscript, and is used for multiplication. The units are given in a form that is easy to type: * is used for multiplication, and ^ marks an exponent.

Example:

  • plain_units_string(qty("kg*cm^2/s^2"))"kg*cm^2/s^2"

quantity_kinds

A constant list of all the recognised kinds of units.

JavaScript functions

See the documentation for js-quantities for detail on its JavaScript API.

The Qty object is available globally when this extension is loaded.

In addition, the following functions are defined under the Numbas.extensions.quantities namespace:

precround(q,dp)

Round the quantity q to dp decimal places. See Numbas.math.precround

siground(q,sf)

Round the quantity q to sf significant figures. See Numbas.math.siground

Recognised units

The following unit names are recognised. Units of the same kind can be converted between each other. The prefixes can be written to the left of any other unit, to change the order of magnitude.

acceleration

  • gee

activity

  • Katal, kat, katal
  • U, enzUnit, unit

angle

  • rad, radian, radians
  • deg, degree, degrees
  • gon, grad, gradian, grads
  • rotation

angular velocity

  • rpm

area

  • hectare
  • acre, acres
  • sqft

capacitance

  • F, Farad, farad

charge

  • C, Coulomb, coulomb
  • Ah

concentration

  • M, molar
  • wt%, wtpercent

conductance

  • S, Siemens, siemens

counting

  • cell, cells
  • each
  • count
  • base-pair, bp
  • nt, nucleotide
  • molecule, molecules

currency

  • USD, dollar
  • cents

current

  • A, Ampere, amp, ampere, amps

energy

  • J, Joule, joule, joules
  • erg, ergs
  • BTU, BTUs, btu
  • cal, calorie, calories
  • Cal, Calorie, Calories
  • Therm, th, therm, therm-US, therms
  • Wh

force

  • N, Newton, newton
  • dyn, dyne
  • lbf, pound-force

frequency

  • Hertz, Hz, hertz

illuminance

  • lux

inductance

  • H, Henry, henry

information

  • B, byte, bytes
  • b, bit, bits

information rate

  • Bps
  • bps

length

  • m, meter, meters, metre, metres
  • ", in, inch, inches
  • ', feet, foot, ft
  • yard, yards, yd
  • mi, mile, miles
  • naut-mile, nmi
  • league, leagues
  • furlong, furlongs
  • rd, rod, rods
  • mil, mils
  • ang, angstrom, angstroms
  • fathom, fathoms
  • pica, picas
  • point, points, pt
  • red-shift, redshift, z
  • AU, astronomical-unit
  • light-second, ls
  • light-minute, lmin
  • light-year, ly
  • parsec, parsecs, pc
  • DM, datamile

logarithmic

  • dB, decibel, decibels

luminosity

  • candela, cd

luminous power

  • lm, lumen

magnetism

  • Wb, weber, webers
  • T, tesla, teslas
  • G, gauss
  • Mx, maxwell, maxwells
  • Oe, oersted, oersteds

mass

  • kg, kilogram, kilograms
  • AMU, amu, u
  • Da, Dalton, Daltons, dalton, daltons
  • slug, slugs
  • short-ton, tn, ton
  • metric-ton, tonne
  • carat, carats, ct
  • , lb, lbs, pound, pounds

  • ounce, ounces, oz
  • g, gram, gramme, grammes, grams
  • gr, grain, grains
  • dr, dram, drams
  • st, stone, stones

potential

  • V, Volt, volt, volts

power

  • W, watt, watts
  • VA, volt-ampere
  • VAR, VAr, Var, var, volt-ampere-reactive
  • horsepower, hp

prefix

  • googol
  • Ki, Kibi, kibi
  • Mebi, Mi, mebi
  • Gi, Gibi, gibi
  • Tebi, Ti, tebi
  • Pebi, Pi, pebi
  • Ei, Exi, exi
  • Zebi, Zi, zebi
  • Yebi, Yi, yebi
  • Y, Yotta, yotta
  • Z, Zetta, zetta
  • E, Exa, exa
  • P, Peta, peta
  • T, Tera, tera
  • G, Giga, giga
  • M, Mega, mega
  • k, kilo
  • Hecto, h, hecto
  • Deca, da, deca, deka
  • Deci, d, deci
  • Centi, c, centi
  • Milli, m, milli
  • Micro, mc, micro, u, µ, μ
  • Nano, n, nano
  • Pico, p, pico
  • Femto, f, femto
  • Atto, a, atto
  • Zepto, z, zepto
  • Yocto, y, yocto

prefix only

  • doz, dozen, dz
  • %, percent
  • ppm
  • ppt
  • gr, gross

pressure

  • Pa, Pascal, pascal
  • bar, bars
  • mmHg
  • inHg
  • torr
  • ATM, atm, atmosphere, atmospheres
  • psi
  • cmH2O, cmh2o
  • inH2O, inh2o

radiation

  • Gy, gray, grays
  • R, roentgen
  • Sv, sievert, sieverts
  • Bq, becquerel, becquerels
  • Ci, curie, curies

rate

  • cpm
  • dpm
  • bpm

resistance

  • Ohm, ohm, Ω, Ω

resolution

  • dot, dots
  • pixel, px
  • ppi

solid angle

  • sr, steradian, steradians

speed

  • kph
  • mph
  • kn, knot, knots, kt, kts
  • fps

substance

  • mol, mole

temperature

  • degK, kelvin
  • celsius, celsius, centigrade, degC
  • degF, fahrenheit
  • degR, rankine
  • temp-K, tempK
  • temp-C, tempC
  • temp-F, tempF
  • temp-R, tempR

time

  • s, sec, second, seconds, secs
  • min, mins, minute, minutes
  • h, hour, hours, hr, hrs
  • d, day, days
  • week, weeks, wk
  • fortnight, fortnights
  • annum, y, year, years, yr
  • decade, decades
  • centuries, century

typography

  • dpi

viscosity

  • P, poise
  • St, stokes

volume

  • L, l, liter, liters, litre, litres
  • gal, gallon, gallons
  • qt, quart, quarts
  • pint, pints, pt
  • cu, cup, cups
  • floz, fluid-ounce, fluid-ounces
  • tablespoon, tablespoons, tb, tbs, tbsp
  • teaspoon, teaspoons, tsp
  • bsh, bu, bushel, bushels
]]>
Random statistically plausible people https://somethingorotherwhatever.com/items/random-statistically-plausible-people 2018-07-24T12:23:13.909000Z Randomly generate the names of statistically plausible people

]]>

Randomly generate the names of statistically plausible people

]]>
Divisibility diagrams https://somethingorotherwhatever.com/items/divisibility-diagrams 2018-07-09T08:11:17.858000Z Show a diagram to compute divisibility by any number

]]>

Show a diagram to compute divisibility by any number

]]>
The Big Internet Math-Off https://somethingorotherwhatever.com/items/the-big-internet-math-off 2018-06-23T23:00:00Z A competition to find The World's Most Interesting Mathematician. It's really a way of tricking people into telling me fun maths.

]]>

A competition to find The World's Most Interesting Mathematician. It's really a way of tricking people into telling me fun maths.

]]>
Get the Average Right https://somethingorotherwhatever.com/items/get-the-average-right 2018-06-17T07:07:41.376000Z I think the gist of the game would be that in each round, everyone guesses a number, and at the end the closest guess to the average of everyone's guesses wins. It didn't really work.

]]>

I think the gist of the game would be that in each round, everyone guesses a number, and at the end the closest guess to the average of everyone's guesses wins. It didn't really work.

]]>
Spinny squares https://somethingorotherwhatever.com/items/spinny-squares 2018-06-15T13:23:50.913000Z Spinny squares

]]>

Spinny squares

]]>
I can name your polynomial https://somethingorotherwhatever.com/items/i-can-name-your-polynomial 2018-05-23T10:02:23Z I can name your polynomial

]]>

Based on a trick I saw David Bedford perform.

]]>
Polar fractions https://somethingorotherwhatever.com/items/polar-fractions 2018-05-15T08:15:23Z Show every fraction in the range [0,1] on a polar plot, using the Calkin-Wilf sequence

]]>

Show every fraction in the range [0,1] on a polar plot, using the Calkin-Wilf sequence.

Inspired by @[email protected]'s toot.

]]>
The incredible palindromic hat-trick https://somethingorotherwhatever.com/items/the-incredible-palindromic-hat-trick 2018-04-29T15:21:04Z Demonstrating the incredible fact that every integer can be written as the sum of 3 palindromes.

]]>

Demonstrating the incredible fact that every integer can be written as the sum of 3 palindromes.

]]>
Stecklegram https://somethingorotherwhatever.com/items/stecklegram 2018-04-22T23:00:00Z A thing to help Katie Steckles decode the secret message in her birthday card.

]]>

A thing to help Katie Steckles decode the secret message in her birthday card.

]]>
The never-ending sum https://somethingorotherwhatever.com/items/the-never-ending-sum 2018-03-06T17:32:26Z A never ending series of sums, where the answer from the last question is part of the next question.

]]>

A never ending series of sums, where the answer from the last question is part of the next question.

]]>
time https://somethingorotherwhatever.com/items/time 2018-02-19T20:43:52Z I had an idea about a way of modelling intervals of time and doing arithmetic with them, prompted by the question of what 'one month from now' means. It didn't really work.

]]>
I had an idea about a way of modelling intervals of time and doing arithmetic with them, prompted by the question of what 'one month from now' means. It didn't really work.

]]>
Dudeney puzzle 403 https://somethingorotherwhatever.com/items/dudeney-puzzle-403 2018-01-25T11:19:33Z An interactive version of Puzzle 403 from Henry Ernest Dudeney's Amusements in Mathematics.

]]>

An interactive version of Puzzle 403 from Henry Ernest Dudeney's Amusements in Mathematics.

]]>
asciimath2tex https://somethingorotherwhatever.com/items/asciimath2tex 2017-12-13T10:58:53Z JavaScript library to convert AsciiMath to TeX

]]>
asciimath2tex

JavaScript library to convert AsciiMath to TeX.

I wrote this so I could use KaTeX to render AsciiMath.

Usage

The library is written as an ECMAScript module but is also distributed as CommonJS and UMD modules.

The file asciimath2tex.js is an ES6 module which can be used in browsers that support it.

In a browser

If you can use ES6 modules, use asciimath2tex.js as-is:

```js import AsciiMathParser from 'asciimath2tex';

const parser = new AsciiMathParser(); const tex = parser.parse("int_(i=1)^10 x^2/2 dx"); ```

parser.parse returns a string of TeX.

If you can't use ES6 modules, there is a UMD version. You can load it from unpkg.com, or create it yourself.

To load from unpkg

```html

```

To create the file locally

Clone this repository, and run:

npm install npm run-script build

Copy the file dist/asciimath2tex.umd.js into your project.

Node.js / CommonJS

Install the package using npm:

npm install asciimath2tex

You can then load the package in your script:

```js const AsciiMathParser = require('asciimath2tex');

const parser = new AsciiMathParser(); const tex = parser.parse("int_(i=1)^10 x^2/2 dx"); ```

Tests

There are some unit tests in test.html, copied from the asciimath repository.

All of the tests are rendered correctly by KaTeX, apart from \twoheadrightarrowtail, which it apparently doesn't support.

]]>
Circular lights out https://somethingorotherwhatever.com/items/circular-lights-out 2017-12-09T16:35:59Z A circular version of the Lights Out puzzle. The aim of the game is to turn all of the lights off. When there is an evenly-spaced sequence of bulbs all turned off or all turned on, you may switch them all on or off by clicking two consecutive lights in the sequence.

]]>

circular-lights-out

A one-dimensional "lights out" variant, played on a circle. You can toggle the state of a bulb, as long as you also toggle every d^th bulb after it, where d is a divisor of the total number of bulbs.

You start with one light turned on. Can you turn all the lights out?

]]>
Lights modular out https://somethingorotherwhatever.com/items/lights-modular-out 2017-11-29T08:44:26Z A move in the classic Lights Out puzzle could be viewed as addition mod 2. This lets you set up a version of the puzzle where it's addition modulo something else.

]]>

lights-modular-out

A lights-out game, with N states instead of just 2.

The URL of the page always represents the state of the game, so you can link to a particular state by copying the URL.

]]>
Exploding dots counter https://somethingorotherwhatever.com/items/exploding-dots-counter 2017-10-03T07:43:30Z An animated counter showing the Exploding Dots 1 → 10 machine.

]]>

Exploding Dots counter

Exploding Dots is James Tanton's thing.

It just keeps counting.

Building

I've used some ES2015 features, so to make it work in older browsers you need to use BabelJS.

Install babel with

npm install

and then run

babel thing.js -o thing.compiled.js

]]>
Random person extension for Numbas https://somethingorotherwhatever.com/items/random-person-extension-for-numbas 2017-07-13T14:12:54Z A Numbas extension providing a collection of functions to generate random people, for use in word problems.

]]>
Random person extension for Numbas

A Numbas extension providing a collection of functions to generate random people, for use in word problems.

Demo: https://numbas.mathcentre.ac.uk/question/23094/the-random-person-extension/

It doesn't really matter what people are called in word problems, but it can have a bad effect on students' perceptions of the world if the plumber's always called Gary and the nurse is always called Julie.

An easy fix is to flip a coin each time you need a name, and choose a male name if it's heads, and a female name if it's tails.

But names come with much more baggage than gender! Social class, age and cultural heritage are just a few of the things you can have a stab at guessing based on someone's name.

So, this extension makes it really easy to randomly pick a name for a representative citizen of England and Wales born between 1996 and 2015, using the ONS's dataset of baby name frequencies in England and Wales, 1996 to 2015.

Names which were given to more than 100 each of males and females are classed as gender-neutral. Additionally, when picking names without specifiying a gender, occasionally a name that would be returned as "male" or "female" is instead returned as "neutral", representing a person who identified as non-binary. The proportion of the time that this happens is controlled by the JavaScript variable Numbas.extensions.random_person.PROB_NONBINARY, which is 1/100 by default.

Providing your own name data

The extension contains some built-in JavaScript objects with the data for name frequencies, and pronouns associated with each gender. You can replace these objects with your own data.

There are some other datasets in Numbas.extensions.random_person.datasets.

To switch to another dataset, put something like this in your question's Javascript preamble:

var random_person = Numbas.extensions.random_person; random_person.data = random_person.datasets.fr;

The name frequencies are stored in an object at Numbas.extensions.random_person.data.

This object has the form:

{ "names": { gender: list of objects {"name": string, "count": integer} }, "totals": { gender: integer } }

(gender stands for a key representing each gender. In the built-in data set, these are "male", "female" and "neutral".)

There is also an object giving pronouns for each gender, stored at Numbas.extensions.random_person.pronouns.

This object has the form:

{ gender: pronoun_map }

The built-in pronoun_map is an object mapping each of the strings "they", "their", "theirs", "them", "themself" to the corresponding pronouns for that gender. Each of these keys is added to the object returned for a randomly-generated person, so if you are using a language other than English, you could provide a different set of keys.

Ways this can be improved

  • Apart from names, what else should be randomised? Jobs?
  • Gender's a complicated topic, so I'm very open to suggestions for improvements in the way it's handled.
  • A function which populates the scope with variables for the pronouns, and verb conjugation, so you don't have to set them up yourself in each question. Or maybe functions like they(person), equivalent to person['pronouns']['they'].

Copyright

The name frequency data is Crown Copyright, reproduced under the Open Government Licence.

The rest of this package is released under the terms of the Apache License 2.0. See the LICENSE file for more information.

The data structure

The code returns dictionaries representing people, of the form

{ "gender": string, //("male", "female", or "neutral" at the moment) "name": string, "pronouns": { "they": the subjective personal pronoun, e.g. 'he' or 'she', "their": the possessive determiner, e.g. 'his' or 'her', "theirs": the possessive pronoun, e.g. 'his' or 'hers', "them": the objective personal pronoun, e.g. 'him' or 'her', "themself": the reflexive pronoun, e.g. 'himself' or 'herself' } }

How to use this

Generate a random person, or people, using the JME functions described below.. Each time you need to use their name, or a pronoun referring to them, use the corresponding entry from their dictionary, as described above.

Here's an example:

``` {person['name']} puts {person['pronouns']['their']} things where {person['pronouns']['they']} like{if(person['gender']='neutral','','s')}.

When people show things to {person['pronouns']['them']}, {person['pronouns']['they']} want{if(person['gender']='neutral','','s')} them for {person['pronouns']['themself']}. ```

The singular "they" is used for gender-neutral people. Don't forget that verb conjugation is different for singular "they": for example, "Charlie likes to read while they walk" compared to "Charlie likes to read while he walks".

If you've only got one person, it can be more convenient to set variables for 'they', 'their', etc. and for verb conjugation, so you don't have to type person['pronouns']['their'] each time.

Here's that example again:

``` {name} put{s} {their} things where {they} like{s}.

When people show things to {them}, {they} want{s} them for {themself}. ```

If you need more than one person, use random_people to ensure that you don't have any repeated names, which could lead to confusion.

JME functions

random_person()

A person with random name and gender.

random_person_with_gender(gender)

A person with random name and the given gender.

random_people(n)

n unique people with random names and genders. If you need more than one person in your question, use this to make sure that no names are repeated.

random_people_with_gender(gender,n)

n unique people with random names and the given gender.

random_person_with_initial(letter)

A person with random name and gender, whose name starts with the given letter.

random_people_with_different_initials(n)

n unique people with random names, whose names each start with distinct letters.

]]>
The curious mathmo talks to David Roberts https://somethingorotherwhatever.com/items/the-curious-mathmo-talks-to-david-roberts 2017-06-23T17:15:01Z Way back at the end of last year I put out a call to mathematicians I know: hop on Skype and chat to me for a while about the work you’re doing at the moment. The first person to answer was D…

]]>

Way back at the end of last year I put out a call to mathematicians I know: hop on Skype and chat to me for a while about the work you’re doing at the moment. The first person to answer was D…

]]>
Some maths jokes https://somethingorotherwhatever.com/items/some-maths-jokes 2017-06-13T23:00:00Z A collection of maths jokes and explanations of why they're funny.

]]>

A collection of maths jokes and explanations of why they're funny.

]]>
Linear algebra extension for Numbas https://somethingorotherwhatever.com/items/linear-algebra-extension-for-numbas 2017-05-25T11:29:51Z A Numbas extension providing functions to work with linear algebra

]]>
Linear algebra extension for Numbas

This extension provides a few functions which make working with linear algebra easier.

The three kinds of permitted row operation are:

  • Swap two rows.
  • Multiply a row by a scalar.
  • Subtract k times one row from another.

This extension works with matrices over the rationals: before any operations are performed, the matrix's cells are converted to fractions.

JME functions

row_echelon_form(matrix)

Uses row operations to put the given matrix in row echelon form. A matrix is in row echelon form if the leading non-zero entry in each row is strictly to the right of the leading non-zero entries in all of the rows above.

row_echelon_form_display(matrix)

Returns a passage of HTML describing the steps involved in transforming the given matrix into row echelon form.

row_echelon_form_display_determinant(matrix)

Returns a passage of HTML describing the steps involved in transforming the given matrix into row echelon form, while describing how the determinant of the matrix changes at each step.

is_row_echelon_form(matrix)

Returns true if the matrix is in row echelon form.

describe_why_row_echelon_form(matrix)

Returns a string describing why the matrix is not in row echelon form, or "The matrix is in row echelon form." if it is.

reduced_row_echelon_form(matrix)

Uses row operations to put the given matrix in reduced row echelon form. A matrix in row echelon form is reduced if every leading non-zero entry is 1 and is the only non-zero entry in its column.

reduced_row_echelon_form_display(matrix)

Returns a passage of HTML describing the steps involved in transforming the given matrix into reduced row echelon form.

is_reduced_row_echelon_form(matrix)

Returns true if the matrix is in reduced row echelon form.

describe_why_reduced_row_echelon_form(matrix)

Returns a string describing why the matrix is not in reduced row echelon form, or "The matrix is in reduced row echelon form." if it is.

rank(matrix)

Computes the rank of the matrix, by returning the number of rows of the reduced row echelon form of the matrix, with all zero rows removed.

is_linearly_independent(matrix)

Returns true if the rows of the matrix are linearly independent.

adjoin(matrix,vector)

Add the given column vector to the right of the given matrix.

subset_with_dimension(vectors,n,d)

Return a subset of n of the given vectors, with dimension d.

This is not always possible - if the vectors have length k, you can't have d>k. This is not If the input list has dimension less than d, it can't be done. This is not Likewise with extra dependent vectors - if there aren't enough, it'll fail.

The vectors are processed in order, so if you want a random subset you should shuffle the list first.

as_sum_of_basis(basis,v)

Express the vector v as the sum of the given list of basis vectors. Returns a list of coefficients corresponding to the basis vectors.

JavaScript functions

All JavaScript functions are members of the Numbas.extensions.linearalgebra object.

Fraction(n)

A constructor for a fraction. n is either a number, in which case a rational approximation is computed, or an object {n: numerator, d:denominator}.

Example:

var two = new Fraction(2); var third = new Fraction(1/3); var two_thirds = two.mul(third);

fraction_matrix(matrix)

Convert all the entries in the given matrix to Fraction objects. Returns a new matrix - doesn't modify the original.

unfraction_matrix(matrix)

Convert all the entries in the given matrix from Fraction objects to normal numbers. Returns a new matrix - doesn't modify the original.

row_echelon_form(matrix)

Transforms the given matrix into row echelon form. Returns an object {matrix: matrix, operations: [list of descriptions of the steps]}.

reduced_row_echelon_form(matrix)

Transforms the given matrix into reduced row echelon form. Returns an object {matrix: matrix, operations: [list of descriptions of the steps]}.

is_row_echelon_form(matrix)

Returns true if the given matrix is in row echelon form. If not, throws an error whose message is an explanation of why the matrix isn't in row echelon form.

is_reduced_row_echelon_form(matrix)

Returns true if the given matrix is in reduced row echelon form. If not, throws an error whose message is an explanation of why the matrix isn't in reduced row echelon form.

rank(matrix)

Returns the rank of the given matrix.

is_linearly_independent(vectors)

Returns true if the given list of vectors is linearly independent.

adjoin(matrix,vector)

Add the given column vector to the right of the given matrix.

subset_with_dimension(vectors,n,d)

Returns a subset of n of the given vectors with dimension d.

as_sum_of_basis(basis,v)

Express the vector v as the sum of the given basis vectors. Returns a list of coefficients corresponding to the basis vectors.

]]>
Hexaflex yourself https://somethingorotherwhatever.com/items/hexaflex-yourself 2017-05-11T15:03:37Z Makes a printable template for a hexaflexagon containing a picture from your camera, or any image you upload. Made for outreach purposes at work.

]]>

Makes a printable template for a hexaflexagon containing a picture from your camera, or any image you upload. Made for outreach purposes at work.

]]>
mathsjam.com https://somethingorotherwhatever.com/items/mathsjam-com 2017-05-02T23:00:00Z The homepage for MathsJam. As of 2017, it's my design.

]]>

The MathsJam website

This repository contains the source files to generate the MathsJam website.

Changing something

  • You need a GitHub account to edit the site. If you don't have one, sign up first - it's free!
  • Find the file you want to edit, and click the Edit this file button (it's a little pencil icon in the top right). The files for individual Jams are in the cities folder. Alternatively, each page on the site has an "edit this page" link at the bottom; clicking this will take you to the corresponding GitHub page.
  • Make your changes, then describe what you've done in the text field at the bottom and click "Propose file change".
  • This will allow you to create a pull request, which one of the admins has to approve. They might request further changes or make their own edits. When the pull request is approved, the change will be published to the site.

Organisation of the repository

Information about each city is stored in a file in the cities folder.

Other pages are generated from .md files in the repository. The front page is generated from index.md.

To add a city

Create a file cities/cityname.md, following this template:

```

layout: city
city_name: CityName local_jam_type: MathsJam (for jams in the US this is "MathJam") jam_name: CityName MathsJam email: [email protected] twitter: CityNameMathsJam facebook: https://www.facebook.com/groups/000000000000/ organiser: name: Organiser's name email: [email protected] location: group: england/rest-of-uk/north-america/rest-of-world pub_name: "Ye Pub" description: " on X Street" url: http://www.yepub.website lon: 1.00000000 (get the lat and long from google maps) lat: 50.0000000 hiatus: False (change to True if the Jam is not currently running) hiatus_months: (add this field if the Jam doesn't run for one or two months) - 2016-01 - 2016-02 changed_dates: (add this field if the Jam is running on a different day one month - give the date the Jam will happen) - 2015-03-23 - 2016-09-28 jam_date_rule: second-last Tuesday december_jam_date_rule: third-last Tuesday start_time: 7pm in the evening lang: language code (for British jams, this is "en_GB") poster_text: | Some custom body text for the poster (Only if you want) Maximum seven lines.


```

All the data from this file will be used to create the page for the Jam, and all other references to the city throughout the site.

If your Jam doesn't meet on the second-last Tuesday of the month, you can add a line for 'jam_date_rule' and follow the convention of 'first/second/third/fourth(-last) Weekday', e.g. fourth Thursday, third-last Saturday. If you can't work out how to word it, do your best and we can fix it before merging.

Most Jams run on a different date in December to avoid Christmas, so there's a separate december_jam_date_rule line, with a default of 'third-last Tuesday'.

If you need to put your MathsJam on hiatus for a single month, this is also possible - add the 'hiatus_months' field, and then on successive lines add the months for which you won't be meeting, in the format YYYY-MM, as in the example above. This will automatically add a note to the site and remove it again afterwards. A similar procedure is available using the 'changed_dates' field for if your MathsJam is running on a different date for one particular month.

If you want your poster to be in a different language, set the lang and poster_text fields.

Responsible people

]]>
Nul points! https://somethingorotherwhatever.com/items/nul-points 2017-05-01T16:56:45Z A thing to tot up everyone's ratings while watching Eurovision.

]]>

Nul points!

A thing to tot up everyone's ratings while watching Eurovision.

]]>
tootbib https://somethingorotherwhatever.com/items/tootbib 2017-04-22T10:39:36Z A tool to toot a description of an entry from a bibtex file

]]>
A command-line tool to toot a random entry from bib-site.

Requires Python 3.

To set up:

  • Register a new app with the Mastodon instance: tootbib register --mastodon <URL of your Mastodon instance>
  • Log in to Mastodon: tootbib login --mastodon <URL of your Mastodon instance> --email <your Mastodon account's email address> --password <your Mastodon account's password>

To use:

tootbib --api_base_url <URL of your Mastodon instance> --bibsite <URL of your bib-site instance> will pick a random entry and create a toot.

Other options:

  • --order <piece names separated by spaces> - specify the order in which the pieces of the toot should be assembled. Default is "title author collections abstract url pdf view"
  • --appfile <filename> - path to the file in which to store the token for your Mastodon app.
  • --userfile <filename> - path to the file in which to store the access token for your Mastodon account.
]]>
The MathJax URL https://somethingorotherwhatever.com/items/the-mathjax-url 2017-04-04T23:00:00Z From the time when I needed it lots, and the main MathJax site didn't make it easy to find, I made this page with just the URL to load MathJax.

]]>
From the time when I needed it lots, and the main MathJax site didn't make it easy to find, I made this page with just the URL to load MathJax.

]]>
A day in the life of a maths e-learning officer https://somethingorotherwhatever.com/items/a-day-in-the-life-of-a-maths-e-learning-officer 2017-03-15T09:17:27Z My wife’s school recently sent round a form with questions about “a day in the life” of people working in STEM careers, to show to their year 6 children. My job involves the M in …

]]>

My wife’s school recently sent round a form with questions about “a day in the life” of people working in STEM careers, to show to their year 6 children. My job involves the M in …

]]>
JME marking algorithms https://somethingorotherwhatever.com/items/jme-marking-algorithms 2017-02-02T15:59:09Z A repository I used to develop the marking algorithms feature in Numbas.

]]>
A language for defining marking algorithms

Demo

A marking algorithm is a set of notes.

A note is a name, an optional description, and a list of procedures.

Applying a procedure returns a JME value or an operation on the state.

The state is a stack of credit/validation/feedback instructions. The only operation is to append instructions to the stack.

Evaluating a note consists of applying all of its procedures, and storing the final JME value and state.

Execution order of the notes is determined by dependency.

(Some context: 'JME' is the name for the scripting language used by the e-assessment system Numbas. Here's a reference for the JME language.)

Special notes

The following notes are required:

  • mark - The state at the end of this note will be used to find the student's final score and feedback.
  • as_jme - The student's answer, as a JME value which can be used in adaptive marking or by other parts.

State operations

These operations are implemented as functions which return a list of state instruction tokens.

  • set_credit(n,message) - Set the credit to n, and add a feedback message explaining why
  • multiply_credit(n,message) - Multiply the credit by n, and add a feedback message explaining why
  • add_credit(n,message) - Add n to the credit, and add a feedback message explaining why
  • sub_credit(n,message) - Subtract n from the credit, and add a feedback message explaining why
  • correct(message) - Set the credit to 1, and add a feedback message explaining why
  • incorrect(message) - Set the credit to 0, and add a feedback message explaining why
  • end - End the evaluation here, and don't continue evaluating any other notes which depend on this one
  • fail(message) - End the evaluation here, set credit to 0, mark the student's answer as invalid, and add a feedback message explaining why
  • assert(test, otherwise) - If test is false, apply otherwise
  • warn(message) - Display a warning next to the input box
  • get_answer(part) - Get the student's answer to the given part. The reference can be relative, e.g. g0 will get this part's first gap, while p0g0 will get the first gap in the first part in the question.
  • mark_part(part) - Apply the given part's marking algorithm, and return its final state.
  • feedback(message) - Give the student some feedback
  • apply(state, [title]) - Append the given state (from another note, for example) to the current state. If a title is given, all the applied feedback messages will be grouped under that title.

Inputs

The following variables are available at any point:

  • studentAnswer - the student's answer, exactly as they entered it
  • settings[name] - get the part setting with the given name, e.g. correctAnswer, maxLength.
]]>
Jupyter Interactions https://somethingorotherwhatever.com/items/jupyter-interactions 2017-01-17T16:36:22Z A site to show off interactions in Jupyter notebooks, which were new at the time.

]]>

A site to show off interactions in Jupyter notebooks, which were new at the time.

This was built during a hackathon session at the Computational Mathematics with Jupyter Workshop in Edinburgh, with Mike Croucher and a few others.

]]>
cp's betablog https://somethingorotherwhatever.com/items/cp-s-betablog 2017-01-08T18:18:12Z I tried out making a static blog very slightly before they were cool.

]]>
I tried out making a static blog very slightly before they were cool.

]]>
checkmyworking.com in spress https://somethingorotherwhatever.com/items/checkmyworking-com-in-spress 2016-11-27T15:26:19Z A spress site to create a static version of checkmyworking.com

]]>
A spress site to create a static version of checkmyworking.com

]]>
Staticize WordPress https://somethingorotherwhatever.com/items/staticize-wordpress 2016-11-25T15:41:03Z A tool to convert a WordPress blog to a static site with Spress. Used on checkmyworking.com

]]>
wordpress-staticize

Render a WordPress blog as static files

At the moment, it creates files which can be used by Spress to create the static pages. Eventually I want to get it to trigger Spress each time it updates.

]]>
Zeta plot https://somethingorotherwhatever.com/items/zeta-plot 2016-11-11T16:48:41Z Build up a plot of the Riemann zeta function by spray paint.

]]>

Build up a plot of the Riemann zeta function by spray paint.

]]>
A clever horse - Theory and applications https://somethingorotherwhatever.com/items/a-clever-horse-theory-and-applications 2016-11-05T00:00:00Z Clever Hans was a famous horse who could answer maths questions. I made my own.

]]>

Clever Hans was a famous horse who could answer maths questions. I made my own.

]]>
Grammars for informal notation https://somethingorotherwhatever.com/items/grammars-for-informal-notation 2016-09-22T14:56:17Z An attempt to produce grammars to describe informal mathematician, which is often ambiguous and inconsistent.

]]>
We're working on a system which can parse student's ambiguous mathematical notation.

  1. Offer suggestions or decided what is meant based on context.
  2. Flexible parsing rules based on commonly used mathematical contexts.
  3. Output the resulting parse-trees in a variety of languages, e.g. LaTeX, Maxima.

The longer term goal of this work is to use the resulting parser in an online assessment system with students.

To run the tests

  • Install npm
  • Install nearley: npm install nearley
  • Compile the grammar to JavaScript: make jme-nearley.js
  • Now test.html should work.

Parsing libraries

  • PEGjs - creates simple, unambiguous parsers.
  • Nearley - creates very versatile parsers, and returns multiple results for ambiguous grammars.
]]>
Numbro extension for Numbas https://somethingorotherwhatever.com/items/numbro-extension-for-numbas 2016-07-28T12:18:55Z Format numbers and currency amounts with numbro.js

]]>
Numbro extension for Numbas

numbro.js provides functions to format numbers and currency amounts.

It uses its own format specification language, which is defined by example. See the numbro.js docs for examples of what's possible.

At the moment, numbro keeps the language setting in a global variable, which makes it difficult to provide formatting functions which take a language/culture parameter without affecting other calls to numbro.

To set the language/culture for a question, call numbro.culture in the question preamble, e.g. numbro.culture('nb-NO').

There's a question showing how to use this extension at https://numbas.mathcentre.ac.uk/question/15000/format-numbers-and-currency-amounts-with-numbro-js/

JME functions

format(n,format)

Format the number n following the given format.

Example: format(1234.5,'0,0.00')"1,234.50"

formatcurrency(n,format)

Format n as a currency amount, following the given format.

Example: formatcurrency(12345,'0a')$12k (when the language is the default value, en-US)

formatcurrency(n,format,currencySymbol)

Format n as a currency amount, following the given format and with the given currency symbol.

Example: formatcurrency(12345,'0a','£')£12k

Licence

numbro.js is © 2014 Adam Draper, © 2015 Företagsplatsen AB, and released under the MIT licence.

This extension is © 2016 Newcastle University.

]]>
Interactive Puzzlebomb puzzles https://somethingorotherwhatever.com/items/interactive-puzzlebomb-puzzles 2016-07-15T07:35:31Z Interactive versions of the early Puzzlebomb puzzle sheets. Made in Elm.

]]>

Interactive Puzzlebomb

Interactive versions of the Puzzlebomb puzzle sheets

]]>
GeoGebra extension for Numbas https://somethingorotherwhatever.com/items/geogebra-extension-for-numbas 2016-07-07T14:37:58Z An extension for Numbas which integrates GeoGebra materials

]]>

GeoGebra extension for Numbas

An extension for Numbas which integrates GeoGebra materials.

To use this extension in a question, tick the "GeoGebra" option on the Extensions and Scripts tab.

All the GeoGebra resources are loaded from geogebra.org, so this extension WILL NOT work offline, or in environments where that domain is blocked or otherwise inaccessible.

Warning: At the moment, there's no way for this code to detect when the GeoGebra embedding fails, either due to an incorrect ID or a network issue. If you just get "geogebra applet loading..." for a long time, check your browser's console.

JME functions

geogebra_applet(id or dimensions, [object definitions], [object-part links]) → ggbapplet

Load a GeoGebra material or create a blank worksheet, and optionally modify or create some objects and set up links between objects and question parts

The parameters begin with either the ID of a material to load from geogebra.org, or a pair of numbers representing the width and height of a blank applet worksheet. The material ID is or the URL of the material, such as https://www.geogebra.org/m/jJ3zQ29z or http://ggbm.at/jJ3zQ29z, or just the random-looking bit, e.g. jJ3zQ29z.

The next parameter is an optional dictionary of definitions (or re-definitions) of objects. The definition can be a value on its own, or a dictionary of properties to set.

If you give a dictionary of properties, the following properties are understood:

  • definition (a value for the object, or a GeoGebra command)
  • caption
  • color (any valid CSS color is accepted)
  • visible
  • label_visible
  • label_style
  • fixed
  • trace
  • rename
  • layer
  • line_style
  • line_thickness
  • point_style
  • point_size
  • display_style
  • filling

The definition can be:

  • a number;
  • a vector, which produces a point in the GeoGebra applet;
  • a string, which is interpreted as a GeoGebra command;
  • a list of any of the above types of value.

If the object with the given name is already defined in the applet, then it is updated with the new definition you give. So you can set up your whole worksheet in the GeoGebra editor with placeholder values, and then replace them with the values generated by your question when it runs.

The optional final parameter is a list of links between GeoGebra objects and Numbas parts, in the format [object or exercise name, part id]. When the object changes in GeoGebra, the answer input for the corresponding part is updated, and vice versa.

Be careful about linking dependent objects to part answers: if the student changes the part's answer input, the GeoGebra worksheet can't be updated to reflect that. So only link independent objects to part answers. If you want to use the position of a dependent object in the marking of a part, use an 'extension' type part and the functions detailed below to get the part's position in a custom marking algorithm.

The object returned by this function can be embedded in any content area just like an HTML value.

Example usage

geogebra_applet('https://www.geogebra.org/m/jJ3zQ29z',[A: vector(ax,ay), B: vector(bx,by), C: vector(cx,cy)])

Loads the given worksheet, and moves points A,B and C to the given positions.

geogebra_applet(800,500,[A: ["definition": vector(1,0), "color": red"]], [["A","p0"]])

Creates a blank worksheet with size 800 by 500 pixels, adds an object A at (1,0) and links the position of A with the answer to the first part in the question.

geogebra_file(filename, [object definitions], [object-part links]) → ggbapplet

Load a GeoGebra file from the given file.

The filename parameter can be the name of a resource attached to the question, or the URL of any .ggb file.

The 'object definitions' and 'object-part links' parameters work the same way as for geogebra_applet.

geogebra_base64(base64, width, height, [object definitions], [object-part links]) → ggbapplet

Create a GeoGebra applet from the given base64-encoded .ggb file, with the given width and height in pixels.

If you have the base64-encoded version of a .ggb file, this function will create a GeoGebra applet with the given dimensions and load the given worksheet in it.

One way of obtaining the base 64 string for a GeoGebra applet is to run ggbApplet.getBase64() on a page containing the applet. Note: the variable won't always be called ggbApplet - on geogebra.org, for example, a unique string of digits is appended to the variable name.

The 'object definitions' and 'object-part links' parameters work the same way as for geogebra_applet.

Functions to obtain properties of objects

Warning: Because of the way GeoGebra loads, these functions only work once the applet has been displayed. That means they don't work during question variable generation. The intended use for these functions is in part marking algorithms.

The following functions get properties of a named object from a GeoGebra applet created with one of the functions above. They are all have the calling signature property(app,object name), e.g. value(app,"A").

  • value - a representation of the object's value.
  • x - the X coordinate
  • y - the Y coordinate
  • z - the Z coordinate
  • color - the color of the object, as a hex string (e.g. #4D4DFF)
  • visible - is the object visible?
  • value_string - GeoGebra's string representation of the object.
  • definition_string - the description of the object.
  • command_string - the command of the object.
  • latex_string - a string of LaTeX representing the object.
  • type - the type of the object, e.g. "point", "numeric".
  • exists - does the object exist in the applet?
  • defined - is the object's value valid at the moment?
  • layer - the layer the object is in.
  • line_style
  • line_thickness
  • point_style
  • point_size
  • caption
  • label_style

An example marking algorithm

This marking algorithm marks the part as correct if the point A is positioned at the coordinates (1,2). The GeoGebra applet has been defined in the variable app.

``` a_pos (The position of the object A, as a vector): value(app,"A")

mark: feedback("A is at $\var{latex(a_pos)}$"); correctif(a_pos=target_position)

interpreted_answer: a_pos ```

JavaScript functions

createGeogebraApplet(options,replacements,parts,question)

options is a dictionary of GeoGebra applet parameters. This function returns a Promise object which resolves to an object {app: <GeoGebra applet>, element: <HTML element containing the applet>}.

You could use this function to load an applet and then manipulate it with the GeoGebra JavaScript API before embedding it in the page.

Note that because this function returns a promise, the applet will not have finished loading at the time the question is displayed to the student. You'll have to insert the applet in the page yourself once the promise resolves.

tokToGeoGebra(token)

Convert a Numbas JME token to a GeoGebra command.

geoGebraToTok(app,name)

Get a JME token representing the value of a GeoGebra object.

app is a GGBApplet object, and name is the name of the GeoGebra object to convert.

Objects of type 'point' are converted to vectors, 'numeric' to numbers, and everything else to strings.

]]>
Sierpinski dots https://somethingorotherwhatever.com/items/sierpinski-dots 2016-06-20T10:31:24Z A thing to play the Chaos game on a triangle, making the Sierpiński triangle.

]]>

A thing to play the Chaos game on a triangle, making the Sierpiński triangle.

]]>
emojiördinates https://somethingorotherwhatever.com/items/emojiordinates 2016-06-14T09:21:33Z Because What3Words is stupid, I made this thing to convert lat/long coordinates into a sequence of four emoji.

]]>

emojiördinates

Because What3Words is stupid, here's a thing that converts a lat/long into 4 emoji, and back. It doesn't do anything clever with projections or tilings - it just scales lat and longs linearly onto a 2×(766²)×(766²) grid, and maps that onto four emoji, picked from the set of 912 that emojiOne can render without any combining characters.

The encoding is completely dependent on the set of emoji I chose, and their order - I think they're in ascending Unicode order.

]]>
A quiz in Elm https://somethingorotherwhatever.com/items/a-quiz-in-elm 2016-06-05T17:36:17Z I wondered how much work it would be to write a quiz system like Numbas, in Elm. The hardest part was thinking about randomising, because I didn't have a good understanding of how Elm's randomisation works.

]]>

elm-quiz

A toy quiz system written in Elm.

I'm just playing about with the Elm language. I thought a little quiz would be a good project to experiment with.

At the moment, the Elm standard library (and even the community packages) don't offer much, so this implements some very basic things.

To build it, run elm-make quiz.elm --output=quiz.js, then open index.html.

]]>
Katie's nail painting puzzle https://somethingorotherwhatever.com/items/katie-s-nail-painting-puzzle 2016-05-21T10:07:14Z A game based on Katie Steckles's binary nail-painting puzzle.

]]>

Katie's nail-painting puzzle

A game based on Katie Steckles's binary nail-painting puzzle. The aim is to add or remove varnish from your nails in a sequence such that every combination of painted/unpainted appears on your hand once, while minimising the number of times you remove paint from a finger (acetone isn't free).

Drag rows of the sequence to reorder them. Your best score is shown in red; click it to restore the sequence that made that score.

]]>
bib-site https://somethingorotherwhatever.com/items/bib-site 2016-05-20T10:33:35Z An interface to browse and edit a .bib file

]]>
This is a set of PHP scripts which provide an interface to browse and edit a .bib file. Everything happens in the .bib file - no SQL database or anything like that needed.

Even if you don't need that, you might like bib-parse.php, which does a better job of parsing .bib files (or at least, my .bib files) than any other PHP parser I found.

I use this to run read.somethingorotherwhatever.com

]]>
Interesting Esoterica https://somethingorotherwhatever.com/items/interesting-esoterica 2016-05-18T23:00:00Z This site hosts my list of interesting and unusual papers that I have collected over the years. Many of the references are kept here so I can easily find them again when I want to tell someone about the really interesting idea they contain; others are here only because they caught my eye when I first came across them.

]]>

This site hosts my list of interesting and unusual papers that I have collected over the years. Many of the references are kept here so I can easily find them again when I want to tell someone about the really interesting idea they contain; others are here only because they caught my eye when I first came across them.

]]>
Numbas LTI tool provider https://somethingorotherwhatever.com/items/numbas-lti-tool-provider 2016-05-02T19:08:47Z An LTI tool provider to run Numbas exams

]]>
Numbas logo

LTI tool provider

This is a Basic LTI 1.1 tool provider, to run Numbas exams in any LTI-compatible virtual learning environment.

The tool handles attempt data, and as well as offering CSV exports of student scores can report scores back to the host VLE's gradebook.

What do I need in order to use this?

You must run your own instance of this tool - as well as using a fair amount of server resources, we don't want to keep other people's student data!

To install the tool, you need:

  • A dedicated server to install the software on, which will communicate with your virtual learning environment. At Newcastle, we use servers running Ubuntu.
  • The ability to add a link to an LTI tool to your virtual learning environment. In Blackboard and Moodle, only administrators can do this.

At most institutions, this will require the help of your IT team.

If you're unsure whether you can use the LTI tool provider, or want help setting it up, email the Numbas team.

How to use

The set-up process looks like this:

  • Install the software on your own server, or on the cloud platform Heroku.
  • Complete the initial set-up, creating an admin account and an LTI consumer key.
  • Add the LTI tool to your VLE using the details provided.
  • When you access the tool from your VLE, upload a Numbas SCORM package, and you're done!

Documentation

See full documentation at docs.numbas.org.uk/lti.

]]>
Approximate a ratio by folding a piece of paper https://somethingorotherwhatever.com/items/approximate-a-ratio-by-folding-a-piece-of-paper 2016-04-23T12:54:47Z Warning: you could make a very strong argument I’ve thought far too much about something inconsequential. If that makes your stomach turn, look away now. This morning in the shower, I had an …

]]>

Warning: you could make a very strong argument I’ve thought far too much about something inconsequential. If that makes your stomach turn, look away now. This morning in the shower, I had an …

]]>
Prime tapestry https://somethingorotherwhatever.com/items/prime-tapestry 2016-04-06T20:37:51Z Inspired by Barry Dalgarno (ignore the nonsense)

]]>

Inspired by https://sites.google.com/site/geometryoftheprimes/ (ignore the nonsense)

]]>
Eat something or other, whatever https://somethingorotherwhatever.com/items/eat-something-or-other-whatever 2016-03-29T23:00:00Z A site for me to collect recipes I like. I tried doing something clever with natural language processing to highlight the measurements in the ingredients, but it doesn't work very well.

]]>

A site for me to collect recipes I like. I tried doing something clever with natural language processing to highlight the measurements in the ingredients, but it doesn't work very well.

]]>
π - It's complicated https://somethingorotherwhatever.com/items/it-s-complicated 2016-03-14T00:00:00Z A talk about calculating π, given at Durham University for π day 2016. Contains lots of animations.

]]>

A talk about calculating π, given at Durham University for π day 2016. Contains lots of animations.

]]>
isthisprime.com https://somethingorotherwhatever.com/items/isthisprime-com 2016-03-08T21:27:51Z It's just a website that does one thing: tells you if a number is prime or not. It's been useful surprisingly often!

]]>

isthisprime.com

This is the code which runs the website isthisprime.com.

Copyright 2016 Christian Lawson-Perfect

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

]]>
The Is this prime? game https://somethingorotherwhatever.com/items/the-is-this-prime-game 2016-03-07T00:00:00Z All you have to do is say whether each number is prime.

]]>

All you have to do is say whether each number is prime.

]]>
Code Clicker https://somethingorotherwhatever.com/items/code-clicker 2016-02-27T11:42:31Z A clicker game where each click runs a program you've written. You get points for completing challenges, but each operation in your program costs points. It works OK, but I didn't have the motivation to finish it.

]]>

A clicker game where each click runs a program you've written. You get points for completing challenges, but each operation in your program costs points. It works OK, but I didn't have the motivation to finish it.

]]>
Maths Objects https://somethingorotherwhatever.com/items/maths-objects 2016-02-20T00:00:00Z A series of videos about mathematical objects.

]]>

A series of videos about mathematical objects.

]]>
Pancake flipping https://somethingorotherwhatever.com/items/pancake-flipping 2016-02-06T18:05:38Z An interactive toy for the pancake-flipping problem, to go with a post by Katie Steckles on The Aperiodical. By repeatedly flipping the top part of a stack of pancakes, can you sort them by size?

]]>

An interactive toy for the pancake-flipping problem, to go with a post by Katie Steckles on The Aperiodical. By repeatedly flipping the top part of a stack of pancakes, can you sort them by size?

]]>
Circle designs https://somethingorotherwhatever.com/items/circle-designs 2016-02-04T09:51:12Z Generates nice designs made of subdivided circle quadrants.

]]>

Generates nice designs made of subdivided circle quadrants.

]]>
Blackboard Numbas SCORM analysis https://somethingorotherwhatever.com/items/blackboard-numbas-scorm-analysis 2016-02-01T13:52:11Z Because Blackboard's built-in SCORM player is so rubbish, I made this tool to give a better presentation of data from Numbas SCORM packages.

]]>

Blackboard SCORM analysis

Part of a report

Blackboard doesn't make it easy to analyse data to do with SCORM packages: the built-in SCORM reports don't give much useful information and are tedious to generate, and it's unclear where in the database the SCORM data lies.

We discovered that the Export/Archive Course tool collects together all of the attempt data for SCORM packages in a way that can be easily interpreted.

This tool allows you to analyse all of the information held by Blackboard about SCORM packages in your course, by presenting the data from a course archive nicely. It's designed to work with SCORM packages generated using Numbas; other packages might work, but we don't guarantee it.

First, a warning

We've found that Blackboard often loses data, or saves inconsistent data. That can mean that a student's attempt is missing, or the question scores don't tally up with the part scores, or the suspend data and correct answers don't match what the student saw.

This happens in a small but significant number of cases. It should be obvious on looking at an individual attempt whether there's something wrong, but bear in mind that inconsistencies can appear if you try to do analyse the set of attempts as a whole.

We've also had a report that if any student has unenrolled from a course, the export will stop as soon as it tries to match an attempt by that student with their Grade Centre entry. This means that tests will appear to have far fewer attempts in the analysis tool than are shown in the Grade Centre.

Finally, the reported durations of attempts only rarely match up with reality. Best not to try to draw any conclusions from those.

Installation

The tool is a self-contained Python Flask server, which you can run on your own PC. Install Python 3, and then install the required Python packages by running the following command:

pip install -r requirements.txt

Obtain a copy of the Blackboard SCORM analysis server (either clone this repository or download a .zip) and extract it into a directory on your PC.

To start the server, run

python server.py

And open http://localhost:5000 in your browser.

Uploading a course

  • Go to your Blackboard course, and click on Packages and Utilities, then Export/Archive Course.
  • Click on the Archive Course button.
  • In the following form, make sure Include Grade Centre History is ticked, then click Submit.
  • It takes a while to create the archive. You'll get an email when it's ready - once that happens, go back to the Export/Archive Course page and click on the .zip file to download it.
  • In the Blackboard SCORM analysis tool, click on Upload a zip file, and then upload the file you just got from Blackboard.

You can update a course's data by generating another archive and uploading that. The old version will be automatically rewritten.

]]>
The Great Intersectionator https://somethingorotherwhatever.com/items/the-great-intersectionator 2016-01-22T12:06:27Z I found a load of corpuses of words. I made this to show the words that are in the intersections of several corpuses.

]]>

I found a load of corpuses of words. I made this to show the words that are in the intersections of several corpuses.

]]>
Duopoly https://somethingorotherwhatever.com/items/duopoly 2016-01-15T20:00:26Z A game about drawing lines

]]>

duopoly

A game about drawing lines

  • Take turns drawing lines on the board.
  • Each player must place two lines per turn.
  • When you connect two lines, you score the difference in their lengths.
  • The game ends when the board is full.
]]>
punchcards https://somethingorotherwhatever.com/items/punchcards 2015-12-07T06:57:19Z I never used real computer punchcards, so this is a simulation of how I think they worked. Click bits to turn them on or off, or in Lovelace mode you can't unpunch a hole! Shows the ASCII decoding of the card on the top.

]]>

I never used real computer punchcards, so this is a simulation of how I think they worked. Click bits to turn them on or off, or in Lovelace mode you can't unpunch a hole! Shows the ASCII decoding of the card on the top.

]]>
Unfurl an image https://somethingorotherwhatever.com/items/unfurl-an-image 2015-12-02T09:52:44Z A thing to do a coordinate transformation on an image. The example it loads with transforms from polar to cartesian coordinates.

]]>

A thing to do a coordinate transformation on an image. The example it loads with transforms from polar to cartesian coordinates.

]]>
Ask Clever Hans a question https://somethingorotherwhatever.com/items/ask-clever-hans-a-question 2015-11-21T17:10:52Z Before I made the physical Clever Hans, I made this page which uses speech recognition and a formal grammar to answer arithmetic questions. Featuring the pixelated horse from my horsey game.

]]>

It's a clever horse who can answer maths questions.

The code for the real-life Clever Hans is in the robot branch.

]]>
Traffic thingy https://somethingorotherwhatever.com/items/traffic-thingy 2015-11-08T14:09:53Z A little tool to help Cushing try out the birthday problem with cars - how many cars should you expect to drive past before having a 50% chance of seeing the same string of final 3 letters twice?

]]>
Traffic tracker

A little tool to help Cushing try out the birthday problem with cars - how many cars should you expect to drive past before having a 50% chance of seeing the same string of final 3 letters twice?

Type the registration of each car you see (or just the last three letters), and it'll tell you when you see a double.

]]>
Droste Dobble https://somethingorotherwhatever.com/items/droste-dobble 2015-11-06T11:14:28Z Exploiting a fact about projective planes

]]>

This goes with a Big MathsJam talk from 2015.

Dobble cards are points on a projective plane.

Each line contains all of the cards with a given symbol.

But a projective plane is its own dual: ifyou swap the lines and points, you get the same structure!

So there's no reason you shouldn't replace the symbols on a Dobble card with more Dobble cards.

]]>
Optimisation problems extension for Numbas https://somethingorotherwhatever.com/items/optimisation-problems-extension-for-numbas 2015-09-28T14:34:23Z An extension for Numbas providing functions to help with optimisation problems

]]>
Optimisation problems extension for Numbas

This extension provides functions to work with linear programs and other optimisation problems.

JME functions

random_partition(n,k,[minimum=1])

Generate a random partition of n into k parts, with smallest part at least minimum.

best_point(program)

Solve a linear program with minimum constraints for each product, maximum constraints for each resource, numbers of each resource used in each product, and a straight line objective function

  • minimum_x, minimum_y: minimum allocations for each product
  • resources_x, resources_y: numbers of each resource used to make 1 unit of each product
  • max_resource_1, max_resource_2: available quantities of each resource
  • profit_x, profit_y: profit per unit of each product

Looks at the following intersection points:

  • 0 - resource 1 with minimum x
  • 1 - resource 2 with minimum x
  • 2 - resource 1 with minimum y
  • 3 - resource 2 with minimum y
  • 4 - resource 1 with resource 2

Returns the index of the intersection point giving maximum profit

best_coords(program)

With program encoded as above, returns the coordinates [x,y] of the point giving the maximum profit

binding_lines(program)

With program encoded as above, returns an array of booleans specifying which lines are binding (touching the optimal solution), from the following: [resource 1, resource 2, minimum x, minimum y]

nw_corner(supplies,demands)

Use the NW corner algorithm to generate a first guess at an optimal solution to a transportation problem. supplies specifies the number of units supplied by each source, and demand specifies the number of units demanded by each destination.

Returns a matrix of the number of units to transport from each source to each destination.

nw_corner_display(supplies,demands)

HTML representation of the stages of the NW corner algorithm

minimum_cost(supplies,demands,costs)

Find the solution to the transportation problem which minimises total cost.

Returns a matrix of the number of units to transport from each source to each destination.

minimum_cost_display(supplies,demands,costs)

HTML representation of the stages of the minimum cost algorithm.

shadow_costs(assignments,allocated,costs)

Returns a list [m,rows,columns], where m is the shadow cost of each cell in the assignment matrix, and rows and columns give the shadow costs for each row and column, respectively.

assignment_is_optimal(assignments,costs)

Returns true if the given assignment (matrix of number of units to deliver from each source to each destination) minimises the total cost.

assignment_is_valid(assignments,supplies,demands)

Returns true if the given assignment is valid - the amount supplied from each source doesn't exceeed the available supply, and the amount delivered to each destination doesn't exceed the demand.

stepping_stone_works(assignments,costs)

Returns true if the stepping stone algorithm to find an optimal assignment terminates.

stepping_stone(assignments,costs)

Find an optimal solution to the given assignment problem, with the stepping stones method, starting with the given assignment.

Returns a matrix of assignments.

stepping_stone_display(assignments,costs)

HTML representation of the steps of the stepping stone method.

assignment_cost(assignments,costs)

Total cost of the given assignment

cost_table(supply,demand,costs)

A table showing the cost matrix for the given assignment problem

assignment_table(assignments,supply,demand)

A table showing the given assignment

show_cost_calculation(assignments,costs)

LaTeX description of the calculation of the total cost of the given assignment

job_cost_table(costs,worker_name,job_name)

A table showing the costs for each worker at each job. worker_name and job_name give the headings for workers and jobs, respectively (e.g., "Delivery driver" and "Route")

hungarian(costs)

Perform the Hungarian algorithm to assign workers to jobs, minimising the total cost. Returns a matrix with 1 in the cell (worker,job) when the corresponding worker is assigned to the corresponding job, and 0 otherwise.

hungarian_display(costs)

HTML representation of the steps of the Hungarian algorithm.

utility_set(utility,actions)

HTML graph showing the given set of points in a 2D decision problem. utility is a list of 2d coordinates [x,y], and actions is a list of labels.

show_expected_value_criteria(utility,labels,prob_state_1,prob_state_2)

HTML graph showing the utility set, with the expected value criterion line defined by prob_state_1 and prob_state_2.

evpi(utility,probabilities)

Expected value of perfect information in the given decision problem, with the given (vector or list of) probabilities.

simplex(objective,equations)

Solve the given linear programming problem with the simplex method

simplex_optimal_tableau(objective,equations)

Matrix representing the optimal tableau when the simplex algorithm terminates.

simplex_find_bascs(tableau)

List specifying which row each variable is basic in, in the given simplex tableau, or-1 if the variable is not basic.

simplex_display(objective,equations)

HTML representation of the steps of the simplex method.

simplex_final_tableau(objective,equations)

HTML representation of an optimal simplex tableau for the given problem.

convex_hull(points)

The convex hull of the given list of points. Returns a list of points, in clockwise order.

]]>
Tennis graph https://somethingorotherwhatever.com/items/tennis-graph 2015-09-18T14:29:55Z A state diagram of a complete tennis match

]]>

A state diagram of a complete tennis match

Released under the CC-BY 3.0 licence. Please give credit to Christian Lawson-Perfect.

]]>
30 second challenge https://somethingorotherwhatever.com/items/30-second-challenge 2015-07-19T17:48:58Z Inspired by the newspaper puzzle my wife's grandma tests me with each time I visit.

]]>

Inspired by the puzzle that my wife's grandma tests me with each time I visit.

Start with the number in the first box and follow the instructions until you get to the end. Enter your answer and press enter (or click on the timer).

Licence

Copyright 2015 Christian Lawson-Perfect

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

]]>
Write maths with JME https://somethingorotherwhatever.com/items/write-maths-with-jme 2015-07-14T23:00:00Z Write maths, see maths applied to JME expressions from Numbas.

]]>
Write maths, see maths applied to JME expressions from Numbas.

]]>
Sequences https://somethingorotherwhatever.com/items/sequences 2015-06-04T15:35:01Z a numbers-in-a-grid game

]]>

sequences

A numbers-in-a-grid game.

Licence

Copyright 2015 Christian Lawson-Perfect

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

]]>
three.onefouronefivenine.com https://somethingorotherwhatever.com/items/three-onefouronefivenine-com 2015-03-14T00:00:00Z A page that scrolls the digits of π endlessly, using Gosper's spigot algorithm.

]]>

A page that scrolls the digits of π endlessly, using Gosper's spigot algorithm.

]]>
Wolfram|Alpha can’t. But CP can! https://somethingorotherwhatever.com/items/wolfram-alpha-cant-but-cp-can 2015-03-02T16:46:53Z Christian Perfect has turned into a one-man plug for the holes in Wolfram|Alpha.

]]>

Christian Perfect has turned into a one-man plug for the holes in Wolfram|Alpha.

]]>
Word Lock https://somethingorotherwhatever.com/items/word-lock 2015-02-02T09:53:17Z The Word Lock puzzle from February 2015's puzzlebomb

]]>

The Word Lock puzzle from February 2015's puzzlebomb

]]>
Polynomials extension for Numbas https://somethingorotherwhatever.com/items/polynomials-extension-for-numbas 2015-01-20T16:40:55Z An extension for Numbas which provides a "polynomial" data type and associated operations

]]>
Polynomials extension for Numbas

This extension provides a new data type and some functions to deal with polynomials

JME data type

This extension adds a new JME data type Numbas.jme.types.polynomial, representing a polynomial in a given variable.

JME functions

polynomial(expression in one variable)

Create a polynomial, automatically detecting the variable name from the expression. This is quite strict about what it accepts - only one variable name, and coefficients and degrees have to be literal numbers, not calculations or references to other variables.

You can either write a literal expression, or pass a string. Note that if you use a literal expression, variables defined in the scope are substituted in. It's safer to use a string.

Examples

  • polynomial(x^2-2x+3)
  • polynomial("5*x^4 + 2*x")

polynomial(variable_name,coefficients)

Create a polynomial in the given variable, with the given coefficients (coefficients[i] is the coefficient of variable_name^i). Example: polynomial(x,[-1,0,1]) represents the polynomial x^2-1.

mod_polynomial(expression,m) or mod_polynomial(variable_name,coefficients,m)

As above, but all operations on this polynomial will be calculated modulo m.

p1+p2

Add two polynomials

p1+n or n+p1

Add a constant to a polynomial - more convenient than p+polynomial(n).

p1-p2

Subtract p2 from p1

p1-n or n-p1

Subtract a constant from a polynomial (or vice versa) - more convenient than p-polynomial(n).

p1*p2

Multiply two polynomials

p1*n or n*p1

Multiply a polynomial by a constant - more convenient than p*polynomial(n).

p^n

Take polynomial p to the nth (integer, non-negative) power.

quotient(p1,p2)

Divide p1 by p2, and throw away the remainder (polynomial quotient of p1 and p2)

remainder(p1,p2)

Remainder when dividing p1 by p2.

mod(p,n)

Take each coefficient of p mod n.

degree(p)

Degree of p - highest power of the variable with a non-zero coefficient.

p1=p2

Are p1 and p2 equal? True if all the coefficients match.

p[d]

Coefficient of x^d in p.

eval(p,x)

Evaluate the polynomial at the given point.

expr(p)

A JME expression equivalent to the given polynomial; you can substitute this into the correct answer for a "Mathematical expression" part, for example.

string(p)

A string representation of the polynomial.

latex(p)

A LaTeX representation of the polynomial.

long_division(p1,p2)

LaTeX rendering of the long division of p1 by p2.

JavaScript functions

Base object: Numbas.extensions.polynomials.Polynomial

(set it to a more convenient name, e.g. var poly = Numbas.extensions.polynomials.Polynomial)

new Polynomial(variable_name,coefficients,[modulo])

coefficients is a dictionary of degree → coefficient. If modulo is given, all coefficients will be reduced modulo that number in any calculations using this polynomial.

Polynomial.from_tree(tree,[modulo])

Create a polynomial object from a compiled JME tree

Polynomial.from_string(expr,[modulo])

Create a polynomial object from a JME string

Polynomial object methods

p.evaluate(x)

Evaluate at point x to a number

p.toLaTeX()

Render as a LaTeX string

p.isZero()

Is this polynomial zero?

p.degree()

Degree of highest power term in p with a non-zero coefficient

p.negate()

Negate every coefficient of p (returns a new polynomial)

p1.add(p2)

Add p1 to p2

p1.sub(p2)

Subtract p2 from p1

p1.mul(p2)

Mutliply p1 by p2

p.pow(n)

nth power of p

p.scale(n)

Multiply p by constant n

p.add_degree(n)

Add n to the degree of each term of p

p1.div(p2)

Divide p1 by p2. Returns an object {quotient: <polynomial>, remainder: <polynomial>}

p.mod(n)

Take each coefficient of p mod n (returns a new polynomial object)

p1.eq(p2)

Are p1 and p2 equal?

p.coefficient(d)

Coefficient of x^d in p.

]]>
Word game https://somethingorotherwhatever.com/items/word-game 2015-01-16T15:24:08Z A ripoff of a word game

]]>
A ripoff of a word game

]]>
Wordsearch generator https://somethingorotherwhatever.com/items/wordsearch-generator 2014-12-16T11:34:31Z Given a list of words, generates a wordsearch.

]]>

Given a list of words, generates a wordsearch.

]]>
Watch out! I’m a blue whale and I’m about to land on you! https://somethingorotherwhatever.com/items/watch-out-im-a-blue-whale-and-im-about-to-land-on-you 2014-11-20T12:15:03Z Christian investigates the possibility of a moving whale being able to warn you it’s coming.

]]>

Christian investigates the possibility of a moving whale being able to warn you it’s coming.

]]>
Apparently I’m not a maths genius (or, On the Subject of Parcel Sizes) https://somethingorotherwhatever.com/items/apparently-im-not-a-maths-genius-or-on-the-subject-of-parcel-sizes 2014-11-19T14:30:19Z Christian investigates the mystery of Hermes’ maximum parcel dimensions.

]]>
Christian investigates the mystery of Hermes’ maximum parcel dimensions.

]]>
Linear codes extension for Numbas https://somethingorotherwhatever.com/items/linear-codes-extension-for-numbas 2014-11-13T14:43:13Z This Numbas extension adds stuff to work with linear codes.

]]>
Linear codes extension for Numbas

This extension provides a new data type and some functions to deal with linear codes.

A collection of questions created using this extension is available to reuse.

JME data types

This extension adds two new JME data types, Numbas.jme.types.codeword and Numbas.jme.types.code.

JME functions

codeword(digits,field_size)

Create a codeword from a list or vector of digits, in Z_{field_size}. For example, codeword([1,1,0,1],2)

codeword(word_string,field_size)

Create a codeword from a string of digits, in Z_{field_size}. For example, codeword("11001",2)

zero(word_length,field_size)

The zero word of the given length in the field Z_{field_size}.

is_zero(word)

Is word a zero word (are all its digits 0)?

latex(codeword)

A LaTeX rendering of the given codeword.

word1+word2

Add two codewords.

word1-word2

Subtract one codeword from another.

n*word or word*n

Multiply a codeword by a scalar.

word[n]

nth digit of codeword.

word[m..n]

List of mth to nth digits of codeword.

weight(w)

Hamming weight of the word.

allwords(word_length,field_size)

Generate a list of all codewords of given length in Z_{field_size}.

random_word(word_length,field_size)

Pick a random word of given length in Z_{field_size}.

random_combination(words)

A random linear combination of the given words (from the field Z_p), i.e. a_0*w_0 + a_1*w_1 + ... + a_n*w_n where the a_i are elements of the field Z_p.

set_generated_by(basis)

Returns the set of codewords generated by the given list of basis codewords.

is_generated_by(basis,words)

Can all of the given words be written as a linear combination of the words in basis?

linearly_independent(basis)

Are the given codewords linearly independent? (it checks that the set generated by the basis contains (field_size)^(number of basis words) words)

coset_containing(word,basis)

Generate the coset containing the given word, with respect to the given generating set.

slepian_array(basis)

Generate the Slepian array corresponding to the given basis set. Each row in the result is a coset, sorted by weight.

is_coset_leader(word,basis)

Is the given word a coset leader in its coset? That is, does it have the minimum weight?

generator_matrix(words)

A minimal set of generators for the linear code generated by the given words. If the words are linearly independent, you'll get the same number of words back, otherwise you'll get fewer.

parity_check_matrix(basis)

Create a parity check matrix for the given generating set, by putting it in reduced row-echelon form I_n|A and returning -A_transpose|I_(m).

lexicographic_parity_check_matrix(words)

Create a parity check matrix for the given generating set, with columns in lexicographic order.

hamming_parity_check_matrix(p,r)

Create a parity check matrix for the Hamming code Ham_p(r). (p must be prime)

hamming_generating_matrix(p,r)

Create a generating matrix for the Hamming code Ham_p(r). (p must be prime)

syndrome(word,pcm)

Compute the syndrome of the given word with respect to the given parity check matrix.

reduced_row_echelon_form(basis)

Put the given list of words (interpreted as a matrix) into reduced row-echelon form.

codeword_matrix(words)

Returns a matrix whose rows are the given codewords.

hamming_square_encode(word)

Encode word using Hamming's square code.

hamming_square_decode(word)

Decode (and correct up to one error in) word using Hamming's square code.

hamming_encode(word)

Encode word using the general Hamming code.

hamming_decode(word)

Decode (and correct up to one error in) word using the general Hamming code.

hamming_distance(word1,word2)

Hamming distance between two codewords.

hamming_ball(word,radius)

All words within given Hamming distance of the given codeword.

hamming_sphere(word,radius)

All words at given Hamming distance from the given codeword.

concat([words])

Concatenate a list of codewords into one codeword.

len(word)

Length of a codeword.

error(word,position)

Introduce an error (change a digit) at the given position. Returns a new codeword.

check_array(word)

Returns a LaTeX check-array for the given word, from a Hamming square code.

string(word)

String representation of a codeword.

latex(word)

LaTeX representation of a codeword.

code([words])

Create a code from a complete set of codewords.

allwords(code)

All words belonging to the given code.

minimum_distance(code)

Minimum Hamming distance between words in code.

information_rate(code)

A code's information rate

len(code)

Number of words in code.

code[n]

nth word in code. (in the order used when you created the code object)

code[m..n]

List of the mth to nth words in code.

positional_permutation(code,positions)

Permute the positions of the digits in code's words, following the given order.

symbolic_permutation(code,symbols)

Permute the symbols in code's words, following the given order. symbols is a list giving a permutation for each digit. That is, symbols[i][j] says what symbol j should change to when in position i.

equivalent(code1,code2)

Can code2 be obtained from code1 by a combination of positional and symbolic permutations?

find_equivalence(code1,code2)

If code1 is equivalent to code2, find a combination of positional and symbolic permutations that maps code1 to code2.

Returns a dictionary with keys "positional_permutation" and "symbolic_permutation" when the codes are equivalent, and nothing if they're not.

find_positional_equivalence(code1,code2).

If code1 is positionally equivalent to code2, find a positional permutation that maps code1 to code2.

Returns a list representing a permutation of codeword digits when the codes are positionally equivalent, and nothing if they're not.

find_symbolic_equivalence(code1,code2).

If code1 is symbolically equivalent to code2, find a symbolic permutation that maps code1 to code2.

Returns a list representing a permutation of the symbols for each codeword digits when the codes are symbolically equivalent, and nothing if they're not.

distance_equivalent(code1,code2)

Is there an isomorphism between the Hamming distance tables of code1 and code2?

Returns true if there is a permutation of the rows and columns of the Hamming distance table of code1 that produces the table for code2.

hamming_bound(field_size,word_length,errors_corrected)

Hamming bound on the maximum number of codewords in a code with the given parameters.

singleton_bound(field_size,word_length,minimum_distance)

Singleton bound on the maximum number of codewords in a code with the given parameters.

gilbert_varshamov_bound(field_size,word_length,minimum_distance)

Gilbert-Varshamov bound on the minimum number of codewords in a code with the given parameters.

JavaScript functions

Everything lives under Numbas.extensions.codewords, which I'll omit from now on.

Codeword(digits,field_size)

Create a codeword with the given digits, belonging to the field Z_{field_size}.

Codeword methods

word.toString()

String representation of the word.

word.toLaTeX()

LaTeX representation of the word.

word.toJME()

JME representation of the word.

word.isZero()

Is the word zero (are all its digits 0)?

word.eq(word2)

Is this word the same as word2?

word.add(word2)

Return a new word which is the sum of this word and word2.

word.sub(word2)

Subtract word2 from this word (returns a new codeword object).

word.negate()

Negate this word: w.add(w.negate()) = 0.

word.scale(n)

Scale this word by n - multiply every digit by n.

word.weight()

Hamming weight of this word - number of non-zero digits.

word.LaTeX_check_array()

LaTeX rendering of a Hamming square code check array for this word (only makes sense if this word is a 9-digit binary word)

word.hamming_ball(radius)

Find all words within radius Hamming distance of this word.

word.hamming_sphere(radius)

Find all words with Hamming distance exactly radius from this word.

Static methods of the Codeword class

fromString(str,field_size)

Create a codeword object from a string representation, e.g. Codeword.fromString("01001",2).

sort(w1,w2)

Comparison function to sort codewords lexicographically.

eq(w1,w2)

Equivalent to w1.eq(w2).

zero_word(word_length,field_size)

Create a zero word with the given length in the field Z_{field_size}.

allwords(word_length,field_size)

Get all words of the given length in the field Z_{field_size}.

random_word(word_length,field_size)

Get a random word of the given length in the field Z_{field_size}.

random_combination(basis)

A random linear combination of the given words (from the field Z_p), i.e. a_0*w_0 + a_1*w_1 + ... + a_n*w_n where the a_i are elements of the field Z_p.

set_generated_by(words)

Get all words generated by the given basis set.

is_generated_by(basis,words)

Can all of the given words be written as a linear combination of the words in basis?

linearly_independent(words)

Are all of the given words linearly independent of each other?

Words are linearly independent if l1*w1 + l2*w2 + .. +ln*wn = 0 has no solution other than l1=l2=...=ln=0.

coset_containing(word,basis)

Generate the coset containing the given word, with respect to the given generating set.

slepian_array(basis)

Generate the Slepian array corresponding to the given basis set. Each row in the result is a coset, sorted by weight.

is_coset_leader(word,basis)

Is the given word a coset leader in its coset? That is, does it have the minimum weight?

hamming_distance(word1,word2)

Hamming distance between two words.

reduced_row_echelon_form(basis)

Put the given list of words (interpreted as a matrix) into reduced row-echelon form by reordering and taking linear combinations.

generator_matrix(words)

A minimal set of generators for the linear code generated by the given words. If the words are linearly independent, you'll get the same number of words back, otherwise you'll get fewer.

parity_check_matrix(basis)

A parity check matrix for the given generating set (which should be linearly independent)

lexicographic_parity_check_matrix(basis)

A parity check matrix for the given generating set, with columns in lexicographic order.

hamming_square_encode(word)

Encode word using Hamming's square code.

hamming_square_decode(word)

Decode (and correct up to one error in) word using Hamming's square code.

hamming_encode(word)

Encode word using the general Hamming code.

hamming_decode(word)

Decode (and correct up to one error in) word using the general Hamming code.

syndrome(word,pcm)

Compute the syndrome of the given word with respect to the given parity check matrix.

hamming_parity_check_matrix(p,r)

Create a parity check matrix for the Hamming code Ham_p(r). (p must be prime)

hamming_generating_matrix(p,r)

Create a generating matrix for the Hamming code Ham_p(r). (p must be prime)

Ham_p(r) is the p-ary Hamming code whose PCM has r rows

Code(words)

A wrapper object for the code containing the given words.

Code methods

code.toString()

String representation of the code - list all its words.

code.toLaTeX()

LaTeX representation of the code.

code.toJME()

JME representation of the code.

code.eq(code2)

Is this code the same as code2? True if they have exactly the same words.

code.contains(word)

Does this code contain word?

code.find_equivalence(code2)

If this code is equivalent to code2, return an object {positional_permutation, symbolic_permutation}. If not, return null.

Two codes are equivalent if we can get from one to the other by a combination of positional and symbolic permutations.

code.equivalent(code2)

Is this code equivalent to code2 - can you get from one to the other by performing positional and symbolic permutations on the digits of the codewords?

code.minimum_distance()

The minimum Hamming distance between any pair of words in this code.

code.information_rate()

Information rate of the code: log(number of words)/(log(2)*word length)

code.positional_permutation(order)

Perform a positional permutation on the words in the code. order is a list, where column i is sent to order[i]. Returns a new Code object.

code.symbolic permutation(symbols)

Perform a symbolic permutation on the words in the code. symbols is a list of permutations for each digit, where symbol j in position i is changed to symbols[i][j]. Returns a new Code object.

hamming_bound(field_size,word_length,errors_corrected)

Hamming bound on the maximum number of codewords in a code with the given parameters.

singleton_bound(field_size,word_length,minimum_distance)

Singleton bound on the maximum number of codewords in a code with the given parameters.

gilbert_varshamov_bound(field_size,word_length,minimum_distance)

Gilbert-Varshamov bound on the minimum number of codewords in a code with the given parameters.

Marking functions

mark_codeword_set(part,field_size,fn)

To be used on a "match text pattern" part, where the student's answer is a list of codewords separated by commas.

Checks that the student's answer is valid, and parses it to a list of Codeword objects in the given field, then calls fn(words). In fn, this refers to the given part object.

validate_codeword_set(part)

Validate a part marked by the above function. Shows a warning message if the student's answer can't be interpreted as a list of codewords separated by commas.

]]>
Download scores report for Moodle SCORM https://somethingorotherwhatever.com/items/download-scores-report-for-moodle-scorm 2014-10-16T13:24:12Z This report provides buttons to download a spreadsheet of scores for a SCORM package. It differs from the basic report by giving the total score in raw marks and percentage, as well as scores for each SCORM objective (called "question").

]]>
Download scores report for Moodle SCORM

This report provides buttons to download a spreadsheet of scores for a SCORM package. It differs from the basic report by giving the total score in raw marks and percentage, as well as scores for each SCORM objective (called "question").

It's designed for Numbas tests, so it assumes there's only one SCO and that objectives map to questions.

Installation

Clone this repository into mod/scorm/report/download_scores, then go to Site administration → Notifications and click to install it.

]]>
Moodle availability_username plugin https://somethingorotherwhatever.com/items/moodle-availability-username-plugin 2014-10-14T13:09:54Z Moodle availability condition plugin. Allows you to restrict access to course sections or activities by username.

]]>
availability_username

Moodle availability condition plugin. Allows you to restrict access to course sections or activities by username.

Installation

Clone into availability/condition/username. Go to "Site administration -> Notifications" and click to install the plugin.

]]>
Permutation groups extension for Numbas https://somethingorotherwhatever.com/items/permutation-groups-extension-for-numbas 2014-09-04T13:55:23Z Permutation groups extension for Numbas

]]>
Permutation groups extension for Numbas

This extension adds a new data type to the Numbas JME system, representing elements of permutation groups (really, just S_infinity, but you can pretend you're working in an S_n).

Permutations are stored as bijections on the natural numbers.

The symbol for the identity permutation is e by default. You can change this by setting Numbas.extensions.permutations.identity_symbol in the question preamble.

JME data type

This extension adds a new JME data type, Numbas.jme.types.permutation, representing a permutation.

JME Functions

permutation(map) or perm(map)

Create a permutation. map is a list of numbers. map[i] is the image of i under the permutation.

Note: Because lists are zero-indexed, the first element is 0, not 1.

Example: permutation([1,0]) is the permutation swapping the first two elements and will be displayed in cycle notation as (1,2).

permutation(str) or perm(str)

Create a permutation. str is a permutation in disjoint cycle notation.

Example: permutation("(1,2)(3,4,5)")

transposition(a,b)

A permutation representing the transposition of the elements a and b.

rotation(n,r)

Create a permutation representing a rotation of the numbers 1 to n by r places. If r is not given it defaults to 1.

flip(n)

Create a permutation representing a reflection of the numbers 1 to n.

compose(p1,p2) or p1*p2

Compose permutations. The action is on the left - (p1*p2)[x] = p1[p2[x]].

p^n

The nth power of p. p^0 is the identity permutation.

p[x]

Apply permutation p to the number x. Consider p as an element of S_n; any x greater than or equal to n is mapped to itself.

inverse(p)

Returns the inverse of permutation p.

even(p)

Is p an even permutation (can it be written as a product of an even number of transpositions?)

size(p)

The largest number n that is permuted by p, or equivalently, the smallest n such that p is a member of S_n.

order(p)

The order of p: the smallest power of p equivalent to the identity permutation.

cycles(p)

Calculate all of p's cycles. Returns a list of lists of numbers.

nontrivial_cycles(p)

Calculate all of p's cycles of length greater than 1.

show(p)

Render p as a TeX string (just substituting p into a TeX expression will also work, but you can use this if you want to manipulate the TeX string somehow)

twoline(p)

Render p in two-line form (numbers 1..n on top row, their images on the bottom) as a TeX string

as_transpositions(p)

Render p as a product of transpositions, in TeX.

p1=p2

Are p1 and p2 the same permutation? True if p1*inverse(p2) maps n to n for all n.

is_disjoint(str)

Returns true if str is a representation of a permutation as disjoint cycles (no two cycles have an element in common).

is_transpositions(str)

Returns true if str is a representation of a permutation as transpositions (each cycle has length 2).

is_rotation(p)

Returns true if p is a rotation, i.e. a permutation of the form f: i -> (i+x) mod N, for some 0< x < N.

is_flip(p)

Returns true if p is a flipped rotation, i.e. a permutation of the form f: i -> (x-i) mod N, for some 0

]]>
swirlograph https://somethingorotherwhatever.com/items/swirlograph 2014-08-27T23:00:00Z Looks like some wiggly worms swirling round a vector field. Made with p5.js.

]]>

Looks like some wiggly worms swirling round a vector field. Made with p5.js.

]]>
Content MathML to Presentation MathML for MathJax https://somethingorotherwhatever.com/items/content-mathml-to-presentation-mathml-for-mathjax 2014-04-04T14:21:24Z A JavaScript implementation of David Carlisle's tool to convert Content MathML to Presentation MathML. I made this as contract work for MathJax.

]]>
ctop

A JavaScript implementation of David Carlisle's Content-to-PresentationMathML xsl

]]>
MathJax in Twine https://somethingorotherwhatever.com/items/mathjax-in-twine 2014-03-29T17:14:51Z A couple of macros which let you use MathJax to render LaTeX in Twine stories

]]>
Twine MathJax macros

A couple of macros that let you use MathJax to render LaTeX in a Twine story.

To use

In your StoryIncludes passage, add the line

mathjax.twee

and either make sure that that file is in the same directory as your story file, or use its full path.

For inline maths, use <<math>>.

For display maths, use <<dmath>>.

Example

<<math e^{i \pi} + 1 = 0 >>

There's an example story in mathjax-demo.tws. You can play it at christianp.github.io/mathjax-twine.

Licence

Public domain or Apache 2.0. I don't care how you use this!

]]>
Regex fractals https://somethingorotherwhatever.com/items/regex-fractals 2014-03-26T20:37:06Z Draw fractals by writing a regular expression which matches parts of a subdivided square.

]]>

Split the space into quadrants. Name them 1,2,3 and 4. Split those quadrants up, and add another digit to the names. Repeat a few times!

Now each cell has a several-digit name. Turn a cell on or off depending on whether its name passes a regular expression. Use the length of the expression's matching groups to colour on cells.

Inspired by SSOΔ.

]]>
Everyone’s a mathematician https://somethingorotherwhatever.com/items/everyones-a-mathematician 2014-03-25T10:57:12Z This morning Katie and I had a little discussion about house style on The Aperiodical. Mathematican Paul Taylor was listed as “Mathematician Paul Taylor” in the blurb for his featured p…

]]>

This morning Katie and I had a little discussion about house style on The Aperiodical. Mathematican Paul Taylor was listed as “Mathematician Paul Taylor” in the blurb for his featured p…

]]>
Building Houses https://somethingorotherwhatever.com/items/building-houses 2014-03-20T15:28:16Z A game about putting flags in a field, made for James Grime

]]>

The Lazy Farmer Flag Game

Made for James Grime - see the video at YouTube.

The aim is to place flags on a field of length 1, so that when you divide the field into equal-sized plots, there's exactly one flag in each field. To complicate matters, you place the flags one-by-one, and you check whether the placements are valid after each flag goes down.

made by cp. Released under the MIT licence.

This uses d3, jQuery, normalize.css, and a picture of a house from Emoji One, which all have their own licences.

]]>
cp's OEIS frontend https://somethingorotherwhatever.com/items/cp-s-oeis-frontend 2014-01-28T16:21:27Z An alternative frontend for the Online Encyclopedia of Integer Sequences.

]]>

This is a Flask app which serves a new frontend to the OEIS.

The aim is to produce pages with non-ancient HTML, and then to pay attention to visual presentation.

The OEIS server happily returns text files for its entries, but I don't know how happy they'd be about getting lots of traffic that way, so this is just a hobby project for me for now.

]]>
Big Friendly BF https://somethingorotherwhatever.com/items/big-friendly-bf 2014-01-10T22:12:26Z An implementation of the programming language I can't name

]]>

BFBF

An obnoxiously large implementation of the programming language I can't name.

]]>
Plot differential equations https://somethingorotherwhatever.com/items/plot-differential-equations 2013-11-26T15:25:30Z A little tool to visualise solutions to first order ODEs

]]>
ode-solution-plot

A little tool to visualise solutions to first order ODEs.

It uses

  • LissaJS to parse a mathematical expression and rewrite it as javascript
  • JSXGraph to render a diagram of the resulting vector field and solution.

See it running at http://www.staff.ncl.ac.uk/christian.perfect/ode-solution-plot/

]]>
LissaJS https://somethingorotherwhatever.com/items/lissajs 2013-10-29T14:37:13Z An algebra parsing, evaluation and simplification system written entirely in JavaScript.

]]>
LissaJS

A library for parsing, evaluating and rearranging algebraic expressions in JavaScript.

This project is no longer maintained. Development continues in https://github.com/numbas/Numbas.

The name "LissaJS" was picked without much thought. It's meant to pun on "Lissajous", and follows the convention that every Javascript library's name ends in "JS", but apart from that it hasn't got much going for it. Suggestions of better names are welcome at issue #1.

This is a spin-off of the Numbas e-assessment system. It has no external dependencies.

It's currently provided on a "do what you can with it" basis; we'll add examples and documentation later.

Demo

There's an interactive demo page at http://numbas.github.io/LissaJS/.

Installing LissaJS

Include the lissajs.js script in your page.

<script src="proxy.php?url=https%3A%2F%2Fsomethingorotherwhatever.com%2Flissajs.js"></script>

It uses some ECMAScript 5 features. For older browsers, you'll also need to load es5-shim.

Using LissaJS

There is an explanation of the syntax, data types supported, and a function reference at http://numbas-editor.readthedocs.org/en/latest/jme-reference.html. Just replace Numbas with LissaJS. For more in-depth code documentation, see http://numbas.github.io/Numbas/ - again replacing Numbas with LissaJS.

All operations happen with respect to a LissaJS.jme.Scope object. There's a default scope at LissaJS.jme.builtinScope containing all the built-in functions and rulesets. A few of the most commonly-used functions are available through the LissaJS object, using this default scope implicitly, for your convenience.

To evaluate an expression:

LissaJS.evaluate('expression',{dict of variables});

or, with a custom scope:

scope.evaluate('expression',{dict of variables});

To compile an expression to a syntax tree:

scope.compile('expression');

To convert an expression to LaTeX:

LissaJS.exprToLaTeX('expression',[rules]);

or, with a custom scope:

LissaJS.jme.display.exprToLaTeX('expression',[rules],scope);

To simplify (rearrange) an expression:

LissaJS.simplifyExpression('expression',[rules]);

or, with a custom scope:

LissaJS.jme.display.simplifyExpression('expression',[rules],[scope]);

There are lots of pure maths functions under LissaJS.math.

Copyright

LissaJS uses code from the Numbas project.

Copyright 2011-16 Newcastle University

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

You can see a plain-English explanation of the license and what it allows at tl;drLegal

]]>
MathJax play area https://somethingorotherwhatever.com/items/mathjax-play-area 2013-10-25T10:54:30Z A page to try out different MathJax configurations.

]]>

A page to try out different MathJax configurations.

]]>
MathJax bindings for knockout.js https://somethingorotherwhatever.com/items/mathjax-bindings-for-knockout-js 2013-10-22T08:24:17Z Binding handlers for knockout.js which typeset all LaTeX inside an element containing HTML, or just typeset some LaTeX on its own.

]]>
======= knockout-mathjax-bindings =========================

Binding handlers for knockout.js which typeset all LaTeX inside an element containing HTML, or just typeset some LaTeX on its own.

Demo at http://checkmyworking.com/misc/knockout-mathjax-bindings/

]]>
An enneahedron for Herschel https://somethingorotherwhatever.com/items/an-enneahedron-for-herschel 2013-10-01T09:16:39Z The Herschel graph has some pretty cool properties. Christian Perfect constructed the associated polyhedron, and it too has some cool properties!

]]>

The Herschel graph has some pretty cool properties. Christian Perfect constructed the associated polyhedron, and it too has some cool properties!

]]>
Little Professor https://somethingorotherwhatever.com/items/little-professor 2013-06-15T23:00:00Z Read out an integer sequence, like the Little Professor calculator used to read out sums.

]]>
Read out an integer sequence, like the Little Professor calculator used to read out sums.

]]>
Integer Sequence Reviews https://somethingorotherwhatever.com/items/integer-sequence-reviews 2013-05-03T23:00:00Z My friend David Cushing and I used to review integer sequences for fun.

]]>

My friend David Cushing and I used to review integer sequences for fun.

]]>
Art for a maths department https://somethingorotherwhatever.com/items/art-for-a-maths-department 2013-04-29T11:18:27Z Christian was asked to find some art to decorate the walls of the university maths department he works in. Here’s what he found.

]]>

Christian was asked to find some art to decorate the walls of the university maths department he works in. Here’s what he found.

]]>
Code excursions https://somethingorotherwhatever.com/items/code-excursions 2013-04-13T13:36:05Z The little bits of code I write to explore ideas.

]]>
Every now and then an idea occurs to me or I see a puzzle or something, and I write a little bit of code to explore it. I have code spread all over the place in flat files and github gists and so on, so I thought it would be a good idea to collect it all in one place. I also realised it would help me in the long run to write down what I'm doing, so I'm going to try to explain my thought process at the top of each project.

]]>
deck.js maths template https://somethingorotherwhatever.com/items/deck-js-maths-template 2013-02-09T14:10:42Z A template to create slides with deck.js, MathJax, and the unicode Computer Modern fonts

]]>
cp's deck.js maths template

A template to create slides with deck.js, MathJax, and the unicode Computer Modern fonts.

This contains everything you need to create a slideshow presentation which runs in the browser but uses the Beamer fonts and supports LaTeX maths.

deck.js is the best tool I've found to make HTML presentations.

I recompiled the cm-unicode project's Unicode version of the Computer Modern fonts (the default fonts used by LaTeX) so they could be used on the web. They can be downloaded from http://checkmyworking.com/cm-web-fonts/.

MathJax does the maths rendering.

You can see an example presentation at http://checkmyworking.com/misc/pgps-computable-groups-feb-2013/.

]]>
Computability of Bass-Serre structures in the Grzegorczyk hierarchy https://somethingorotherwhatever.com/items/computability-of-bass-serre-structures-in-the-grzegorczyk-hierarchy 2013-02-08T00:00:00Z A talk about the stuff I was looking at in my aborted PhD.

]]>

A talk about the stuff I was looking at in my aborted PhD.

]]>
MathJax bookmarklet https://somethingorotherwhatever.com/items/mathjax-bookmarklet 2013-01-01T00:00:00Z A bookmarklet to render LaTeX by adding MathJax to pages that don't have it.

]]>
A bookmarklet to render LaTeX by adding MathJax to pages that don't have it.

]]>
Spiral Life https://somethingorotherwhatever.com/items/spiral-life 2012-11-01T22:19:49Z Conway's Game of Life, but it doesn't all happen at once

]]>

Conway's Game of Life, but it doesn't all happen at once

]]>
Zero-knowledge protocols https://somethingorotherwhatever.com/items/zero-knowledge-protocols 2012-10-23T23:00:00Z A talk about zero-knowledge protocols, given at Newcastle's postgraduate forum.

]]>

A talk about zero-knowledge protocols, given at Newcastle's postgraduate forum.

]]>
Using Computer Modern on the web https://somethingorotherwhatever.com/items/using-computer-modern-on-the-web 2012-08-28T23:00:00Z I compiled the Computer Modern fonts into a format that can be used on the web.

]]>

I compiled the Computer Modern fonts into a format that can be used on the web.

]]>
Olympic chokers https://somethingorotherwhatever.com/items/olympic-chokers 2012-08-09T23:00:00Z Which countries are just failing to win the most? Shows a table of all countries who have won at least one gold (to exclude the milquetoast nations for whom second place is an achievement), sorted by the proportion of their medals which are not gold.

]]>
Which countries are just failing to win the most? Shows a table of all countries who have won at least one gold (to exclude the milquetoast nations for whom second place is an achievement), sorted by the proportion of their medals which are not gold.

]]>
make big maths https://somethingorotherwhatever.com/items/make-big-maths 2012-08-08T06:49:27Z A simple page for rendering LaTeX at any size, using MathJax.

]]>

A simple page for rendering LaTeX at any size, using MathJax.

Copyright (c) 2012 Christian Perfect

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.

]]>
WordPress writemaths plugin https://somethingorotherwhatever.com/items/wordpress-writemaths-plugin 2012-06-20T10:54:23Z A WordPress plugin to add the Write maths, see maths thing to the editor. Doesn't work with the block editor.

]]>
A wordpress plugin for jQuery.writemaths

Adds write maths, see maths to comment boxes, and to TinyMCE editor instances (in particular, the post editor).

Requires MathJax to be available to wp_enqueue_script under the name 'mathjax'. The Simple MathJax plugin does this.

Licence

Copyright 2014 Christian Perfect

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

(tl;dr)

]]>
logerrific https://somethingorotherwhatever.com/items/logerrific 2012-05-01T22:27:23Z A javascript server log analyser

]]>
I'm trying to make a modern-looking server log analyser, because it seems none exists.

]]>
The Aperiodical https://somethingorotherwhatever.com/items/the-aperiodical 2012-04-24T23:00:00Z The blog I run with Peter Rowlett and Katie Steckles.

]]>

The blog I run with Peter Rowlett and Katie Steckles.

]]>
Putting maths notation online https://somethingorotherwhatever.com/items/putting-maths-notation-online 2012-03-31T23:00:00Z A talk about how to use MathJax, from when it was new.

]]>

A talk about how to use MathJax, from when it was new.

]]>
An interesting puzzle from MathsJam https://somethingorotherwhatever.com/items/an-interesting-puzzle-from-mathsjam 2012-03-27T23:00:00Z About the 'Princess in a castle' puzzle.

]]>

About the 'Princess in a castle' puzzle.

]]>
Princess in a castle https://somethingorotherwhatever.com/items/princess-in-a-castle 2011-12-07T01:20:12Z An interactive version of the Princess in a Castle puzzle

]]>

Princess in a Castle puzzle!

see http://checkmyworking.com/misc/princess-castle

uses Paper.js.

]]>
Random Eratosthenetic Pseudo-Primes https://somethingorotherwhatever.com/items/random-eratosthenetic-pseudo-primes 2011-10-27T23:00:00Z An investigation of what happens if you make the Sieve of Eratosthenes randomly.

]]>

An investigation of what happens if you make the Sieve of Eratosthenes randomly.

]]>
Aperiodical Round Up https://somethingorotherwhatever.com/items/aperiodical-round-up 2011-10-19T23:00:00Z This is a sporadic series of posts where I collect links to interesting or unusual maths things.

]]>

This is a sporadic series of posts where I collect links to interesting or unusual maths things.

]]>
Hands-on Maths, or Here's One I Proved Earlier https://somethingorotherwhatever.com/items/hands-on-maths-or-here-s-one-i-proved-earlier 2011-10-18T23:00:00Z A talk about some physical mathematical objects, given at Newcastle's postgraduate forum.

]]>

A talk about some physical mathematical objects, given at Newcastle's postgraduate forum.

]]>
Tic-Tac-Reversi https://somethingorotherwhatever.com/items/tic-tac-reversi 2011-09-26T23:00:00Z A cross between tic-tac-toe and Reversi, apparently.

]]>

A cross between tic-tac-toe and Reversi, apparently.

]]>
Kleinsteroids! https://somethingorotherwhatever.com/items/kleinsteroids 2011-09-10T23:00:00Z Asteroids, played on the projective plane or the Klein bottle.

]]>

Asteroids, played on the projective plane or the Klein bottle.

]]>
Codes and Ciphers https://somethingorotherwhatever.com/items/codes-and-ciphers 2011-08-22T21:45:46Z I wanted to make interactive demonstrations of some codes and ciphers. I only got as far as doing the Caesar Cipher.

]]>

I wanted to make interactive demonstrations of some codes and ciphers. I only got as far as doing the Caesar Cipher.

]]>
When's your next prime birthday? https://somethingorotherwhatever.com/items/when-s-your-next-prime-birthday 2011-08-08T16:46:08Z Tells you when you are next a prime number of days old.

]]>

This is a simple script which asks for your date of birth and then calculates when your next prime birthday is.

A prime birthday is when you are a prime number of days old!

]]>
textile in javascript https://somethingorotherwhatever.com/items/textile-in-javascript 2011-07-19T20:09:40Z A Textile convertor in Javascript, because no good one already existed.

]]>
A better javascript textile converter, because I couldn't find one.

]]>
textile https://somethingorotherwhatever.com/items/textile 2011-06-25T23:00:00Z A demo page for my JavaScript implementation of the Textile markup language.

]]>
A demo page for my JavaScript implementation of the Textile markup language.

]]>
Monkey bits https://somethingorotherwhatever.com/items/monkey-bits 2011-06-20T08:06:18Z Code written in the Monkey language.

]]>

This repository contains things I have written using Monkey.

Some of the things may not work, some may work but have no purpose, and others may work and be useful but no fun at all.

]]>
Write maths, see maths https://somethingorotherwhatever.com/items/write-maths-see-maths 2011-06-01T09:01:18Z A jQuery plugin to give an instant preview of LaTeX in editing areas.

]]>
Write maths, see maths is a jQuery plugin for editable areas which gives an instant MathJax preview of the TeX you're writing just above the cursor.

To use it, just call $(selector).writemaths()$ when the page loads.

You can optionally pass in an object with some options:

  • cleanMaths: a function which does something to the LaTeX before displaying it.
  • callback: a function which is called when the preview is displayed.
  • iFrame: set this to true if you're applying writemaths to something like TinyMCE, which lives inside an iframe.
  • position: the position on the parent element on which to place the preview. It's really the `at option of jquery.ui.position.
  • previewPosition: the position on the preview element to line up with the parent element. It's really the my option of jquery.ui.position.
  • of: the element to position relative to.
]]>
PHD-Notes https://somethingorotherwhatever.com/items/phd-notes 2011-05-09T09:51:04Z Stuff produced during the PhD I gave up on. I was supposed to be looking at computability of products of groups.

]]>
I've put my TeX files up here because I've been editing them on several different PCs lately.

I usually write up my thoughts informally on my blog before I TeX them up.

]]>
Numbas https://somethingorotherwhatever.com/items/numbas 2011-04-25T08:08:44Z Numbas is an open-source e-assessment tool aimed at mathematical disciplines. It's what I spend most of my work time on.

]]>

Numbas logo

Numbas is an open-source system for creating tests which run entirely in the browser. It has been developed by Newcastle University's School of Mathematics, Statistics and Physics.

For more information about Numbas and what it does, see our website at numbas.org.uk.

How to use Numbas

Documentation for Numbas users is at numbas-editor.readthedocs.org.

Installation

This repository contains the Numbas compiler, which runs as standalone Python 3, but the most convenient way to use Numbas is through the web-based editor.

A publicly-available editor, requiring no set-up, is available at numbas.mathcentre.ac.uk. Or, you can follow our instructions for Windows, Mac, or Ubuntu to install your own instance.

If you decide to run your own installation, install the compiler's dependencies with pip install -r requirements.txt.

This repository is just one part of the Numbas ecosystem. See the numbas organisation for the other pieces, including the web-based editor, extensions, and VLE integrations.

Contributing to Numbas

Numbas is open source, and we welcome contributions of any sort. Bug reports or feature suggestions can be added to the GitHub issue tracker, or emailed to [email protected].

See our page on contributing to Numbas for more information on how you can help.

We keep a list of tasks specifically for new contributors, under the good-first-issue label. There's a corresponding list in the editor repository, too. These tasks should be fairly straightforward to implement without much knowledge of how all the code fits together.

Development

This tool runs on the command line: run python bin/numbas.py to see the options. You can give it the name of a .exam file or pipe one in.

When making changes to the JavaScript runtime, it's a good idea to run the unit tests in the tests directory. Start a local web server with python -m http.server and go to http://localhost:8000/tests. The file jme.html contains tests to do with the JME system, and parts.html contains tests to do with the part marking algorithms.

If you make a change, please try to add unit tests to confirm that Numbas behaves as expected.

The Makefile in this repository collects together scripts to run the unit tests, and builds the API documentation. Linux and Mac OS have built-in support Makefiles, but Windows doesn't. On Windows, cygwin provides make.

API documentation for developers is at numbas.github.io/Numbas. This is generated using JSDoc, with a custom template. Run make docs to rebuild the API documentation into ../numbas-docs.

Copyright

Copyright 2011-18 Newcastle University

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

You can see a plain-English explanation of the license and what it allows at tl;drLegal

Copyright in the content produced using Numbas resides with the author.

]]>
Circles https://somethingorotherwhatever.com/items/circles 2011-03-09T00:00:00Z Subdividing a triangle into circles.

]]>

Subdividing a triangle into circles.

]]>
I can't believe it's a universal computer! https://somethingorotherwhatever.com/items/i-can-t-believe-it-s-a-universal-computer 2011-02-09T00:00:00Z A talk about Turing completeness, given at Newcastle's postgraduate forum.

]]>

A talk about Turing completeness, given at Newcastle's postgraduate forum.

]]>
Check my working https://somethingorotherwhatever.com/items/check-my-working 2010-02-02T00:00:00Z checkmyworking.com began as place to put notes about my PhD work, before I abandoned it. I also used to post about maths things, before I started The Aperiodical. Now (in 2022), my plan is to use this site to post bits and bobs about the techy things I'm doing, for the sake of anyone else who might encounter the same problems I do.

]]>

checkmyworking.com began as place to put notes about my PhD work, before I abandoned it. I also used to post about maths things, before I started The Aperiodical. Now (in 2022), my plan is to use this site to post bits and bobs about the techy things I'm doing, for the sake of anyone else who might encounter the same problems I do.

]]>
Picaresque https://somethingorotherwhatever.com/items/picaresque 2009-02-02T15:03:32Z I'd just read Candide, I was full of big ideas, I thought I'd make a game about all of that. I didn't get far.

]]>
03/02/09: Added old fencing and trader games source to 'inspiration' folder.

02/02/09: Actually run for the actual hills, it's the first commit!

]]>
Cards https://somethingorotherwhatever.com/items/cards 2008-12-31T00:00:00Z Some greetings cards I made.

]]>

Some greetings cards I made.

]]>
warpycode https://somethingorotherwhatever.com/items/warpycode 2008-10-25T12:15:03Z This is an up-to-date repository of all my blitzmax code. It's mainly for my use, but others might find something useful in it.

]]>
This is an up-to-date repository of all my blitzmax code. It's mainly for my use, but others might find something useful in it.

]]>
The unfortunate man https://somethingorotherwhatever.com/items/the-unfortunate-man 2008-01-02T00:00:00Z A nonsense story

]]>

A nonsense story

]]>
The Failure Song https://somethingorotherwhatever.com/items/the-failure-song 2008-01-01T00:00:00Z Some rubbish about exams?

]]>

Some rubbish about exams?

]]>
Christian does some stuff https://somethingorotherwhatever.com/items/christian-does-some-stuff 2007-05-31T23:00:00Z A series of cartoons

]]>

A series of cartoons

]]>