{"id":13609528,"url":"https://github.com/susam/mathb","last_synced_at":"2025-05-14T23:15:49.690Z","repository":{"id":11959779,"uuid":"14531574","full_name":"susam/mathb","owner":"susam","description":"Mathematics pastebin software that powered MathB.in from 2012 to 2025","archived":false,"fork":false,"pushed_at":"2025-03-16T01:01:20.000Z","size":226,"stargazers_count":366,"open_issues_count":0,"forks_count":26,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-04-12T20:36:51.164Z","etag":null,"topics":["commonlisp","javascript","latex","lisp","markdown","mathematics","mathjax","pastebin","texme"],"latest_commit_sha":null,"homepage":"","language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/susam.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-11-19T17:13:09.000Z","updated_at":"2025-04-05T13:46:25.000Z","dependencies_parsed_at":"2024-01-12T10:25:45.291Z","dependency_job_id":"708dd66d-0aa5-4165-bb56-ced85b8a3312","html_url":"https://github.com/susam/mathb","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/susam%2Fmathb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/susam%2Fmathb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/susam%2Fmathb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/susam%2Fmathb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/susam","download_url":"https://codeload.github.com/susam/mathb/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254243314,"owners_count":22038048,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["commonlisp","javascript","latex","lisp","markdown","mathematics","mathjax","pastebin","texme"],"created_at":"2024-08-01T19:01:35.623Z","updated_at":"2025-05-14T23:15:49.653Z","avatar_url":"https://github.com/susam.png","language":"Common Lisp","readme":"MathB\n=====\n\nMathB is a mathematics pastebin software that powered `MathB.in` from\n2012 to 2025.  It is a web-based service meant for sharing snippets of\nmathematical text with others on the world wide web.\n\n\nContents\n--------\n\n* [Features](#features)\n* [Quick Start](#quick-start)\n* [Custom Directory Paths](#custom-directory-paths)\n* [Data Files](#data-files)\n* [Runtime Options](#runtime-options)\n* [Templates Files](#template-files)\n* [Static Files](#static-files)\n* [Live Directory](#live-directory)\n* [Print](#print)\n* [Save PDF](#save-pdf)\n* [History](#history)\n* [License](#license)\n* [Support](#support)\n* [Channels](#channels)\n* [More](#more)\n\n\nFeatures\n--------\n\n- Minimalist user interface that has not changed much over a decade.\n- Live preview of Markdown and LaTeX content as it is typed.\n- Support for mixing Markdown and LaTeX code freely.\n- Printing a post to PDF or paper prints only the rendered content.\n- All UI elements apart from rendered content are excluded from\n  prints.\n- No web cookies.\n- No web analytics.\n\n\nQuick Start\n-----------\n\nThis section explains how to run this project locally.  The steps\nassume a macOS, Debian, or Debian-based Linux distribution.  However,\nit should be possible to adapt these steps for another operating\nsystem.\n\n 1. Install SBCL and Git.\n\n    On macOS, enter the following command if you have Homebrew:\n\n    ```sh\n    brew install sbcl git\n    ```\n\n    On Debian, Ubuntu, or another Debian-based Linux system, enter the\n    following command:\n\n    ```sh\n    sudo apt-get update\n    sudo apt-get install sbcl git\n    ```\n\n 2. Install Quicklisp with the following commands:\n\n    ```sh\n    curl -O https://beta.quicklisp.org/quicklisp.lisp\n    sbcl --load quicklisp.lisp --eval \"(quicklisp-quickstart:install)\" --quit\n    sbcl --load ~/quicklisp/setup.lisp --eval \"(ql:add-to-init-file)\" --quit\n    ```\n\n 3. From here on, we assume that all commands are being run in the\n    top-level directory of this project.  Set up dependencies\n    necessary to run this project by running this command within the\n    top-level directory of this project:\n\n    ```sh\n    make live\n    ```\n\n    This creates a `_live` directory within the current directory and\n    copies all necessary dependencies to it.\n\n 4. Create data and log directories:\n\n    ```sh\n    sudo mkdir -p /opt/data/mathb/ /opt/log/mathb/\n    sudo cp -R meta/data/* /opt/data/mathb/\n    sudo chown -R \"$USER\" /opt/data/mathb/ /opt/log/mathb/\n    ```\n\n    By default, MathB reads post data from and writes posts to\n    `/opt/data/mathb/`.  It writes logs to `/opt/log/mathb/` by\n    default.  The next section explains how to make it use custom\n    directory paths.\n\n 4. Run MathB with the following command:\n\n    ```sh\n    sbcl --load mathb.lisp\n    ```\n\n 5. Visit http://localhost:4242/ with a web browser to use MathB.\n\nAfter starting MathB in this manner, click on the various navigation\nlinks and make a new post to confirm that MathB is working as\nexpected.\n\n\nCustom Directory Paths\n----------------------\n\nIn the previous section, we created a data directory at\n`/opt/data/mathb/` and a log directory at `/opt/log/mathb/`.  By\ndefault, MathB writes new posts to and reads posts from this directory\npath.  To make it use a different path for the data directory, set the\nvariable named `*data-directory*` before loading it.  Similarly, set\nthe variable named `*log-directory*` to specify a different path for\nthe log directory.  The following steps demonstrate how to do this:\n\n 1. Create data directory at a custom path, say, at `~/data`:\n\n    ```sh\n    mkdir -p ~/data/ ~/log/\n    cp -R meta/data/* ~/data/\n    ```\n\n 2. Run MathB with the following command:\n\n    ```sh\n    sbcl --eval '(defvar *data-directory* \"~/data/\")' \\\n         --eval '(defvar *log-directory* \"~/log/\")' \\\n         --load mathb.lisp\n    ```\n\n 3. Visit http://localhost:4242/ with a web browser to use MathB.\n\nAfter starting MathB in this manner, click on the various navigation\nlinks and make a new post to confirm that MathB is working as\nexpected.\n\n\nData Files\n----------\n\nThe data directory contains the following files:\n\n - [`opt.lisp`]: This file contains a property list that can be\n   modified to alter the behaviour of MathB.  This is explained in\n   detail in the next section.\n\n - [`slug.txt`]: This file contains the ID of the latest post\n   successfully saved.\n\n - [`post/X/Y/*.txt`]: These files contain the actual posts submitted\n   by users where `X` and `Y` are placeholders for two integers\n   explained shortly.  Each `.txt` file contains a post submitted by a\n   user.\n\nIn the last point, the placeholder `X` is the post ID divided\nby 1000000.  The placeholder `Y` is the post ID divided by 1000.  For\nexample, for a post with ID 1, `X` is `0` and `Y` is `0`, so a post\nwith this ID is saved at `post/0/0/1.txt`.  For a more illustrative\nexample, consider a post with with ID 2301477.  Now `X` is `2` and `Y`\nis `2301`, so a post with this ID is saved at\n`post/2/2301/2301477.txt`.\n\nLet us call each `X` directory a short-prefix directory and each `Y`\ndirectory under it a long-prefix directory.  As a result of the\ncalculation explained above, each short-prefix directory contains a\nmaximum of 1000 long-prefix directories and each long-prefix directory\ncontains a maximum of 1000 post files.  Thus, each short-prefix\ndirectory contains a maximum of one million post files under it.\n\n[`opt.lisp`]: meta/data/opt.lisp\n[`slug.txt`]: meta/data/slug.txt\n[`post/X/Y/*.txt`]: meta/data/post/0/0\n\n\nRuntime Options\n---------------\n\nMathB reads runtime properties from `opt.lisp`.  This file contains a\nproperty list.  Each property in this list is followed by a value for\nthat property.  This property list may be used to alter the behaviour\nof MathB.  A list of all supported properties and their descriptions\nis provided below.\n\n  - `:lock-down` (default is `nil`): A value of `t` makes MathB run in\n    lock-down mode, i.e., existing posts cannot be viewed and new\n    posts cannot be submitted.\n\n  - `:read-only` (default is `nil`): A value of `t` makes MathB run in\n    read-only mode, i.e., old posts can be viewed but new posts cannot\n    be made.  If the values of both this property and the previous\n    property are `nil`, then MathB runs normally in read-write mode.\n\n  - `:min-title-length` (default is `0`): The minimum number of\n    characters allowed in the title field.\n\n  - `:max-title-length` (default is `120`): The maximum number of\n    characters allowed in the title field.\n\n  - `:min-name-length` (default is `0`): The minimum number of\n    characters allowed in the name field.\n\n  - `:max-name-length` (default is `120`): The maximum number of\n    characters allowed in the name field.\n\n  - `:min-code-length` (default is `1`): The minimum number of\n    characters allowed in the code field.\n\n  - `:max-code-length` (default is `10000`): The maximum number of\n    characters allowed in the code field.\n\n  - `:global-post-interval` (default is `0`): The minimum interval (in\n    seconds) required between two consecutive successful posts.\n\n    Example: If this value is `10` and one client submits a new post\n    at 10:00:00 and another client submits a post at 10:00:07, the\n    post of the second client is rejected with an error message that\n    they must wait for 3 more seconds before submitting the post.  An\n    attempt to submit the post at 10:00:10 or later would succeed,\n    provided that no other client submitted another post between\n    10:00:10 and the second client's attempt to make a post.\n\n  - `:client-post-interval` (default is `0`): The minimum interval (in\n    seconds) between two consecutive successful posts allowed from the\n    same client.\n\n    Example: If this value is `10` and one client submits a new post\n    at 10:00:00, then the same client is allowed to make the next\n    successful post submission at 10:00:10 or later.  If the same\n    client submits another post at 10:00:07, the post is rejected with\n    an error message that they must wait for 3 more seconds before\n    submitting the post.  This does not affect the posting behaviour\n    for other clients.  For example, another client can successfully\n    submit their post at 10:00:07 while the first client cannot.\n\n  - `:expect` (default is `nil`): A list of strings.  At least one\n    string from this list must occur in the submitted code field.\n\n    Example: If this value is `(\"\\(\" \"\\[\")` and the submitted post\n    contains `\\[ 1 + 1 = 2. \\]` in the code field, then the post is\n    accepted successfully.  However, if the submitted code contains\n    only `1 + 1 = 2`, then the post is rejected because neither the\n    string `\"\\(\"` nor the string `\"\\[\"` occurs in the code field of\n    this submission.\n\n  - `:block` (default is `nil`): A list of strings that are not\n    allowed in a post.  If a post contains any string in this list,\n    the post is rejected and the input form is returned intact to the\n    client.\n\n    Example: If this value is `(\"berk\" \"naff\" \"xxx\")` and a client\n    posts content which contains the string `xxx` in any field (code,\n    title, or name), the post is rejected.\n\n  - `:ban` (default is `nil`): A list of IPv4 or IPv6 address\n    prefixes.  If the address of the remote client (as it appears in\n    the logs) matches any prefix in this list, the post from the\n    client is rejected.  The prefixes must be expressed as simple\n    string literals.  CIDRs, globs, regular expressions, etc. are not\n    supported.  A dollar sign (`$`) at the end of a prefix string\n    matches the end of the client's address string.\n\n    Example: Let us consider a value of `(\"10.1.\" \"10.2.0.2\"\n    \"10.3.0.2$\")` for this property.  If a client from IP address\n    `10.1.2.3` submits a post, it is rejected because the prefix\n    `10.1.` matches this IP address.  If a client from IP address\n    `10.2.0.23` submits a post, it is rejected because the prefix\n    `10.2.0.2` matches this IP address.  If a client from IP address\n    `10.3.0.2` submits a post, it is rejected because the prefix\n    `10.3.0.2$` matches this IP address.  If a client from IP address\n    `10.3.0.23` submits a post, it is accepted because none of the\n    prefixes match this IP address.\n\n  - `:protect` (default is `0`): The maximum ID of protected posts.\n    If MathB determines that the post ID of the next post is less than\n    or equal to this value, then it rejects the post.  Setting this\n    property is almost never required.  However, it is provided for\n    paranoid administrators who might worry what would happen if the\n    data file `slug.txt` ever becomes corrupt.  This property ensures\n    that in case this data file ever becomes corrupt, MathB would\n    never ever overwrite old posts with IDs less than or equal to the\n    number set for this property.\n\n    Example: Let us assume that the current value in `slug.txt`\n    is 1200.  Now normally, the next time a client submits a new post,\n    their post would be saved with an ID of 1201 and the value in\n    `slug.txt` would be incremented to 1201.  But instead, let us\n    assume that due to an unforeseen scenario (say, a bug in MathB or\n    a hardware failure), the value in `slug.txt` is corrupted to `12`.\n    With a value of `0` for `:protect`, MathB would overwrite an\n    existing post at `post/0/0/13.txt`.  However, with a value of say,\n    `100` for `:protect`, MathB would refuse to overwrite the existing\n    port.\n\nIf a property name is missing from this file or if the file itself is\nmissing, then the default value of the property mentioned within\nparentheses above is used.\n\nWhenever a post is rejected due to a runtime option, the entire input\nform is returned intact to the client with an error message, so that\nthey can fix the errors or wait for the suggested post interval and\nresubmit the post again.\n\nThe property values in `opt.lisp` may be modified at any time, even\nwhile MathB is running.  It is not necessary to restart MathB after\nchanging property values in `opt.lisp`.  The changes are picked up\nautomatically while processing the next HTTP POST request.\n\n\nTemplate Files\n--------------\n\nThere are two template files to generate the HTML pages sent to the\nclients:\n\n  - [`web/html/mathb.html`]: This template file is used to generate\n    the HTML response for the home page, a mathematical snippet page,\n    as well as an HTTP response page when the post is rejected due to\n    a validation error.\n\n  - [`web/html/error.html`]: This template file is used to generate\n    HTTP error pages.\n\nA template file may be modified at any time, even while MathB is\nrunning.  It is not necessary to restart MathB after changing a\ntemplate file.  The changes are picked up automatically while\nprocessing the next HTTP request.\n\n[`web/html/mathb.html`]: web/html/mathb.html\n[`web/html/error.html`]: web/html/error.html\n\n\nStatic Files\n------------\n\nThere are three types of static files that MathB uses to for its HTML\npages:\n\n  - [`web/js/`]: This directory contains the JavaScript files that\n    perform input rendering as a user types out content in the input\n    form.\n\n  - [`web/css/`]: This directory contains the stylesheets for the HTML\n    pages generated by MathB.\n\n  - [`web/img/`]: This directory contains the favicons for the\n    website.  These icons are generated using a LaTeX project in the\n    [`meta/logo/`] directory.\n\nA static file may be modified at any time, even while MathB is\nrunning.  It is not necessary to restart MathB after adding, deleting,\nor editing a static file.  However, it is necessary to run `make live`\n(in the top-level directory of the project) to copy the static files\nto the live directory (explained in the next section) from which MathB\nserves the static files.\n\n[`web/js/`]: web/js/\n[`web/css/`]: web/css/\n[`web/img/`]: web/img/\n[`meta/logo/`]: meta/logo/\n\n\nLive Directory\n--------------\n\nMathB needs to pull additional JavaScript libraries named TeXMe,\nMarked, and MathJax that are essential for rendering Markdown and\nLaTeX input.  This is done by running the following command in the\ntop-level directory of this project:\n\n```sh\nmake live\n```\n\nThe above command creates a `_live` directory from scratch, copies the\nstatic files to it, then pulls the additional JavaScript libraries\ninto it, and sets up the `_live` directory, so that MathB can serve\nthe static files from it.\n\nThe live directory should never be modified directly because every\n`make live` run deletes the entire directory and creates it from\nscratch again.  Any modification necessary should be made to the\ntemplate files or static files explained in the previous two sections.\n\n\nPrint\n-----\n\nWhile the primary purpose of this project is to allow users to write\nmathematical snippets, save them, and share a link to them with\nothers, the stylesheet used in this project takes special care to\nallow printing beautifully rendered pages to paper.\n\nWhen a MathB page is printed, only the rendered content appears in the\nprint.  The input form, buttons, navigation links, and other user\ninterface elements do not appear in the print.\n\n\nSave PDF\n--------\n\nIt is possible to turn a MathB post into a PDF file using the printing\nfacility of most web browsers running on a desktop or laptop.  The\nexact steps to save a web page as PDF vary from browser to browser but\nthe steps to do so look roughly like this:\n\n- Select File \u003e Print from the web browser menu.\n- Then in the print window or dialog box that comes up,\n  deselect/disable the options to print headers and footers.\n- Finally, choose the option to save a PDF.\n\nIf everything works as expected, the saved PDF should contain only the\nrendered content with all mathematical formulas rendered properly.\nThe web pages generated by this project use special styling rules to\nensure that the input form, buttons, navigation links, and other user\ninterface elements do not appear in saved PDF.\n\n\nHistory\n-------\n\nMathB.in was the longest-running mathematics pastebin, serving its\ncommunity of users for over a decade until its discontinuation in\nMarch 2025.  It was not the first mathematics pastebin on the world\nwide web though.  It was the second one.  The first one was created by\nMark A. Stratman which was hosted at `mathbin.net` until 2020.\n\nMathB.in was launched on Sunday, 25 March 2012, after a single night\nof furious coding.  This was a result of stumbling upon\n[math.stackexchange.com][] the previous night, which used MathJax to\nrender mathematical formulas in a web browser.  Thanks to that chance\nencounter with MathJax, the rest of that Saturday night was spent\ncoding a new mathematics pastebin using MathJax and PHP.  After coding\nthrough the night, registering a domain name, and setting up a\nwebsite, MathB.in was released early Sunday morning.\n\nOver the years, MathB.in received occasional refinements.  It was\neventually rewritten in Common Lisp, replacing its original PHP\nimplementation.  For a detailed account of its evolution, see the post\n[MathB.in Turns Ten][].\n\nMathB.in remained a useful tool for IRC communities, students,\neducators, and collaborators for 13 years.  It was eventually shut\ndown on Sunday, 16 March 2025.  At the time of its discontinuation, it\nheld the distinction of being the longest-running mathematics\npastebin.  For more details about why this service was discontinued,\nsee the post [MathB.in Is Shutting Down][].\n\nAlthough the original MathB.in service no longer exists, its source\ncode is still available as free and open-source software through this\nproject.\n\n[math.stackexchange.com]: https://math.stackexchange.com/\n[MathB.in Turns Ten]: https://susam.net/blog/mathbin-turns-ten.html\n[MathB.in Is Shutting Down]: https://susam.net/blog/mathbin-is-shutting-down.html\n\n\nLicense\n-------\n\nThis is free and open source software.  You can use, copy, modify,\nmerge, publish, distribute, sublicense, and/or sell copies of it,\nunder the terms of the MIT License.  See [LICENSE.md][L] for details.\n\nThis software is provided \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nexpress or implied.  See [LICENSE.md][L] for details.\n\n[L]: LICENSE.md\n\n\nSupport\n-------\n\nTo report bugs, suggest improvements, or ask questions, [create\nissues][issues].\n\n[issues]: https://github.com/susam/mathb/issues\n\n\nChannels\n--------\n\nThe author of this project hangs out at the following places online:\n\n- Website: [susam.net](https://susam.net)\n- GitHub: [@susam](https://github.com/susam) on GitHub\n- Mastodon: [@susam@mastodon.social](https://mastodon.social/@susam)\n\nYou are welcome to subscribe to, follow, or join one or more of the\nabove channels to receive updates from the author or ask questions\nabout this project.\n\n\nMore\n----\n\nIf you like this project, check out related projects\n[TeXMe](https://github.com/susam/texme) and\n[Muboard](https://github.com/susam/muboard).\n","funding_links":[],"categories":["Common Lisp","Applications"],"sub_categories":["Education"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsusam%2Fmathb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsusam%2Fmathb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsusam%2Fmathb/lists"}