Showing preview only (1,270K chars total). Download the full file or copy to clipboard to get everything.
Repository: kt3k/remarker
Branch: main
Commit: a3698e754e9b
Files: 44
Total size: 1.2 MB
Directory structure:
gitextract_o9ditkzz/
├── .bmp.yml
├── .editorconfig
├── .github/
│ └── workflows/
│ └── ci.yml
├── .gitignore
├── LICENSE
├── README.md
├── assets/
│ ├── default.css
│ └── help-message.txt
├── examples/
│ ├── add-scripts/
│ │ ├── bar.css
│ │ ├── baz.js
│ │ ├── foo.css
│ │ ├── qux.js
│ │ ├── remarker.yml
│ │ └── slides.md
│ ├── favicon/
│ │ ├── remarker.yml
│ │ └── slides.md
│ ├── has-assets/
│ │ └── slides.md
│ ├── latex-mathjax/
│ │ ├── remarker.yml
│ │ └── slides.md
│ ├── livereload-false/
│ │ ├── remarker.yml
│ │ └── slides.md
│ ├── livereload-port/
│ │ ├── remarker.yml
│ │ └── slides.md
│ ├── metatags/
│ │ ├── README.md
│ │ ├── my-slides-2.md
│ │ ├── my-slides.md
│ │ ├── remarker.yml
│ │ └── slides.md
│ ├── remark/
│ │ ├── README.md
│ │ ├── remarker.yml
│ │ └── slides.md
│ ├── replace-remark/
│ │ ├── my-own-remark.js
│ │ ├── remarker.yml
│ │ └── slides.md
│ └── simple/
│ ├── README.md
│ ├── my-slides-2.md
│ ├── my-slides.md
│ └── slides.md
├── index.js
├── layout.njk
├── package.json
├── test.js
└── vendor/
├── livereload.js
└── remark.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .bmp.yml
================================================
version: 1.15.0
commit: Bump to version v%.%.%
files:
README.md: remarker v%.%.%
package.json: '"version": "%.%.%"'
================================================
FILE: .editorconfig
================================================
root=true
[*]
indent_style=space
indent_size=2
trim_trailing_whitespace=true
insert_final_newline=true
================================================
FILE: .github/workflows/ci.yml
================================================
name: ci
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v4
- run: npm install
- run: npm run cov
- uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
================================================
FILE: .gitignore
================================================
# npm
/node_modules
# Sorry, npm. We prefer yarn.lock
/package-lock.json
# coverage
/coverage
/.nyc_output
================================================
FILE: LICENSE
================================================
The MIT License
Copyright © 2016 Yoshiya Hinosawa ( @kt3k )
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.
================================================
FILE: README.md
================================================
# remarker v1.15.0
[](https://github.com/kt3k/remarker/actions/workflows/ci.yml)
[](https://codecov.io/gh/kt3k/remarker)
> [Remark][remark] cli
[remark][remark] is a simple, in-browser, markdown-driven slideshow tool.
`remarker` is a command line tool for building a remark-based slideshow page
very easily.
# Usage
Install via npm:
```console
$ npm install --save remarker
```
Write your slide in markdown:
```md
# My Slide
---
# My Slide 2
???
Presenter notes here
---
```
save the above as `slides.md`
Invoke `remarker` command.
```console
$ ./node_modules/.bin/remarker
```
Or if you have `npx` command, then hit:
```console
$ npx remarker
```
This starts a local server at port 6275 (this is configurable) and you can see
your slides at [http://localhost:6275/](http://localhost:6275/).
See remark's [slide](https://remarkjs.com/) and
[documentation](https://github.com/gnab/remark#remark) for more details about
its syntax, features etc.
## Build slides
You can build your slides as static page as `remarker build` command.
```console
$ ./node_modules/.bin/remarker build
```
This builds your slides as html page under `build/` directory. The output
directory is configurable. See the below for details.
## Installing globally
You can instead install it globally, in one of these two ways:
```bash
sudo npm i -g remarker # from the npm repository
sudo npm i -g . # if there's a clone in the current directory
```
After that, you should be able to invoke it this way from any directory in your
system:
```bash
remarker [build]
```
# Configuration
You can configure remarker with the configuration file `remarker.yml`:
(Note: remarker.yml should be put in the current directory.)
Default settings are as follows:
```yml
port: 6275
dest: build
out: index.html
source: slides.md
title: ''
assets: ['assets']
css: ''
cssFiles: []
script: ''
scriptFiles: []
remarkConfig: {}
remarkPath: moduleDir + '/vendor/remark.js'
scriptFilesAfterCreate: []
livereload: true
livereloadPort: 35729
```
## Basic options
- `port` is the port number of remarker server. Default is `6275`.
- `dest` is the destination of `remarker build` command. Default is `build`
- `out` is the filename of the result html page. Default is `index.html`
- `source` is the source markdown filename. Default is `slides.md`.
- `title` is the page title of the slides. Default is an empty string.
- `css` is css text you want to add to slides' html page.
- `cssFiles` is the list of additional stylesheet files (URL or the file path
relative to your current working director) you want to add to slides' html
page. If you provide file paths, these files are copied/served statically.
Default is an empty array.
## Advanced options
- `assets` is the list of assets directory. These directories are copied/served
statically.
- `scriptFiles` is the list of additional JavaScript files (URL or the file path
relative to your current working director) appended after the remark.js. If
you provide file paths, these files are copied/served statically. Default is
an empty array.
- `script` is additional JavaScript code appended after the remark.js and
`scriptFiles`. Default is an empty string.
- `remarkConfig` is the config object which is passed to remark.create(options).
Default is an empty object.
- See
[the remark source code](https://github.com/gnab/remark/blob/develop/src/remark/models/slideshow.js#L41-L48)
for what option is available.
- `remarkPath` is the path to remark.js. This replaces the original remark.js
with specified one.
- `scriptFilesAfterCreate` is the list of additional JavaScript files (URL or
the file path relative to your current working director) appended after the
`remark.create()`. If you provide file paths, these files are copied/served
statically. Default is an empty array.
- `livereload` is the flag to toggle livereloading feature. Default is true.
- `livereloadPort` is the port number for livereloading websocket connection.
Default is 35729.
## CLI Usage
<!--
Notes: This help message is stored in //assets/help-message.txt
Please try keep these in sync.
-->
```
Usage:
remarker [options] serve Serves all the assets at localhost
remarker [options] build Builds all the assets to the dest
Options:
-h, --help Shows the help message and exits
-v, --version Shows the version number and exits
-s, --source <path> Specifies the slide's markdown file.
This overrides 'source' property of the config file.
-o, --out <filename> The output filename of the slides. Default is index.html.
-d, --dest <path> The destination directory for built slides.
-p, --port <number> The port number for dev server.
-b, --open-browser Open the browser to the page when server starts. Default is false.
```
# Examples
- [simple example](https://github.com/kt3k/remarker/tree/master/examples/simple)
- [remark slides](https://github.com/kt3k/remarker/tree/master/examples/remark)
- The original `remark` slides in `remarker` configuration.
- [LaTeX and Mathjax](https://github.com/kt3k/remarker/tree/master/examples/latex-mathjax)
- Usage of LaTeX and Mathjax in remarker. Contributed by @michaelliebling.
# Motivation of `remarker`
`remark` is a great presentation tool and you can write your slide's contents in
markdown. The problem is when you simply use remark, you need to maintain the
html, css and scripts as well as markdown. If you care the details of design and
style of the slides, that's fine. However if you don't care the design of the
slides that much and want to focus only on the contents, then the settings of
css, html, scripts seem quite messy. `remarker` solves this problem. `remarker`
separates the contents (= markdown) from the settings (css, html, scripts). So
you can only focus on and keep maintaining the contents of the slides and let
`remarker` do the rest of the work. This is easier than using `remark` directly.
# How-tos
## How to use images in slides
Put the images under `./assets` directory and they are automatically
served/copied and you can reference it like
`<img src="assets/my-diagram.png" width="600" />` in your slides.
The directory name of `assets` can be configured in `remarker.yml`. See the
configuration section for details.
# Who uses this tool?
See [this search](https://github.com/search?q=filename%3Aremarker.yml).
# History
- 2022-11-24 v1.15.0 Added loading indicator.
- 2022-02-13 v1.14.0 Fixed error while changing slides.md
- 2020-05-11 v1.12.0 Added scriptFilesAfterCreate option.
- 2019-10-18 v1.11.1 Fix dependency.
- 2019-10-18 v1.11.0 Added `-b, --open-browser` option.
- 2019-05-14 v1.10.0 Added `--dest`, `--out`, and `--port` CLI options.
- 2018-08-06 v1.9.0 Added :emoji: transformation. Modify `cssFiles` option
handling (#11).
- 2018-06-10 v1.8.1 Fixed help and version options.
- 2018-06-10 v1.8.0 Added livereloading feature.
- 2018-01-29 v1.7.0 Enabled file asset (#8).
- 2018-01-13 v1.6.1 Fixed -s option.
- 2018-01-12 v1.6.0 Added --source cli option.
- 2017-08-05 v1.3.0 Added remarkConfig prop.
# License
MIT
[remark]: https://github.com/gnab/remark
================================================
FILE: assets/default.css
================================================
body {
font-family: 'Avenir Next', 'Hiragino Kaku Gothic ProN', 'Meiryo', 'メイリオ', sans-serif;
}
h1, h2, h3 {
font-weight: bold;
}
.remark-code,
.remark-inline-code {
font-family: 'Menlo', 'Monaco', 'Courier new', monospace;
}
.remark-slide-content.inverse {
color: #f3f3f3;
background-color: #272822;
}
================================================
FILE: assets/help-message.txt
================================================
Usage:
remarker [options] serve Serves all the assets at localhost
remarker [options] build Builds all the assets to the dest
Options:
-h, --help Shows the help message and exits
-v, --version Shows the version number and exits
-s, --source <path> Specifies the slide's markdown file.
This overrides 'source' property of the config file.
-o, --out <filename> The output filename of the slides. Default is index.html.
-d, --dest <path> The destination directory for built slides.
-p, --port <number> The port number for dev server.
-b, --open-browser Open the browser to the page when server starts. Default is false.
See https://npm.im/remarker for more details.
================================================
FILE: examples/add-scripts/bar.css
================================================
================================================
FILE: examples/add-scripts/baz.js
================================================
================================================
FILE: examples/add-scripts/foo.css
================================================
================================================
FILE: examples/add-scripts/qux.js
================================================
================================================
FILE: examples/add-scripts/remarker.yml
================================================
cssFiles:
- foo.css
- bar.css
- https://example.com/style.css
scriptFiles:
- baz.js
- qux.js
- https://example.com/script.js
================================================
FILE: examples/add-scripts/slides.md
================================================
# add script example
================================================
FILE: examples/favicon/remarker.yml
================================================
assets:
- favicon.ico
================================================
FILE: examples/favicon/slides.md
================================================
class: center, middle
# My Awesome Presentation
This is my-slides.md
---
# Agenda
1. Introduction
2. Deep-dive
3. ...
## [NOTE]: Note that you need remark.js alongside this html file, but no internet connection.
# Introduction
================================================
FILE: examples/has-assets/slides.md
================================================
class: center, middle
# My Awesome Presentation
???
Notes for the _first_ slide!
---
# Agenda
1. Introduction
2. Deep-dive
3. ...
## [NOTE]: Note that you need remark.js alongside this html file, but no internet connection.
# Introduction
================================================
FILE: examples/latex-mathjax/remarker.yml
================================================
scriptFiles:
- https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS_HTML&delayStartupUntil=configured
script:
- "MathJax.Hub.Config({ tex2jax: { skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'] } }); MathJax.Hub.Configured();"
================================================
FILE: examples/latex-mathjax/slides.md
================================================
class: center, middle
# Configuring remarker to display LaTeX via MathJax
Michael Liebling
26 September 2019
This is an example [Remark](https://github.com/gnab/remark) presentation that
demonstrates the configuration of
[Remarker](https://www.npmjs.com/package/remarker) for the use of LaTeX math via
[MathJax](https://www.mathjax.org).
---
# LaTeX, Mathjax, & Remark
The use of MathJax with Remark is documented on a
[Remark wiki page](https://github.com/gnab/remark/wiki/LaTeX-using-MathJax).
Specifically, the syntax requires that LaTeX math commands be placed between a
pair of backticks:
```markdown
`\(\LaTeX{}\)`
1. This is an inline integral: `\(\int_a^bf(x)dx\)`
2. More `\(x={a \over b}\)` formulae.
Display formula:
$$e^{i\pi} + 1 = 0$$
```
_Note:_ this is different from the syntax used in
[marked2app](https://marked2app.com/help/MathJax.html), where LaTeX math is
indicated with an extra backslash:
```markdown
\\( x^2+y^2 \\)
```
---
# LaTeX and Mathjax with Remarker
In order for the presentation to be properly generated, one creates a
`remarker.yml` configuration file (at the same level as the `slides.md` file)
with the following content:
```YML
scriptFiles:
- https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS_HTML&delayStartupUntil=configured
script:
- "MathJax.Hub.Config({ tex2jax: { skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'] } }); MathJax.Hub.Configured();"
```
---
# Math example
`\(\LaTeX{}\)`
1. This is an inline integral: `\(\int_a^bf(x)dx\)`
2. More `\(x={a \over b}\)` formulae.
Display formula:
$$e^{i\pi} + 1 = 0$$
================================================
FILE: examples/livereload-false/remarker.yml
================================================
livereload: false
================================================
FILE: examples/livereload-false/slides.md
================================================
# hey
================================================
FILE: examples/livereload-port/remarker.yml
================================================
livereloadPort: 12345
================================================
FILE: examples/livereload-port/slides.md
================================================
# demo of livereloading in different port
test test
================================================
FILE: examples/metatags/README.md
================================================
run:
node ../../index.js
and slides are up at `http://localhost:6275/`
================================================
FILE: examples/metatags/my-slides-2.md
================================================
class: center, middle
# My Awesome Presentation
This is my-slides-2.md
---
# Agenda
1. Introduction
2. Deep-dive
3. ...
## [NOTE]: Note that you need remark.js alongside this html file, but no internet connection.
# Introduction
================================================
FILE: examples/metatags/my-slides.md
================================================
class: center, middle
# My Awesome Presentation
This is my-slides.md
---
# Agenda
1. Introduction
2. Deep-dive
3. ...
## [NOTE]: Note that you need remark.js alongside this html file, but no internet connection.
# Introduction
================================================
FILE: examples/metatags/remarker.yml
================================================
title: Example slides
description: This is example slides
ogImage: https://avatars.githubusercontent.com/kt3k
ogImageWidth: 400
ogImageHeight: 400
twitter: kt3k
favicon: https://avatars.githubusercontent.com/kt3k
url: https://github.com/kt3k/remarker
================================================
FILE: examples/metatags/slides.md
================================================
class: center, middle
# My Awesome Presentation
???
Notes for the _first_ slide!
---
# Agenda
1. Introduction :mag:
2. Deep-dive :swimmer:
3. ...
## [NOTE]: Note that you need remark.js alongside this html file, but no internet connection.
# Introduction
================================================
FILE: examples/remark/README.md
================================================
run:
node ../../index.js
and slides are up at `http://localhost:6275/`
================================================
FILE: examples/remark/remarker.yml
================================================
remarkConfig:
highlightStyle: monokai
highlightLanguage: remark
highlightLines: true
assets:
- unknown-assets
- symlink-asset
- fifo-asset
css: |
@import url(https://fonts.googleapis.com/css?family=Droid+Serif);
@import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz);
@import url(https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic);
body {
font-family: 'Droid Serif';
}
h1, h2, h3 {
font-family: 'Yanone Kaffeesatz';
font-weight: 400;
margin-bottom: 0;
}
.remark-slide-content h1 { font-size: 3em; }
.remark-slide-content h2 { font-size: 2em; }
.remark-slide-content h3 { font-size: 1.6em; }
.footnote {
position: absolute;
bottom: 3em;
}
li p { line-height: 1.25em; }
.red { color: #fa0000; }
.large { font-size: 2em; }
a, a > code {
color: rgb(249, 38, 114);
text-decoration: none;
}
code {
background: #e7e8e2;
border-radius: 5px;
}
.remark-code, .remark-inline-code { font-family: 'Ubuntu Mono'; }
.remark-code-line-highlighted { background-color: #373832; }
.pull-left {
float: left;
width: 47%;
}
.pull-right {
float: right;
width: 47%;
}
.pull-right ~ p {
clear: both;
}
#slideshow .slide .content code {
font-size: 0.8em;
}
#slideshow .slide .content pre code {
font-size: 0.9em;
padding: 15px;
}
.inverse {
background: #272822;
color: #777872;
text-shadow: 0 0 20px #333;
}
.inverse h1, .inverse h2 {
color: #f3f3f3;
line-height: 0.8em;
}
/* Slide-specific styling */
#slide-inverse .footnote {
bottom: 12px;
left: 20px;
}
#slide-how .slides {
font-size: 0.9em;
position: absolute;
top: 151px;
right: 140px;
}
#slide-how .slides h3 {
margin-top: 0.2em;
}
#slide-how .slides .first, #slide-how .slides .second {
padding: 1px 20px;
height: 90px;
width: 120px;
-moz-box-shadow: 0 0 10px #777;
-webkit-box-shadow: 0 0 10px #777;
box-shadow: 0 0 10px #777;
}
#slide-how .slides .first {
background: #fff;
position: absolute;
top: 20%;
left: 20%;
z-index: 1;
}
#slide-how .slides .second {
position: relative;
background: #fff;
z-index: 0;
}
/* Two-column layout */
.left-column {
color: #777;
width: 20%;
height: 92%;
float: left;
}
.left-column h2:last-of-type, .left-column h3:last-child {
color: #000;
}
.right-column {
width: 75%;
float: right;
padding-top: 1em;
}
================================================
FILE: examples/remark/slides.md
================================================
name: inverse
## layout: true class: center, middle, inverse
## #remark [ri-mahrk] .footnote[Go directly to [project site](https://github.com/gnab/remark)]
## What is it and why should I be using it?
---
layout: false .left-column[
## What is it?
] .right-column[ A simple, in-browser, Markdown-driven slideshow tool targeted
at people who know their way around HTML and CSS, featuring:
- Markdown formatting, with smart extensions
- Presenter mode, with cloned slideshow view
- Syntax highlighting, supporting a range of languages
- Slide scaling, thus similar appearance on all devices / resolutions .red[*]
- Touch support for smart phones and pads, i.e. swipe to navigate slides
## .footnote[.red[*] At least browsers try their best] ]
.left-column[
## What is it?
## Why use it?
] .right-column[ If your ideal slideshow creation workflow contains any of the
following steps:
- Just write what's on your mind
- Do some basic styling
- Easily collaborate with others
- Share with and show to everyone
Then remark might be perfect for your next.red[*] slideshow!
## .footnote[.red[*] You probably want to convert existing slideshows as well] ]
.left-column[
## What is it?
## Why use it?
] .right-column[ As the slideshow is expressed using Markdown, you may:
- Focus on the content, expressing yourself in next to plain text not worrying
what flashy graphics and disturbing effects to put where
As the slideshow is actually an HTML document, you may:
- Display it in any decent browser
- Style it using regular CSS, just like any other HTML content
- Use it offline!
As the slideshow is contained in a plain file, you may:
- Store it wherever you like; on your computer, hosted from your Dropbox, hosted
on Github Pages alongside the stuff you're presenting...
- Easily collaborate with others, keeping track of changes using your favourite
SCM tool, like Git or Mercurial ]
---
template: inverse
## How does it work, then?
---
name: how
.left-column[
## How does it work?
### - Markdown
] .right-column[ A Markdown-formatted chunk of text is transformed into
individual slides by JavaScript running in the browser:
```remark
# Slide 1
This is slide 1
---
# Slide 2
This is slide 2
```
.slides[ .first[
### Slide 1
This is slide 1 ] .second[
### Slide 2
This is slide 2 ] ]
Regular Markdown rules apply with only a single exception:
- A line containing three dashes constitutes a new slide (not a horizontal rule,
`<hr />`)
## Have a look at the [Markdown website](http://daringfireball.net/projects/markdown/) if you're not familiar with Markdown formatting. ]
.left-column[
## How does it work?
### - Markdown
### - Inside HTML
] .right-column[ A simple HTML document is needed for hosting the styles,
Markdown and the generated slides themselves:
```xml
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
/* Slideshow styles */
</style>
</head>
<body>
* <textarea id="source">
<!-- Slideshow Markdown -->
</textarea>
* <script src="remark.js">
</script>
<script>
* var slideshow = remark.create();
</script>
</body>
</html>
```
## You may download remark to have your slideshow not depend on any online resources, or reference the [latest version](http://remarkjs.com/downloads/remark-latest.min.js) online directly. ]
template: inverse
## Of course, Markdown can only go so far.
---
.left-column[
## Markdown extensions
] .right-column[ To help out with slide layout and formatting, a few Markdown
extensions have been included:
- Slide properties, for naming, styling and templating slides
- Content classes, for styling specific content
- Syntax highlighting, supporting a range of languages ]
---
.left-column[
## Markdown extensions
### - Slide properties
] .right-column[ Initial lines containing key-value pairs are extracted as slide
properties:
```remark
name: agenda
class: middle, center
# Agenda
The name of this slide is {{ name }}.
```
Slide properties serve multiple purposes:
- Naming and styling slides using properties `name` and `class`
- Using slides as templates using properties `template` and `layout`
- Expansion of `{{ property }}` expressions to property values
## See the [complete list](https://github.com/gnab/remark/wiki/Markdown#slide-properties) of slide properties. ]
.left-column[
## Markdown extensions
### - Slide properties
### - Content classes
] .right-column[ Any occurences of one or more dotted CSS class names followed
by square brackets are replaced with the contents of the brackets with the
specified classes applied:
```remark
.footnote[.red.bold[*] Important footnote]
```
Resulting HTML extract:
```xml
<span class="footnote">
<span class="red bold">*</span> Important footnote
</span>
```
## ]
.left-column[
## Markdown extensions
### - Slide properties
### - Content classes
### - Syntax Highlighting
] .right-column[ Code blocks can be syntax highlighted by specifying a language
from the set of
[supported languages](https://github.com/gnab/remark/wiki/Configuration#highlighting).
Using [GFM](http://github.github.com/github-flavored-markdown/) fenced code
blocks you can easily specify highlighting language:
.pull-left[
<pre><code>```javascript
function add(a, b)
return a + b
end
```</code></pre>
] .pull-right[
<pre><code>```ruby
def add(a, b)
a + b
end
```</code></pre>
]
A number of highlighting
[styles](https://github.com/gnab/remark/wiki/Configuration#highlighting) are
available, including several well-known themes from different editors and IDEs.
## ]
.left-column[
## Presenter mode
] .right-column[ To help out with giving presentations, a presenter mode
comprising the following features is provided:
- Display of slide notes for the current slide, to help you remember key points
- Display of upcoming slide, to let you know what's coming
- Cloning of slideshow for viewing on extended display ]
---
.left-column[
## Presenter mode
### - Inline notes
] .right-column[ Just like three dashes separate slides, three question marks
separate slide content from slide notes:
```
Slide 1 content
*???
Slide 1 notes
---
Slide 2 content
*???
Slide 2 notes
```
Slide notes are also treated as Markdown, and will be converted in the same
manner slide content is.
Pressing **P** will toggle presenter mode. ] ??? Congratulations, you just
toggled presenter mode!
## Now press **P** to toggle it back off.
.left-column[
## Presenter mode
### - Inline notes
### - Cloned view
] .right-column[ Presenter mode of course makes no sense to the audience.
Creating a cloned view of your slideshow lets you:
- Move the cloned view to the extended display visible to the audience
- Put the original slideshow in presenter mode
- Navigate as usual, and the cloned view will automatically keep up with the
original
## Pressing **C** will open a cloned view of the current slideshow in a new browser window. ]
template: inverse
## It's time to get started!
---
.left-column[
## Getting started
] .right-column[ Getting up and running is done in only a few steps:
1. Visit the [project site](http://github.com/gnab/remark)
2. Follow the steps in the Getting Started section
## For more information on using remark, please check out the [wiki](https://github.com/gnab/remark/wiki) pages. ]
name: last-page template: inverse
## That's all folks (for now)!
Slideshow created using [remark](http://github.com/gnab/remark).
================================================
FILE: examples/replace-remark/my-own-remark.js
================================================
console.log("remark.js");
================================================
FILE: examples/replace-remark/remarker.yml
================================================
remarkPath: my-own-remark.js
script: console.log("injected script")
================================================
FILE: examples/replace-remark/slides.md
================================================
Slide 0
---
Slide 1
---
Slide 2
================================================
FILE: examples/simple/README.md
================================================
run:
node ../../index.js
and slides are up at `http://localhost:6275/`
================================================
FILE: examples/simple/my-slides-2.md
================================================
class: center, middle
# My Awesome Presentation
This is my-slides-2.md
---
# Agenda
1. Introduction
2. Deep-dive
3. ...
## [NOTE]: Note that you need remark.js alongside this html file, but no internet connection.
# Introduction
================================================
FILE: examples/simple/my-slides.md
================================================
class: center, middle
# My Awesome Presentation
This is my-slides.md
---
# Agenda
1. Introduction
2. Deep-dive
3. ...
## [NOTE]: Note that you need remark.js alongside this html file, but no internet connection.
# Introduction
================================================
FILE: examples/simple/slides.md
================================================
class: center, middle
# My Awesome Presentation
???
Notes for the _first_ slide!
---
# Agenda
1. Introduction :mag:
2. Deep-dive :swimmer:
3. ...
## [NOTE]: Note that you need remark.js alongside this html file, but no internet connection.
# Introduction
================================================
FILE: index.js
================================================
#!/usr/bin/env node
const {
asset,
dest,
name,
on,
port,
debugPagePath,
helpMessage,
loggerTitle,
addMiddleware,
} = require("berber");
const layout1 = require("layout1");
const rename = require("gulp-rename");
const { readFileSync, existsSync, statSync } = require("fs");
const { join } = require("path");
const minimisted = require("minimisted");
const openurl = require("openurl");
const transform = require("vinyl-transform");
const map = require("map-stream");
const emoji = require("node-emoji");
require("yaml-hook/register");
const emojify = () =>
transform((filename) =>
map((chunk, next) => next(null, emoji.emojify(chunk.toString())))
);
const read = (path) => readFileSync(join(__dirname, path)).toString();
const layoutFilename = join(__dirname, "layout.njk");
const defaultCss = read("assets/default.css");
const defaultAssetsPath = "assets";
const defaultConfig = {
title: "", // The page title of the result html
description: "", // The description og:description meta tag
ogImage: "", // The url for og:image and twitter:image
ogImageWidth: null, // The width of og:image
ogImageHeight: null, // The height of og:image
twitter: null, // twitter display id
favicon: null, // The path to favicon
url: null, // The url of the slides
port: 6275, // The port number of dev server
livereload: true,
livereloadPort: 35729,
dest: "build", // The destination directory of built assets
out: "index.html", // The result html filename of the slides
source: "slides.md", // The source of the slides
css: defaultCss, // The additional css for the slides
cssFiles: [], // The additional css files
script: "", // The additional script for the slides
scriptFiles: [], // The additional script files
remarkConfig: {}, // The config object passed to remark
remarkPath: join(__dirname, "vendor", "remark.js"), // The remark path
scriptFilesAfterCreate: [], // The additional script files loaded after remark.create
assets: [defaultAssetsPath], // The asset paths
"open-browser": false, // open the browser to the page when the server starts
};
name("remarker");
debugPagePath("__remarker__");
loggerTitle("remarker");
helpMessage(read("assets/help-message.txt"));
const onConfig = (config, argv) => {
config = Object.assign({}, defaultConfig, config, argv);
port(config.port);
dest(config.dest);
const cssFiles = !Array.isArray(config.cssFiles)
? Array(config.cssFiles)
: config.cssFiles;
const scriptFiles = !Array.isArray(config.scriptFiles)
? Array(config.scriptFiles)
: config.scriptFiles;
const scriptFilesAfterCreate = !Array.isArray(config.scriptFilesAfterCreate)
? Array(config.scriptFilesAfterCreate)
: config.scriptFilesAfterCreate;
const slidePipeline = asset(config.source)
.assetOptions({ allowEmpty: true })
.pipe(emojify())
.pipe(rename(config.out))
.pipe(
layout1.nunjucks(layoutFilename, {
data: {
css: config.css,
cssFiles: cssFiles,
script: config.script,
scriptFiles: scriptFiles,
title: config.title,
description: config.description,
ogImage: config.ogImage,
ogImageWidth: config.ogImageWidth,
ogImageHeight: config.ogImageHeight,
twitter: config.twitter,
favicon: config.favicon,
url: config.url,
remarkConfig: config.remarkConfig,
scriptFilesAfterCreate: scriptFilesAfterCreate,
livereloadPort: config.livereloadPort,
},
}),
);
// livereload settings
if (config.livereload) {
on("serve", () => {
onLivereloadConfig(slidePipeline, config);
});
}
// open browser if the option specified
if (config["open-browser"]) {
on("serve", () => {
openurl.open("http://localhost:" + config.port);
});
}
asset(config.remarkPath).pipe(rename("remark.js"));
cssFiles
.filter((src) => !/^http/.test(src))
.forEach((src) => {
asset(src).base(process.cwd());
});
scriptFiles
.filter((src) => !/^http/.test(src))
.forEach((src) => {
asset(src).base(process.cwd());
});
config.assets.forEach((src) => {
if (existsSync(src)) {
const stat = statSync(src);
if (stat.isDirectory()) {
asset(join(src, "**/*.*")).base(process.cwd());
} else if (stat.isFile()) {
asset(src).base(process.cwd());
} else {
console.log(
`Warning: asset entry '${src}' has unknown type, skipping this entry`,
);
}
} else if (src === defaultAssetsPath) {
// do nothing, ignore silently
} else {
console.log(
`Warning: asset entry '${src}' not found, skipping this entry`,
);
}
});
};
const livereloadScriptMiddleware = (req, res, next) => {
if (require("url").parse(req.url).pathname !== "/livereload.js") {
next();
return;
}
const livereloadScript = read("vendor/livereload.js");
res.setHeader("Content-Type", "text/javascript");
res.end(livereloadScript);
};
const onLivereloadConfig = (slidePipeline, config) => {
const livereload = require("connect-livereload");
const gulplivereload = require("gulp-livereload");
const port = config.livereloadPort;
addMiddleware(() => livereload({ port, src: "/livereload.js" }));
addMiddleware(() => livereloadScriptMiddleware);
gulplivereload.listen({ port });
slidePipeline.pipe(gulplivereload({ port }));
};
on("config", (config) =>
minimisted((argv) => onConfig(config, argv), {
string: ["source", "out", "dest", "port"],
boolean: ["open-browser"],
alias: {
s: "source",
o: "out",
p: "port",
d: "dest",
b: "open-browser",
},
}));
================================================
FILE: layout.njk
================================================
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
{% if url %}
<meta property="og:url" content="{{ url }}" />
{% endif %}
<meta property="og:title" content="{{ title }}"/>
{% if ogImage %}
<meta property="og:image" content="{{ ogImage }}"/>
{% if ogImageWidth %}
<meta property="og:image:width" content="{{ ogImageWidth }}"/>
{% endif %}
{% if ogImageHeight %}
<meta property="og:image:height" content="{{ ogImageHeight }}"/>
{% endif %}
{% endif %}
{% if description %}
<meta property="og:description" content="{{ description }}" />
{% endif %}
{% if twitter %}
<meta name="twitter:creator" content="@{{ twitter }}"/>
{% endif %}
{% if ogImage %}
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="{{ ogImage }}" />
{% endif %}
{% if favicon %}
<link rel="icon" href="{{ favicon }}" type="image/svg+xml" />
{% endif %}
{% for file in cssFiles %}
<link rel="stylesheet" href="{{ file }}" />
{% endfor %}
<style type="text/css">
{{ css | safe }}
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(-360deg); } }
</style>
</head>
<body>
<textarea id="source" style="display: none">{{ file.contents | safe }}</textarea>
<div style="z-index: -1; position: fixed; display: flex; align-items: center; gap: 4px;">
<svg style="animation: spin 1s linear infinite; width: 18px; height: 18px;" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-refresh" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#2c3e50" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<path d="M20 11a8.1 8.1 0 0 0 -15.5 -2m-.5 -4v4h4" />
<path d="M4 13a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4" />
</svg>
<span>loading...</span>
</div>
<script src="remark.js"></script>
{% for file in scriptFiles %}
<script src="{{ file }}"></script>
{% endfor %}
<script>
window.slideshow = remark.create({{ remarkConfig | dump | safe }})
</script>
{% for file in scriptFilesAfterCreate %}
<script src="{{ file }}"></script>
{% endfor %}
<script>
{{ script | safe }}
;window.LiveReloadOptions = {
host: 'localhost',
port: '{{ livereloadPort }}'
};
</script>
</body>
</html>
================================================
FILE: package.json
================================================
{
"name": "remarker",
"version": "1.15.0",
"description": "Remark cli",
"main": "index.js",
"bin": "index.js",
"files": [
"index.js",
"assets",
"vendor",
"layout.njk"
],
"scripts": {
"test": "kocha test",
"cov": "nyc --reporter=lcov --reporter=text-summary npm test",
"codecov": "npm run cov && codecov",
"precommit": "lint-staged"
},
"repository": {
"type": "git",
"url": "git+https://github.com/kt3k/remarker.git"
},
"keywords": [
"remark",
"markdown",
"cli",
"slides"
],
"author": "Yoshiya Hinosawa",
"license": "MIT",
"bugs": {
"url": "https://github.com/kt3k/remarker/issues"
},
"homepage": "https://github.com/kt3k/remarker#readme",
"dependencies": {
"berber": "^1.4.1",
"connect-livereload": "^0.6.0",
"gulp-livereload": "^3.8.1",
"gulp-rename": "^1.2.2",
"layout1": "^1.1.0",
"map-stream": "0.0.7",
"minimisted": "^2.0.0",
"node-emoji": "^1.8.1",
"nunjucks": "^3.0.1",
"openurl": "^1.1.1",
"vinyl-transform": "^1.0.0",
"yaml-hook": "^1.0.0"
},
"devDependencies": {
"axios": "^1.6.0",
"chai": "^4.1.0",
"codecov": "^3.6.5",
"kocha": "^1.8.0",
"nyc": "^13.0.0",
"rimraf": "^2.6.1",
"touch": "^3.1.0",
"ws": "^7.4.6"
}
}
================================================
FILE: test.js
================================================
const { before, after, describe, it, context, timeout } = require("kocha");
const { expect } = require("chai");
const { spawn, execSync } = require("child_process");
const { readFileSync, existsSync } = require("fs");
const { join } = require("path");
const rimraf = require("rimraf");
const touch = require("touch");
const WebSocket = require("ws");
const axios = require("axios");
const examples = {
simple: join(__dirname, "examples/simple"),
replaceRemark: join(__dirname, "examples/replace-remark"),
hasAssets: join(__dirname, "examples/has-assets"),
favicon: join(__dirname, "examples/favicon"),
remark: join(__dirname, "examples/remark"),
addScripts: join(__dirname, "examples/add-scripts"),
};
const processes = [];
before((done) => {
rimraf("examples/*/build", done);
});
after((done) => {
processes.forEach((child) => child.kill());
rimraf("examples/*/{build,build2}", done);
});
describe("remarker", () => {
it("creates index.html from slides.md", () => {
execSync("node ../../index.js build", { cwd: examples.simple });
expect(
readFileSync(join(examples.simple, "build", "index.html")).toString(),
).to.include("My Awesome Presentation");
});
it("replaces :emoji: notations", () => {
execSync("node ../../index.js build", { cwd: examples.simple });
const result = readFileSync(
join(examples.simple, "build", "index.html"),
).toString();
expect(result).to.include("🏊");
expect(result).to.not.include(":swimmer:");
});
it("replaces stylesheets by remarker.yml's css property", () => {
execSync("node ../../index.js build", { cwd: examples.remark });
expect(
readFileSync(join(examples.remark, "build", "index.html")).toString(),
).to.include(
"@import url(https://fonts.googleapis.com/css?family=Droid+Serif);",
);
});
it("replaces remark.js by remarker.yml's remarkPath", () => {
execSync("node ../../index.js build", { cwd: examples.replaceRemark });
expect(
readFileSync(
join(examples.replaceRemark, "build", "remark.js"),
).toString(),
).to.include('console.log("remark.js")');
});
it("injects scripts by remarker.yml's script", () => {
execSync("node ../../index.js build", {
cwd: examples.replaceRemark,
});
expect(
readFileSync(
join(examples.replaceRemark, "build", "index.html"),
).toString(),
).to.include('console.log("injected script")');
});
describe("-s, --source option", () => {
it("specifies the slide's markdown path", () => {
execSync("node ../../index.js build --source my-slides.md", {
cwd: examples.simple,
});
expect(
readFileSync(join(examples.simple, "build", "index.html")).toString(),
).to.include("This is my-slides.md");
execSync("node ../../index.js build -s my-slides-2.md", {
cwd: examples.simple,
});
expect(
readFileSync(join(examples.simple, "build", "index.html")).toString(),
).to.include("This is my-slides-2.md");
});
});
describe("-d, --dest option", () => {
it("specifies destination directory", () => {
execSync("node ../../index.js build --dest build2", {
cwd: examples.simple,
});
expect(
readFileSync(join(examples.simple, "build2", "index.html")).toString(),
).to.include("My Awesome Presentation");
});
});
describe("-o, --out option", () => {
it("specifies destination directory", () => {
execSync("node ../../index.js build --out slides.html", {
cwd: examples.simple,
});
expect(
readFileSync(join(examples.simple, "build", "slides.html")).toString(),
).to.include("My Awesome Presentation");
});
});
describe("contents in assets directory", () => {
it("are copied to build directory", () => {
execSync("node ../../index.js build", { cwd: examples.hasAssets });
expect(existsSync("examples/has-assets/build/assets/degu.png")).to.equal(
true,
);
});
});
describe("file asset entry", () => {
it("builds the given file to build dir", () => {
execSync("node ../../index.js build", { cwd: examples.favicon });
expect(existsSync("examples/favicon/build/favicon.ico")).to.equal(true);
});
});
describe("scriptFiles option", () => {
it("adds script files", () => {
execSync("node ../../index.js build", { cwd: examples.addScripts });
const html = readFileSync(
join(examples.addScripts, "build", "index.html"),
).toString();
expect(html).to.include("baz.js");
expect(html).to.include("qux.js");
});
});
describe("cssFiles option", () => {
it("adds css files", () => {
execSync("node ../../index.js build", { cwd: examples.addScripts });
const html = readFileSync(
join(examples.addScripts, "build", "index.html"),
).toString();
expect(html).to.include("foo.css");
expect(html).to.include("bar.css");
});
});
context("when serving", () => {
it("starts livereload server by default", (done) => {
timeout(8000);
const child = spawn("node", ["../../index.js"], { cwd: examples.remark });
processes.push(child);
setTimeout(() => {
const ws = new WebSocket("http://localhost:35729/livereload");
ws.on("message", (data) => {
expect(JSON.parse(data).command).to.equal("reload");
child.kill();
done();
});
touch(join(examples.remark, "slides.md"));
}, 2000);
});
it("responses livereload.js at /livereload.js", (done) => {
timeout(8000);
const child = spawn("node", ["../../index.js"], { cwd: examples.remark });
processes.push(child);
setTimeout(() => {
axios.get("http://localhost:6275/index.html");
axios.get("http://localhost:6275/livereload.js").then((res) => {
expect(res.data).to.include("livereload");
done();
});
}, 2000);
});
});
});
================================================
FILE: vendor/livereload.js
================================================
(function e(t, n, r) {
function s(o, u) {
if (!n[o]) {
if (!t[o]) {
var a = typeof require == "function" && require;
if (!u && a) return a(o, !0);
if (i) return i(o, !0);
var f = new Error("Cannot find module '" + o + "'");
throw f.code = "MODULE_NOT_FOUND", f;
}
var l = n[o] = { exports: {} };
t[o][0].call(
l.exports,
function (e) {
var n = t[o][1][e];
return s(n ? n : e);
},
l,
l.exports,
e,
t,
n,
r,
);
}
return n[o].exports;
}
var i = typeof require == "function" && require;
for (var o = 0; o < r.length; o++) s(r[o]);
return s;
})(
{
1: [function (require, module, exports) {
(function () {
var Connector, PROTOCOL_6, PROTOCOL_7, Parser, Version, _ref;
_ref = require("./protocol"),
Parser = _ref.Parser,
PROTOCOL_6 = _ref.PROTOCOL_6,
PROTOCOL_7 = _ref.PROTOCOL_7;
Version = "2.2.2";
exports.Connector = Connector = (function () {
function Connector(options, WebSocket, Timer, handlers) {
var path;
this.options = options;
this.WebSocket = WebSocket;
this.Timer = Timer;
this.handlers = handlers;
path = this.options.path ? "" + this.options.path : "livereload";
this._uri = "ws" + (this.options.https ? "s" : "") + "://" +
this.options.host + ":" + this.options.port + "/" + path;
this._nextDelay = this.options.mindelay;
this._connectionDesired = false;
this.protocol = 0;
this.protocolParser = new Parser({
connected: (function (_this) {
return function (protocol) {
_this.protocol = protocol;
_this._handshakeTimeout.stop();
_this._nextDelay = _this.options.mindelay;
_this._disconnectionReason = "broken";
return _this.handlers.connected(protocol);
};
})(this),
error: (function (_this) {
return function (e) {
_this.handlers.error(e);
return _this._closeOnError();
};
})(this),
message: (function (_this) {
return function (message) {
return _this.handlers.message(message);
};
})(this),
});
this._handshakeTimeout = new Timer((function (_this) {
return function () {
if (!_this._isSocketConnected()) {
return;
}
_this._disconnectionReason = "handshake-timeout";
return _this.socket.close();
};
})(this));
this._reconnectTimer = new Timer((function (_this) {
return function () {
if (!_this._connectionDesired) {
return;
}
return _this.connect();
};
})(this));
this.connect();
}
Connector.prototype._isSocketConnected = function () {
return this.socket &&
this.socket.readyState === this.WebSocket.OPEN;
};
Connector.prototype.connect = function () {
this._connectionDesired = true;
if (this._isSocketConnected()) {
return;
}
this._reconnectTimer.stop();
this._disconnectionReason = "cannot-connect";
this.protocolParser.reset();
this.handlers.connecting();
this.socket = new this.WebSocket(this._uri);
this.socket.onopen = (function (_this) {
return function (e) {
return _this._onopen(e);
};
})(this);
this.socket.onclose = (function (_this) {
return function (e) {
return _this._onclose(e);
};
})(this);
this.socket.onmessage = (function (_this) {
return function (e) {
return _this._onmessage(e);
};
})(this);
return this.socket.onerror = (function (_this) {
return function (e) {
return _this._onerror(e);
};
})(this);
};
Connector.prototype.disconnect = function () {
this._connectionDesired = false;
this._reconnectTimer.stop();
if (!this._isSocketConnected()) {
return;
}
this._disconnectionReason = "manual";
return this.socket.close();
};
Connector.prototype._scheduleReconnection = function () {
if (!this._connectionDesired) {
return;
}
if (!this._reconnectTimer.running) {
this._reconnectTimer.start(this._nextDelay);
return this._nextDelay = Math.min(
this.options.maxdelay,
this._nextDelay * 2,
);
}
};
Connector.prototype.sendCommand = function (command) {
if (this.protocol == null) {
return;
}
return this._sendCommand(command);
};
Connector.prototype._sendCommand = function (command) {
return this.socket.send(JSON.stringify(command));
};
Connector.prototype._closeOnError = function () {
this._handshakeTimeout.stop();
this._disconnectionReason = "error";
return this.socket.close();
};
Connector.prototype._onopen = function (e) {
var hello;
this.handlers.socketConnected();
this._disconnectionReason = "handshake-failed";
hello = {
command: "hello",
protocols: [PROTOCOL_6, PROTOCOL_7],
};
hello.ver = Version;
if (this.options.ext) {
hello.ext = this.options.ext;
}
if (this.options.extver) {
hello.extver = this.options.extver;
}
if (this.options.snipver) {
hello.snipver = this.options.snipver;
}
this._sendCommand(hello);
return this._handshakeTimeout.start(this.options.handshake_timeout);
};
Connector.prototype._onclose = function (e) {
this.protocol = 0;
this.handlers.disconnected(
this._disconnectionReason,
this._nextDelay,
);
return this._scheduleReconnection();
};
Connector.prototype._onerror = function (e) {};
Connector.prototype._onmessage = function (e) {
return this.protocolParser.process(e.data);
};
return Connector;
})();
}).call(this);
}, { "./protocol": 6 }],
2: [function (require, module, exports) {
(function () {
var CustomEvents;
CustomEvents = {
bind: function (element, eventName, handler) {
if (element.addEventListener) {
return element.addEventListener(eventName, handler, false);
} else if (element.attachEvent) {
element[eventName] = 1;
return element.attachEvent("onpropertychange", function (event) {
if (event.propertyName === eventName) {
return handler();
}
});
} else {
throw new Error(
"Attempt to attach custom event " + eventName +
" to something which isn't a DOMElement",
);
}
},
fire: function (element, eventName) {
var event;
if (element.addEventListener) {
event = document.createEvent("HTMLEvents");
event.initEvent(eventName, true, true);
return document.dispatchEvent(event);
} else if (element.attachEvent) {
if (element[eventName]) {
return element[eventName]++;
}
} else {
throw new Error(
"Attempt to fire custom event " + eventName +
" on something which isn't a DOMElement",
);
}
},
};
exports.bind = CustomEvents.bind;
exports.fire = CustomEvents.fire;
}).call(this);
}, {}],
3: [function (require, module, exports) {
(function () {
var LessPlugin;
module.exports = LessPlugin = (function () {
LessPlugin.identifier = "less";
LessPlugin.version = "1.0";
function LessPlugin(window, host) {
this.window = window;
this.host = host;
}
LessPlugin.prototype.reload = function (path, options) {
if (this.window.less && this.window.less.refresh) {
if (path.match(/\.less$/i)) {
return this.reloadLess(path);
}
if (options.originalPath.match(/\.less$/i)) {
return this.reloadLess(options.originalPath);
}
}
return false;
};
LessPlugin.prototype.reloadLess = function (path) {
var link, links, _i, _len;
links = (function () {
var _i, _len, _ref, _results;
_ref = document.getElementsByTagName("link");
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
link = _ref[_i];
if (
link.href && link.rel.match(/^stylesheet\/less$/i) ||
(link.rel.match(/stylesheet/i) &&
link.type.match(/^text\/(x-)?less$/i))
) {
_results.push(link);
}
}
return _results;
})();
if (links.length === 0) {
return false;
}
for (_i = 0, _len = links.length; _i < _len; _i++) {
link = links[_i];
link.href = this.host.generateCacheBustUrl(link.href);
}
this.host.console.log(
"LiveReload is asking LESS to recompile all stylesheets",
);
this.window.less.refresh(true);
return true;
};
LessPlugin.prototype.analyze = function () {
return {
disable: !!(this.window.less && this.window.less.refresh),
};
};
return LessPlugin;
})();
}).call(this);
}, {}],
4: [function (require, module, exports) {
(function () {
var Connector,
LiveReload,
Options,
ProtocolError,
Reloader,
Timer,
__hasProp = {}.hasOwnProperty;
Connector = require("./connector").Connector;
Timer = require("./timer").Timer;
Options = require("./options").Options;
Reloader = require("./reloader").Reloader;
ProtocolError = require("./protocol").ProtocolError;
exports.LiveReload = LiveReload = (function () {
function LiveReload(window) {
var k, v, _ref;
this.window = window;
this.listeners = {};
this.plugins = [];
this.pluginIdentifiers = {};
this.console = this.window.console && this.window.console.log &&
this.window.console.error
? this.window.location.href.match(/LR-verbose/)
? this.window.console
: {
log: function () {},
error: this.window.console.error.bind(this.window.console),
}
: {
log: function () {},
error: function () {},
};
if (
!(this.WebSocket = this.window.WebSocket ||
this.window.MozWebSocket)
) {
this.console.error(
"LiveReload disabled because the browser does not seem to support web sockets",
);
return;
}
if ("LiveReloadOptions" in window) {
this.options = new Options();
_ref = window["LiveReloadOptions"];
for (k in _ref) {
if (!__hasProp.call(_ref, k)) continue;
v = _ref[k];
this.options.set(k, v);
}
} else {
this.options = Options.extract(this.window.document);
if (!this.options) {
this.console.error(
"LiveReload disabled because it could not find its own <SCRIPT> tag",
);
return;
}
}
this.reloader = new Reloader(this.window, this.console, Timer);
this.connector = new Connector(
this.options,
this.WebSocket,
Timer,
{
connecting: (function (_this) {
return function () {};
})(this),
socketConnected: (function (_this) {
return function () {};
})(this),
connected: (function (_this) {
return function (protocol) {
var _base;
if (
typeof (_base = _this.listeners).connect === "function"
) {
_base.connect();
}
_this.log(
"LiveReload is connected to " + _this.options.host + ":" +
_this.options.port + " (protocol v" + protocol + ").",
);
return _this.analyze();
};
})(this),
error: (function (_this) {
return function (e) {
if (e instanceof ProtocolError) {
if (typeof console !== "undefined" && console !== null) {
return console.log("" + e.message + ".");
}
} else {
if (typeof console !== "undefined" && console !== null) {
return console.log(
"LiveReload internal error: " + e.message,
);
}
}
};
})(this),
disconnected: (function (_this) {
return function (reason, nextDelay) {
var _base;
if (
typeof (_base = _this.listeners).disconnect === "function"
) {
_base.disconnect();
}
switch (reason) {
case "cannot-connect":
return _this.log(
"LiveReload cannot connect to " + _this.options.host +
":" + _this.options.port + ", will retry in " +
nextDelay + " sec.",
);
case "broken":
return _this.log(
"LiveReload disconnected from " + _this.options.host +
":" + _this.options.port + ", reconnecting in " +
nextDelay + " sec.",
);
case "handshake-timeout":
return _this.log(
"LiveReload cannot connect to " + _this.options.host +
":" + _this.options.port +
" (handshake timeout), will retry in " + nextDelay +
" sec.",
);
case "handshake-failed":
return _this.log(
"LiveReload cannot connect to " + _this.options.host +
":" + _this.options.port +
" (handshake failed), will retry in " + nextDelay +
" sec.",
);
case "manual":
break;
case "error":
break;
default:
return _this.log(
"LiveReload disconnected from " + _this.options.host +
":" + _this.options.port + " (" + reason +
"), reconnecting in " + nextDelay + " sec.",
);
}
};
})(this),
message: (function (_this) {
return function (message) {
switch (message.command) {
case "reload":
return _this.performReload(message);
case "alert":
return _this.performAlert(message);
}
};
})(this),
},
);
this.initialized = true;
}
LiveReload.prototype.on = function (eventName, handler) {
return this.listeners[eventName] = handler;
};
LiveReload.prototype.log = function (message) {
return this.console.log("" + message);
};
LiveReload.prototype.performReload = function (message) {
var _ref, _ref1, _ref2;
this.log(
"LiveReload received reload request: " +
(JSON.stringify(message, null, 2)),
);
return this.reloader.reload(message.path, {
liveCSS: (_ref = message.liveCSS) != null ? _ref : true,
liveImg: (_ref1 = message.liveImg) != null ? _ref1 : true,
reloadMissingCSS: (_ref2 = message.reloadMissingCSS) != null
? _ref2
: true,
originalPath: message.originalPath || "",
overrideURL: message.overrideURL || "",
serverURL: "http://" + this.options.host + ":" +
this.options.port,
});
};
LiveReload.prototype.performAlert = function (message) {
return alert(message.message);
};
LiveReload.prototype.shutDown = function () {
var _base;
if (!this.initialized) {
return;
}
this.connector.disconnect();
this.log("LiveReload disconnected.");
return typeof (_base = this.listeners).shutdown === "function"
? _base.shutdown()
: void 0;
};
LiveReload.prototype.hasPlugin = function (identifier) {
return !!this.pluginIdentifiers[identifier];
};
LiveReload.prototype.addPlugin = function (pluginClass) {
var plugin;
if (!this.initialized) {
return;
}
if (this.hasPlugin(pluginClass.identifier)) {
return;
}
this.pluginIdentifiers[pluginClass.identifier] = true;
plugin = new pluginClass(this.window, {
_livereload: this,
_reloader: this.reloader,
_connector: this.connector,
console: this.console,
Timer: Timer,
generateCacheBustUrl: (function (_this) {
return function (url) {
return _this.reloader.generateCacheBustUrl(url);
};
})(this),
});
this.plugins.push(plugin);
this.reloader.addPlugin(plugin);
};
LiveReload.prototype.analyze = function () {
var plugin, pluginData, pluginsData, _i, _len, _ref;
if (!this.initialized) {
return;
}
if (!(this.connector.protocol >= 7)) {
return;
}
pluginsData = {};
_ref = this.plugins;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
plugin = _ref[_i];
pluginsData[plugin.constructor.identifier] =
pluginData =
(typeof plugin.analyze === "function"
? plugin.analyze()
: void 0) || {};
pluginData.version = plugin.constructor.version;
}
this.connector.sendCommand({
command: "info",
plugins: pluginsData,
url: this.window.location.href,
});
};
return LiveReload;
})();
}).call(this);
}, {
"./connector": 1,
"./options": 5,
"./protocol": 6,
"./reloader": 7,
"./timer": 9,
}],
5: [function (require, module, exports) {
(function () {
var Options;
exports.Options = Options = (function () {
function Options() {
this.https = false;
this.host = null;
this.port = 35729;
this.snipver = null;
this.ext = null;
this.extver = null;
this.mindelay = 1000;
this.maxdelay = 60000;
this.handshake_timeout = 5000;
}
Options.prototype.set = function (name, value) {
if (typeof value === "undefined") {
return;
}
if (!isNaN(+value)) {
value = +value;
}
return this[name] = value;
};
return Options;
})();
Options.extract = function (document) {
var element,
keyAndValue,
m,
mm,
options,
pair,
src,
_i,
_j,
_len,
_len1,
_ref,
_ref1;
_ref = document.getElementsByTagName("script");
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
element = _ref[_i];
if (
(src = element.src) &&
(m = src.match(/^[^:]+:\/\/(.*)\/z?livereload\.js(?:\?(.*))?$/))
) {
options = new Options();
options.https = src.indexOf("https") === 0;
if (mm = m[1].match(/^([^\/:]+)(?::(\d+))?$/)) {
options.host = mm[1];
if (mm[2]) {
options.port = parseInt(mm[2], 10);
}
}
if (m[2]) {
_ref1 = m[2].split("&");
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
pair = _ref1[_j];
if ((keyAndValue = pair.split("=")).length > 1) {
options.set(
keyAndValue[0].replace(/-/g, "_"),
keyAndValue.slice(1).join("="),
);
}
}
}
return options;
}
}
return null;
};
}).call(this);
}, {}],
6: [function (require, module, exports) {
(function () {
var PROTOCOL_6,
PROTOCOL_7,
Parser,
ProtocolError,
__indexOf = [].indexOf || function (item) {
for (
var i = 0, l = this.length;
i < l;
i++
) {
if (i in this && this[i] === item) return i;
}
return -1;
};
exports.PROTOCOL_6 =
PROTOCOL_6 =
"http://livereload.com/protocols/official-6";
exports.PROTOCOL_7 =
PROTOCOL_7 =
"http://livereload.com/protocols/official-7";
exports.ProtocolError = ProtocolError = (function () {
function ProtocolError(reason, data) {
this.message = "LiveReload protocol error (" + reason +
') after receiving data: "' + data + '".';
}
return ProtocolError;
})();
exports.Parser = Parser = (function () {
function Parser(handlers) {
this.handlers = handlers;
this.reset();
}
Parser.prototype.reset = function () {
return this.protocol = null;
};
Parser.prototype.process = function (data) {
var command, e, message, options, _ref;
try {
if (this.protocol == null) {
if (data.match(/^!!ver:([\d.]+)$/)) {
this.protocol = 6;
} else if (message = this._parseMessage(data, ["hello"])) {
if (!message.protocols.length) {
throw new ProtocolError(
"no protocols specified in handshake message",
);
} else if (
__indexOf.call(message.protocols, PROTOCOL_7) >= 0
) {
this.protocol = 7;
} else if (
__indexOf.call(message.protocols, PROTOCOL_6) >= 0
) {
this.protocol = 6;
} else {
throw new ProtocolError("no supported protocols found");
}
}
return this.handlers.connected(this.protocol);
} else if (this.protocol === 6) {
message = JSON.parse(data);
if (!message.length) {
throw new ProtocolError("protocol 6 messages must be arrays");
}
command = message[0], options = message[1];
if (command !== "refresh") {
throw new ProtocolError("unknown protocol 6 command");
}
return this.handlers.message({
command: "reload",
path: options.path,
liveCSS: (_ref = options.apply_css_live) != null
? _ref
: true,
});
} else {
message = this._parseMessage(data, ["reload", "alert"]);
return this.handlers.message(message);
}
} catch (_error) {
e = _error;
if (e instanceof ProtocolError) {
return this.handlers.error(e);
} else {
throw e;
}
}
};
Parser.prototype._parseMessage = function (data, validCommands) {
var e, message, _ref;
try {
message = JSON.parse(data);
} catch (_error) {
e = _error;
throw new ProtocolError("unparsable JSON", data);
}
if (!message.command) {
throw new ProtocolError('missing "command" key', data);
}
if (
_ref = message.command, __indexOf.call(validCommands, _ref) < 0
) {
throw new ProtocolError(
"invalid command '" + message.command +
"', only valid commands are: " + (validCommands.join(", ")) +
")",
data,
);
}
return message;
};
return Parser;
})();
}).call(this);
}, {}],
7: [function (require, module, exports) {
(function () {
var IMAGE_STYLES,
Reloader,
numberOfMatchingSegments,
pathFromUrl,
pathsMatch,
pickBestMatch,
splitUrl;
splitUrl = function (url) {
var comboSign, hash, index, params;
if ((index = url.indexOf("#")) >= 0) {
hash = url.slice(index);
url = url.slice(0, index);
} else {
hash = "";
}
comboSign = url.indexOf("??");
if (comboSign >= 0) {
if (comboSign + 1 !== url.lastIndexOf("?")) {
index = url.lastIndexOf("?");
}
} else {
index = url.indexOf("?");
}
if (index >= 0) {
params = url.slice(index);
url = url.slice(0, index);
} else {
params = "";
}
return {
url: url,
params: params,
hash: hash,
};
};
pathFromUrl = function (url) {
var path;
url = splitUrl(url).url;
if (url.indexOf("file://") === 0) {
path = url.replace(/^file:\/\/(localhost)?/, "");
} else {
path = url.replace(/^([^:]+:)?\/\/([^:\/]+)(:\d*)?\//, "/");
}
return decodeURIComponent(path);
};
pickBestMatch = function (path, objects, pathFunc) {
var bestMatch, object, score, _i, _len;
bestMatch = {
score: 0,
};
for (_i = 0, _len = objects.length; _i < _len; _i++) {
object = objects[_i];
score = numberOfMatchingSegments(path, pathFunc(object));
if (score > bestMatch.score) {
bestMatch = {
object: object,
score: score,
};
}
}
if (bestMatch.score > 0) {
return bestMatch;
} else {
return null;
}
};
numberOfMatchingSegments = function (path1, path2) {
var comps1, comps2, eqCount, len;
path1 = path1.replace(/^\/+/, "").toLowerCase();
path2 = path2.replace(/^\/+/, "").toLowerCase();
if (path1 === path2) {
return 10000;
}
comps1 = path1.split("/").reverse();
comps2 = path2.split("/").reverse();
len = Math.min(comps1.length, comps2.length);
eqCount = 0;
while (eqCount < len && comps1[eqCount] === comps2[eqCount]) {
++eqCount;
}
return eqCount;
};
pathsMatch = function (path1, path2) {
return numberOfMatchingSegments(path1, path2) > 0;
};
IMAGE_STYLES = [
{
selector: "background",
styleNames: ["backgroundImage"],
},
{
selector: "border",
styleNames: ["borderImage", "webkitBorderImage", "MozBorderImage"],
},
];
exports.Reloader = Reloader = (function () {
function Reloader(window, console, Timer) {
this.window = window;
this.console = console;
this.Timer = Timer;
this.document = this.window.document;
this.importCacheWaitPeriod = 200;
this.plugins = [];
}
Reloader.prototype.addPlugin = function (plugin) {
return this.plugins.push(plugin);
};
Reloader.prototype.analyze = function (callback) {
return results;
};
Reloader.prototype.reload = function (path, options) {
var plugin, _base, _i, _len, _ref;
this.options = options;
if ((_base = this.options).stylesheetReloadTimeout == null) {
_base.stylesheetReloadTimeout = 15000;
}
_ref = this.plugins;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
plugin = _ref[_i];
if (plugin.reload && plugin.reload(path, options)) {
return;
}
}
if (options.liveCSS && path.match(/\.css(?:\.map)?$/i)) {
if (this.reloadStylesheet(path)) {
return;
}
}
if (options.liveImg && path.match(/\.(jpe?g|png|gif)$/i)) {
this.reloadImages(path);
return;
}
if (options.isChromeExtension) {
this.reloadChromeExtension();
return;
}
return this.reloadPage();
};
Reloader.prototype.reloadPage = function () {
return this.window.document.location.reload();
};
Reloader.prototype.reloadChromeExtension = function () {
return this.window.chrome.runtime.reload();
};
Reloader.prototype.reloadImages = function (path) {
var expando,
img,
selector,
styleNames,
styleSheet,
_i,
_j,
_k,
_l,
_len,
_len1,
_len2,
_len3,
_ref,
_ref1,
_ref2,
_ref3,
_results;
expando = this.generateUniqueString();
_ref = this.document.images;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
img = _ref[_i];
if (pathsMatch(path, pathFromUrl(img.src))) {
img.src = this.generateCacheBustUrl(img.src, expando);
}
}
if (this.document.querySelectorAll) {
for (_j = 0, _len1 = IMAGE_STYLES.length; _j < _len1; _j++) {
_ref1 = IMAGE_STYLES[_j],
selector = _ref1.selector,
styleNames = _ref1.styleNames;
_ref2 = this.document.querySelectorAll(
"[style*=" + selector + "]",
);
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
img = _ref2[_k];
this.reloadStyleImages(img.style, styleNames, path, expando);
}
}
}
if (this.document.styleSheets) {
_ref3 = this.document.styleSheets;
_results = [];
for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) {
styleSheet = _ref3[_l];
_results.push(
this.reloadStylesheetImages(styleSheet, path, expando),
);
}
return _results;
}
};
Reloader.prototype.reloadStylesheetImages = function (
styleSheet,
path,
expando,
) {
var e, rule, rules, styleNames, _i, _j, _len, _len1;
try {
rules = styleSheet != null ? styleSheet.cssRules : void 0;
} catch (_error) {
e = _error;
}
if (!rules) {
return;
}
for (_i = 0, _len = rules.length; _i < _len; _i++) {
rule = rules[_i];
switch (rule.type) {
case CSSRule.IMPORT_RULE:
this.reloadStylesheetImages(rule.styleSheet, path, expando);
break;
case CSSRule.STYLE_RULE:
for (_j = 0, _len1 = IMAGE_STYLES.length; _j < _len1; _j++) {
styleNames = IMAGE_STYLES[_j].styleNames;
this.reloadStyleImages(
rule.style,
styleNames,
path,
expando,
);
}
break;
case CSSRule.MEDIA_RULE:
this.reloadStylesheetImages(rule, path, expando);
}
}
};
Reloader.prototype.reloadStyleImages = function (
style,
styleNames,
path,
expando,
) {
var newValue, styleName, value, _i, _len;
for (_i = 0, _len = styleNames.length; _i < _len; _i++) {
styleName = styleNames[_i];
value = style[styleName];
if (typeof value === "string") {
newValue = value.replace(
/\burl\s*\(([^)]*)\)/,
(function (_this) {
return function (match, src) {
if (pathsMatch(path, pathFromUrl(src))) {
return "url(" +
(_this.generateCacheBustUrl(src, expando)) + ")";
} else {
return match;
}
};
})(this),
);
if (newValue !== value) {
style[styleName] = newValue;
}
}
}
};
Reloader.prototype.reloadStylesheet = function (path) {
var imported,
link,
links,
match,
style,
_i,
_j,
_k,
_l,
_len,
_len1,
_len2,
_len3,
_ref,
_ref1;
links = (function () {
var _i, _len, _ref, _results;
_ref = this.document.getElementsByTagName("link");
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
link = _ref[_i];
if (
link.rel.match(/^stylesheet$/i) &&
!link.__LiveReload_pendingRemoval
) {
_results.push(link);
}
}
return _results;
}).call(this);
imported = [];
_ref = this.document.getElementsByTagName("style");
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
style = _ref[_i];
if (style.sheet) {
this.collectImportedStylesheets(style, style.sheet, imported);
}
}
for (_j = 0, _len1 = links.length; _j < _len1; _j++) {
link = links[_j];
this.collectImportedStylesheets(link, link.sheet, imported);
}
if (this.window.StyleFix && this.document.querySelectorAll) {
_ref1 = this.document.querySelectorAll("style[data-href]");
for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {
style = _ref1[_k];
links.push(style);
}
}
this.console.log(
"LiveReload found " + links.length + " LINKed stylesheets, " +
imported.length + " @imported stylesheets",
);
match = pickBestMatch(
path,
links.concat(imported),
(function (_this) {
return function (l) {
return pathFromUrl(_this.linkHref(l));
};
})(this),
);
if (match) {
if (match.object.rule) {
this.console.log(
"LiveReload is reloading imported stylesheet: " +
match.object.href,
);
this.reattachImportedRule(match.object);
} else {
this.console.log(
"LiveReload is reloading stylesheet: " +
(this.linkHref(match.object)),
);
this.reattachStylesheetLink(match.object);
}
} else {
if (this.options.reloadMissingCSS) {
this.console.log(
"LiveReload will reload all stylesheets because path '" +
path +
"' did not match any specific one. To disable this behavior, set 'options.reloadMissingCSS' to 'false'.",
);
for (_l = 0, _len3 = links.length; _l < _len3; _l++) {
link = links[_l];
this.reattachStylesheetLink(link);
}
} else {
this.console.log(
"LiveReload will not reload path '" + path +
"' because the stylesheet was not found on the page and 'options.reloadMissingCSS' was set to 'false'.",
);
}
}
return true;
};
Reloader.prototype.collectImportedStylesheets = function (
link,
styleSheet,
result,
) {
var e, index, rule, rules, _i, _len;
try {
rules = styleSheet != null ? styleSheet.cssRules : void 0;
} catch (_error) {
e = _error;
}
if (rules && rules.length) {
for (
index = _i = 0, _len = rules.length;
_i < _len;
index = ++_i
) {
rule = rules[index];
switch (rule.type) {
case CSSRule.CHARSET_RULE:
continue;
case CSSRule.IMPORT_RULE:
result.push({
link: link,
rule: rule,
index: index,
href: rule.href,
});
this.collectImportedStylesheets(
link,
rule.styleSheet,
result,
);
break;
default:
break;
}
}
}
};
Reloader.prototype.waitUntilCssLoads = function (clone, func) {
var callbackExecuted, executeCallback, poll;
callbackExecuted = false;
executeCallback = (function (_this) {
return function () {
if (callbackExecuted) {
return;
}
callbackExecuted = true;
return func();
};
})(this);
clone.onload = (function (_this) {
return function () {
_this.console.log(
"LiveReload: the new stylesheet has finished loading",
);
_this.knownToSupportCssOnLoad = true;
return executeCallback();
};
})(this);
if (!this.knownToSupportCssOnLoad) {
(poll = (function (_this) {
return function () {
if (clone.sheet) {
_this.console.log(
"LiveReload is polling until the new CSS finishes loading...",
);
return executeCallback();
} else {
return _this.Timer.start(50, poll);
}
};
})(this))();
}
return this.Timer.start(
this.options.stylesheetReloadTimeout,
executeCallback,
);
};
Reloader.prototype.linkHref = function (link) {
return link.href || link.getAttribute("data-href");
};
Reloader.prototype.reattachStylesheetLink = function (link) {
var clone, parent;
if (link.__LiveReload_pendingRemoval) {
return;
}
link.__LiveReload_pendingRemoval = true;
if (link.tagName === "STYLE") {
clone = this.document.createElement("link");
clone.rel = "stylesheet";
clone.media = link.media;
clone.disabled = link.disabled;
} else {
clone = link.cloneNode(false);
}
clone.href = this.generateCacheBustUrl(this.linkHref(link));
parent = link.parentNode;
if (parent.lastChild === link) {
parent.appendChild(clone);
} else {
parent.insertBefore(clone, link.nextSibling);
}
return this.waitUntilCssLoads(
clone,
(function (_this) {
return function () {
var additionalWaitingTime;
if (/AppleWebKit/.test(navigator.userAgent)) {
additionalWaitingTime = 5;
} else {
additionalWaitingTime = 200;
}
return _this.Timer.start(additionalWaitingTime, function () {
var _ref;
if (!link.parentNode) {
return;
}
link.parentNode.removeChild(link);
clone.onreadystatechange = null;
return (_ref = _this.window.StyleFix) != null
? _ref.link(clone)
: void 0;
});
};
})(this),
);
};
Reloader.prototype.reattachImportedRule = function (_arg) {
var href, index, link, media, newRule, parent, rule, tempLink;
rule = _arg.rule, index = _arg.index, link = _arg.link;
parent = rule.parentStyleSheet;
href = this.generateCacheBustUrl(rule.href);
media = rule.media.length ? [].join.call(rule.media, ", ") : "";
newRule = '@import url("' + href + '") ' + media + ";";
rule.__LiveReload_newHref = href;
tempLink = this.document.createElement("link");
tempLink.rel = "stylesheet";
tempLink.href = href;
tempLink.__LiveReload_pendingRemoval = true;
if (link.parentNode) {
link.parentNode.insertBefore(tempLink, link);
}
return this.Timer.start(
this.importCacheWaitPeriod,
(function (_this) {
return function () {
if (tempLink.parentNode) {
tempLink.parentNode.removeChild(tempLink);
}
if (rule.__LiveReload_newHref !== href) {
return;
}
parent.insertRule(newRule, index);
parent.deleteRule(index + 1);
rule = parent.cssRules[index];
rule.__LiveReload_newHref = href;
return _this.Timer.start(
_this.importCacheWaitPeriod,
function () {
if (rule.__LiveReload_newHref !== href) {
return;
}
parent.insertRule(newRule, index);
return parent.deleteRule(index + 1);
},
);
};
})(this),
);
};
Reloader.prototype.generateUniqueString = function () {
return "livereload=" + Date.now();
};
Reloader.prototype.generateCacheBustUrl = function (url, expando) {
var hash, oldParams, originalUrl, params, _ref;
if (expando == null) {
expando = this.generateUniqueString();
}
_ref = splitUrl(url),
url = _ref.url,
hash = _ref.hash,
oldParams = _ref.params;
if (this.options.overrideURL) {
if (url.indexOf(this.options.serverURL) < 0) {
originalUrl = url;
url = this.options.serverURL + this.options.overrideURL +
"?url=" + encodeURIComponent(url);
this.console.log(
"LiveReload is overriding source URL " + originalUrl +
" with " + url,
);
}
}
params = oldParams.replace(
/(\?|&)livereload=(\d+)/,
function (match, sep) {
return "" + sep + expando;
},
);
if (params === oldParams) {
if (oldParams.length === 0) {
params = "?" + expando;
} else {
params = "" + oldParams + "&" + expando;
}
}
return url + params + hash;
};
return Reloader;
})();
}).call(this);
}, {}],
8: [function (require, module, exports) {
(function () {
var CustomEvents, LiveReload, k;
CustomEvents = require("./customevents");
LiveReload =
window.LiveReload =
new (require("./livereload").LiveReload)(window);
for (k in window) {
if (k.match(/^LiveReloadPlugin/)) {
LiveReload.addPlugin(window[k]);
}
}
LiveReload.addPlugin(require("./less"));
LiveReload.on("shutdown", function () {
return delete window.LiveReload;
});
LiveReload.on("connect", function () {
return CustomEvents.fire(document, "LiveReloadConnect");
});
LiveReload.on("disconnect", function () {
return CustomEvents.fire(document, "LiveReloadDisconnect");
});
CustomEvents.bind(document, "LiveReloadShutDown", function () {
return LiveReload.shutDown();
});
}).call(this);
}, { "./customevents": 2, "./less": 3, "./livereload": 4 }],
9: [function (require, module, exports) {
(function () {
var Timer;
exports.Timer = Timer = (function () {
function Timer(func) {
this.func = func;
this.running = false;
this.id = null;
this._handler = (function (_this) {
return function () {
_this.running = false;
_this.id = null;
return _this.func();
};
})(this);
}
Timer.prototype.start = function (timeout) {
if (this.running) {
clearTimeout(this.id);
}
this.id = setTimeout(this._handler, timeout);
return this.running = true;
};
Timer.prototype.stop = function () {
if (this.running) {
clearTimeout(this.id);
this.running = false;
return this.id = null;
}
};
return Timer;
})();
Timer.start = function (timeout, func) {
return setTimeout(func, timeout);
};
}).call(this);
}, {}],
},
{},
[8],
);
================================================
FILE: vendor/remark.js
================================================
require = (function e(t, n, r) {
function s(o, u) {
if (!n[o]) {
if (!t[o]) {
var a = typeof require == "function" && require;
if (!u && a) return a(o, !0);
if (i) return i(o, !0);
var f = new Error("Cannot find module '" + o + "'");
throw f.code = "MODULE_NOT_FOUND", f;
}
var l = n[o] = { exports: {} };
t[o][0].call(
l.exports,
function (e) {
var n = t[o][1][e];
return s(n ? n : e);
},
l,
l.exports,
e,
t,
n,
r,
);
}
return n[o].exports;
}
var i = typeof require == "function" && require;
for (var o = 0; o < r.length; o++) s(r[o]);
return s;
})(
{
1: [function (require, module, exports) {
// Copyright Joyent, Inc. and other Node contributors.
//
// 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.
function EventEmitter() {
this._events = this._events || {};
this._maxListeners = this._maxListeners || undefined;
}
module.exports = EventEmitter;
// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._maxListeners = undefined;
// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
EventEmitter.defaultMaxListeners = 10;
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter.prototype.setMaxListeners = function (n) {
if (!isNumber(n) || n < 0 || isNaN(n)) {
throw TypeError("n must be a positive number");
}
this._maxListeners = n;
return this;
};
EventEmitter.prototype.emit = function (type) {
var er, handler, len, args, i, listeners;
if (!this._events) {
this._events = {};
}
// If there is no 'error' event listener then throw.
if (type === "error") {
if (
!this._events.error ||
(isObject(this._events.error) && !this._events.error.length)
) {
er = arguments[1];
if (er instanceof Error) {
throw er; // Unhandled 'error' event
} else {
// At least give some kind of context to the user
var err = new Error(
'Uncaught, unspecified "error" event. (' + er + ")",
);
err.context = er;
throw err;
}
}
}
handler = this._events[type];
if (isUndefined(handler)) {
return false;
}
if (isFunction(handler)) {
switch (arguments.length) {
// fast cases
case 1:
handler.call(this);
break;
case 2:
handler.call(this, arguments[1]);
break;
case 3:
handler.call(this, arguments[1], arguments[2]);
break;
// slower
default:
args = Array.prototype.slice.call(arguments, 1);
handler.apply(this, args);
}
} else if (isObject(handler)) {
args = Array.prototype.slice.call(arguments, 1);
listeners = handler.slice();
len = listeners.length;
for (i = 0; i < len; i++) {
listeners[i].apply(this, args);
}
}
return true;
};
EventEmitter.prototype.addListener = function (type, listener) {
var m;
if (!isFunction(listener)) {
throw TypeError("listener must be a function");
}
if (!this._events) {
this._events = {};
}
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (this._events.newListener) {
this.emit(
"newListener",
type,
isFunction(listener.listener) ? listener.listener : listener,
);
}
if (!this._events[type]) {
// Optimize the case of one listener. Don't need the extra array object.
this._events[type] = listener;
} else if (isObject(this._events[type])) {
// If we've already got an array, just append.
this._events[type].push(listener);
} // Adding the second element, need to change to array.
else {
this._events[type] = [this._events[type], listener];
}
// Check for listener leak
if (isObject(this._events[type]) && !this._events[type].warned) {
if (!isUndefined(this._maxListeners)) {
m = this._maxListeners;
} else {
m = EventEmitter.defaultMaxListeners;
}
if (m && m > 0 && this._events[type].length > m) {
this._events[type].warned = true;
console.error(
"(node) warning: possible EventEmitter memory " +
"leak detected. %d listeners added. " +
"Use emitter.setMaxListeners() to increase limit.",
this._events[type].length,
);
if (typeof console.trace === "function") {
// not supported in IE 10
console.trace();
}
}
}
return this;
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.once = function (type, listener) {
if (!isFunction(listener)) {
throw TypeError("listener must be a function");
}
var fired = false;
function g() {
this.removeListener(type, g);
if (!fired) {
fired = true;
listener.apply(this, arguments);
}
}
g.listener = listener;
this.on(type, g);
return this;
};
// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener = function (type, listener) {
var list, position, length, i;
if (!isFunction(listener)) {
throw TypeError("listener must be a function");
}
if (!this._events || !this._events[type]) {
return this;
}
list = this._events[type];
length = list.length;
position = -1;
if (
list === listener ||
(isFunction(list.listener) && list.listener === listener)
) {
delete this._events[type];
if (this._events.removeListener) {
this.emit("removeListener", type, listener);
}
} else if (isObject(list)) {
for (i = length; i-- > 0;) {
if (
list[i] === listener ||
(list[i].listener && list[i].listener === listener)
) {
position = i;
break;
}
}
if (position < 0) {
return this;
}
if (list.length === 1) {
list.length = 0;
delete this._events[type];
} else {
list.splice(position, 1);
}
if (this._events.removeListener) {
this.emit("removeListener", type, listener);
}
}
return this;
};
EventEmitter.prototype.removeAllListeners = function (type) {
var key, listeners;
if (!this._events) {
return this;
}
// not listening for removeListener, no need to emit
if (!this._events.removeListener) {
if (arguments.length === 0) {
this._events = {};
} else if (this._events[type]) {
delete this._events[type];
}
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
for (key in this._events) {
if (key === "removeListener") continue;
this.removeAllListeners(key);
}
this.removeAllListeners("removeListener");
this._events = {};
return this;
}
listeners = this._events[type];
if (isFunction(listeners)) {
this.removeListener(type, listeners);
} else if (listeners) {
// LIFO order
while (listeners.length) {
this.removeListener(type, listeners[listeners.length - 1]);
}
}
delete this._events[type];
return this;
};
EventEmitter.prototype.listeners = function (type) {
var ret;
if (!this._events || !this._events[type]) {
ret = [];
} else if (isFunction(this._events[type])) {
ret = [this._events[type]];
} else {
ret = this._events[type].slice();
}
return ret;
};
EventEmitter.prototype.listenerCount = function (type) {
if (this._events) {
var evlistener = this._events[type];
if (isFunction(evlistener)) {
return 1;
} else if (evlistener) {
return evlistener.length;
}
}
return 0;
};
EventEmitter.listenerCount = function (emitter, type) {
return emitter.listenerCount(type);
};
function isFunction(arg) {
return typeof arg === "function";
}
function isNumber(arg) {
return typeof arg === "number";
}
function isObject(arg) {
return typeof arg === "object" && arg !== null;
}
function isUndefined(arg) {
return arg === void 0;
}
}, {}],
2: [function (require, module, exports) {
(function (global) {
/**
* marked - a markdown parser
* Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed)
* https://github.com/chjj/marked
*/
(function () {
/**
* Block-Level Grammar
*/
var block = {
newline: /^\n+/,
code: /^( {4}[^\n]+\n*)+/,
fences: noop,
hr: /^( *[-*_]){3,} *(?:\n+|$)/,
heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
nptable: noop,
lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/,
list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,
def:
/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
table: noop,
paragraph:
/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
text: /^[^\n]+/,
};
block.bullet = /(?:[*+-]|\d+\.)/;
block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
block.item = replace(block.item, "gm")(/bull/g, block.bullet)();
block.list = replace(block.list)(/bull/g, block.bullet)(
"hr",
/\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/,
)();
block._tag = "(?!(?:" +
"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code" +
"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo" +
"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";
block.html = replace(block.html)("comment", /<!--[\s\S]*?-->/)(
"closed",
/<(tag)[\s\S]+?<\/\1>/,
)("closing", /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)(
/tag/g,
block._tag,
)();
block.paragraph = replace(block.paragraph)("hr", block.hr)(
"heading",
block.heading,
)("lheading", block.lheading)("blockquote", block.blockquote)(
"tag",
"<" + block._tag,
)("def", block.def)();
/**
* Normal Block Grammar
*/
block.normal = merge({}, block);
/**
* GFM Block Grammar
*/
block.gfm = merge({}, block.normal, {
fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
paragraph: /^/,
});
block.gfm.paragraph = replace(block.paragraph)(
"(?!",
"(?!" +
block.gfm.fences.source.replace("\\1", "\\2") + "|" +
block.list.source.replace("\\1", "\\3") + "|",
)();
/**
* GFM + Tables Block Grammar
*/
block.tables = merge({}, block.gfm, {
nptable:
/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/,
});
/**
* Block Lexer
*/
function Lexer(options) {
this.tokens = [];
this.tokens.links = {};
this.options = options || marked.defaults;
this.rules = block.normal;
if (this.options.gfm) {
if (this.options.tables) {
this.rules = block.tables;
} else {
this.rules = block.gfm;
}
}
}
/**
* Expose Block Rules
*/
Lexer.rules = block;
/**
* Static Lex Method
*/
Lexer.lex = function (src, options) {
var lexer = new Lexer(options);
return lexer.lex(src);
};
/**
* Preprocessing
*/
Lexer.prototype.lex = function (src) {
src = src
.replace(/\r\n|\r/g, "\n")
.replace(/\t/g, " ")
.replace(/\u00a0/g, " ")
.replace(/\u2424/g, "\n");
return this.token(src, true);
};
/**
* Lexing
*/
Lexer.prototype.token = function (src, top) {
var src = src.replace(/^ +$/gm, ""),
next,
loose,
cap,
bull,
b,
item,
space,
i,
l;
while (src) {
// newline
if (cap = this.rules.newline.exec(src)) {
src = src.substring(cap[0].length);
if (cap[0].length > 1) {
this.tokens.push({
type: "space",
});
}
}
// code
if (cap = this.rules.code.exec(src)) {
src = src.substring(cap[0].length);
cap = cap[0].replace(/^ {4}/gm, "");
this.tokens.push({
type: "code",
text: !this.options.pedantic ? cap.replace(/\n+$/, "") : cap,
});
continue;
}
// fences (gfm)
if (cap = this.rules.fences.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: "code",
lang: cap[2],
text: cap[3],
});
continue;
}
// heading
if (cap = this.rules.heading.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: "heading",
depth: cap[1].length,
text: cap[2],
});
continue;
}
// table no leading pipe (gfm)
if (top && (cap = this.rules.nptable.exec(src))) {
src = src.substring(cap[0].length);
item = {
type: "table",
header: cap[1].replace(/^ *| *\| *$/g, "").split(/ *\| */),
align: cap[2].replace(/^ *|\| *$/g, "").split(/ *\| */),
cells: cap[3].replace(/\n$/, "").split("\n"),
};
for (i = 0; i < item.align.length; i++) {
if (/^ *-+: *$/.test(item.align[i])) {
item.align[i] = "right";
} else if (/^ *:-+: *$/.test(item.align[i])) {
item.align[i] = "center";
} else if (/^ *:-+ *$/.test(item.align[i])) {
item.align[i] = "left";
} else {
item.align[i] = null;
}
}
for (i = 0; i < item.cells.length; i++) {
item.cells[i] = item.cells[i].split(/ *\| */);
}
this.tokens.push(item);
continue;
}
// lheading
if (cap = this.rules.lheading.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: "heading",
depth: cap[2] === "=" ? 1 : 2,
text: cap[1],
});
continue;
}
// hr
if (cap = this.rules.hr.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: "hr",
});
continue;
}
// blockquote
if (cap = this.rules.blockquote.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: "blockquote_start",
});
cap = cap[0].replace(/^ *> ?/gm, "");
// Pass `top` to keep the current
// "toplevel" state. This is exactly
// how markdown.pl works.
this.token(cap, top);
this.tokens.push({
type: "blockquote_end",
});
continue;
}
// list
if (cap = this.rules.list.exec(src)) {
src = src.substring(cap[0].length);
bull = cap[2];
this.tokens.push({
type: "list_start",
ordered: bull.length > 1,
});
// Get each top-level item.
cap = cap[0].match(this.rules.item);
next = false;
l = cap.length;
i = 0;
for (; i < l; i++) {
item = cap[i];
// Remove the list item's bullet
// so it is seen as the next token.
space = item.length;
item = item.replace(/^ *([*+-]|\d+\.) +/, "");
// Outdent whatever the
// list item contains. Hacky.
if (~item.indexOf("\n ")) {
space -= item.length;
item = !this.options.pedantic
? item.replace(
new RegExp("^ {1," + space + "}", "gm"),
"",
)
: item.replace(/^ {1,4}/gm, "");
}
// Determine whether the next list item belongs here.
// Backpedal if it does not belong in this list.
if (this.options.smartLists && i !== l - 1) {
b = block.bullet.exec(cap[i + 1])[0];
if (bull !== b && !(bull.length > 1 && b.length > 1)) {
src = cap.slice(i + 1).join("\n") + src;
i = l - 1;
}
}
// Determine whether item is loose or not.
// Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
// for discount behavior.
loose = next || /\n\n(?!\s*$)/.test(item);
if (i !== l - 1) {
next = item.charAt(item.length - 1) === "\n";
if (!loose) loose = next;
}
this.tokens.push({
type: loose ? "loose_item_start" : "list_item_start",
});
// Recurse.
this.token(item, false);
this.tokens.push({
type: "list_item_end",
});
}
this.tokens.push({
type: "list_end",
});
continue;
}
// html
if (cap = this.rules.html.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: this.options.sanitize ? "paragraph" : "html",
pre: cap[1] === "pre" || cap[1] === "script" ||
cap[1] === "style",
text: cap[0],
});
continue;
}
// def
if (top && (cap = this.rules.def.exec(src))) {
src = src.substring(cap[0].length);
this.tokens.links[cap[1].toLowerCase()] = {
href: cap[2],
title: cap[3],
};
continue;
}
// table (gfm)
if (top && (cap = this.rules.table.exec(src))) {
src = src.substring(cap[0].length);
item = {
type: "table",
header: cap[1].replace(/^ *| *\| *$/g, "").split(/ *\| */),
align: cap[2].replace(/^ *|\| *$/g, "").split(/ *\| */),
cells: cap[3].replace(/(?: *\| *)?\n$/, "").split("\n"),
};
for (i = 0; i < item.align.length; i++) {
if (/^ *-+: *$/.test(item.align[i])) {
item.align[i] = "right";
} else if (/^ *:-+: *$/.test(item.align[i])) {
item.align[i] = "center";
} else if (/^ *:-+ *$/.test(item.align[i])) {
item.align[i] = "left";
} else {
item.align[i] = null;
}
}
for (i = 0; i < item.cells.length; i++) {
item.cells[i] = item.cells[i]
.replace(/^ *\| *| *\| *$/g, "")
.split(/ *\| */);
}
this.tokens.push(item);
continue;
}
// top-level paragraph
if (top && (cap = this.rules.paragraph.exec(src))) {
src = src.substring(cap[0].length);
this.tokens.push({
type: "paragraph",
text: cap[1].charAt(cap[1].length - 1) === "\n"
? cap[1].slice(0, -1)
: cap[1],
});
continue;
}
// text
if (cap = this.rules.text.exec(src)) {
// Top-level should never reach here.
src = src.substring(cap[0].length);
this.tokens.push({
type: "text",
text: cap[0],
});
continue;
}
if (src) {
throw new Error("Infinite loop on byte: " + src.charCodeAt(0));
}
}
return this.tokens;
};
/**
* Inline-Level Grammar
*/
var inline = {
escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
url: noop,
tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
link: /^!?\[(inside)\]\(href\)/,
reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
br: /^ {2,}\n(?!\s*$)/,
del: noop,
text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/,
};
inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
inline.link = replace(inline.link)("inside", inline._inside)(
"href",
inline._href,
)();
inline.reflink = replace(inline.reflink)("inside", inline._inside)();
/**
* Normal Inline Grammar
*/
inline.normal = merge({}, inline);
/**
* Pedantic Inline Grammar
*/
inline.pedantic = merge({}, inline.normal, {
strong:
/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,
});
/**
* GFM Inline Grammar
*/
inline.gfm = merge({}, inline.normal, {
escape: replace(inline.escape)("])", "~|])")(),
url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
del: /^~~(?=\S)([\s\S]*?\S)~~/,
text: replace(inline.text)("]|", "~]|")("|", "|https?://|")(),
});
/**
* GFM + Line Breaks Inline Grammar
*/
inline.breaks = merge({}, inline.gfm, {
br: replace(inline.br)("{2,}", "*")(),
text: replace(inline.gfm.text)("{2,}", "*")(),
});
/**
* Inline Lexer & Compiler
*/
function InlineLexer(links, options) {
this.options = options || marked.defaults;
this.links = links;
this.rules = inline.normal;
this.renderer = this.options.renderer || new Renderer();
this.renderer.options = this.options;
if (!this.links) {
throw new Error("Tokens array requires a `links` property.");
}
if (this.options.gfm) {
if (this.options.breaks) {
this.rules = inline.breaks;
} else {
this.rules = inline.gfm;
}
} else if (this.options.pedantic) {
this.rules = inline.pedantic;
}
}
/**
* Expose Inline Rules
*/
InlineLexer.rules = inline;
/**
* Static Lexing/Compiling Method
*/
InlineLexer.output = function (src, links, options) {
var inline = new InlineLexer(links, options);
return inline.output(src);
};
/**
* Lexing/Compiling
*/
InlineLexer.prototype.output = function (src) {
var out = "",
link,
text,
href,
cap;
while (src) {
// escape
if (cap = this.rules.escape.exec(src)) {
src = src.substring(cap[0].length);
out += cap[1];
continue;
}
// autolink
if (cap = this.rules.autolink.exec(src)) {
src = src.substring(cap[0].length);
if (cap[2] === "@") {
text = cap[1].charAt(6) === ":"
? this.mangle(cap[1].substring(7))
: this.mangle(cap[1]);
href = this.mangle("mailto:") + text;
} else {
text = escape(cap[1]);
href = text;
}
out += this.renderer.link(href, null, text);
continue;
}
// url (gfm)
if (cap = this.rules.url.exec(src)) {
src = src.substring(cap[0].length);
text = escape(cap[1]);
href = text;
out += this.renderer.link(href, null, text);
continue;
}
// tag
if (cap = this.rules.tag.exec(src)) {
src = src.substring(cap[0].length);
out += this.options.sanitize ? escape(cap[0]) : cap[0];
continue;
}
// link
if (cap = this.rules.link.exec(src)) {
src = src.substring(cap[0].length);
out += this.outputLink(cap, {
href: cap[2],
title: cap[3],
});
continue;
}
// reflink, nolink
if (
(cap = this.rules.reflink.exec(src)) ||
(cap = this.rules.nolink.exec(src))
) {
src = src.substring(cap[0].length);
link = (cap[2] || cap[1]).replace(/\s+/g, " ");
link = this.links[link.toLowerCase()];
if (!link || !link.href) {
out += cap[0].charAt(0);
src = cap[0].substring(1) + src;
continue;
}
out += this.outputLink(cap, link);
continue;
}
// strong
if (cap = this.rules.strong.exec(src)) {
src = src.substring(cap[0].length);
out += this.renderer.strong(this.output(cap[2] || cap[1]));
continue;
}
// em
if (cap = this.rules.em.exec(src)) {
src = src.substring(cap[0].length);
out += this.renderer.em(this.output(cap[2] || cap[1]));
continue;
}
// code
if (cap = this.rules.code.exec(src)) {
src = src.substring(cap[0].length);
out += this.renderer.codespan(escape(cap[2], true));
continue;
}
// br
if (cap = this.rules.br.exec(src)) {
src = src.substring(cap[0].length);
out += this.renderer.br();
continue;
}
// del (gfm)
if (cap = this.rules.del.exec(src)) {
src = src.substring(cap[0].length);
out += this.renderer.del(this.output(cap[1]));
continue;
}
// text
if (cap = this.rules.text.exec(src)) {
src = src.substring(cap[0].length);
out += escape(this.smartypants(cap[0]));
continue;
}
if (src) {
throw new Error("Infinite loop on byte: " + src.charCodeAt(0));
}
}
return out;
};
/**
* Compile Link
*/
InlineLexer.prototype.outputLink = function (cap, link) {
var href = escape(link.href),
title = link.title ? escape(link.title) : null;
return cap[0].charAt(0) !== "!"
? this.renderer.link(href, title, this.output(cap[1]))
: this.renderer.image(href, title, escape(cap[1]));
};
/**
* Smartypants Transformations
*/
InlineLexer.prototype.smartypants = function (text) {
if (!this.options.smartypants) return text;
return text
// em-dashes
.replace(/--/g, "\u2014")
// opening singles
.replace(/(^|[-\u2014/(\[{"\s])'/g, "$1\u2018")
// closing singles & apostrophes
.replace(/'/g, "\u2019")
// opening doubles
.replace(/(^|[-\u2014/(\[{\u2018\s])"/g, "$1\u201c")
// closing doubles
.replace(/"/g, "\u201d")
// ellipses
.replace(/\.{3}/g, "\u2026");
};
/**
* Mangle Links
*/
InlineLexer.prototype.mangle = function (text) {
var out = "",
l = text.length,
i = 0,
ch;
for (; i < l; i++) {
ch = text.charCodeAt(i);
if (Math.random() > 0.5) {
ch = "x" + ch.toString(16);
}
out += "&#" + ch + ";";
}
return out;
};
/**
* Renderer
*/
function Renderer(options) {
this.options = options || {};
}
Renderer.prototype.code = function (code, lang, escaped) {
if (this.options.highlight) {
var out = this.options.highlight(code, lang);
if (out != null && out !== code) {
escaped = true;
code = out;
}
}
if (!lang) {
return "<pre><code>" +
(escaped ? code : escape(code, true)) +
"\n</code></pre>";
}
return '<pre><code class="' +
this.options.langPrefix +
escape(lang, true) +
'">' +
(escaped ? code : escape(code, true)) +
"\n</code></pre>\n";
};
Renderer.prototype.blockquote = function (quote) {
return "<blockquote>\n" + quote + "</blockquote>\n";
};
Renderer.prototype.html = function (html) {
return html;
};
Renderer.prototype.heading = function (text, level, raw) {
return "<h" +
level +
' id="' +
this.options.headerPrefix +
raw.toLowerCase().replace(/[^\w]+/g, "-") +
'">' +
text +
"</h" +
level +
">\n";
};
Renderer.prototype.hr = function () {
return "<hr>\n";
};
Renderer.prototype.list = function (body, ordered) {
var type = ordered ? "ol" : "ul";
return "<" + type + ">\n" + body + "</" + type + ">\n";
};
Renderer.prototype.listitem = function (text) {
return "<li>" + text + "</li>\n";
};
Renderer.prototype.paragraph = function (text) {
return "<p>" + text + "</p>\n";
};
Renderer.prototype.table = function (header, body) {
return "<table>\n" +
"<thead>\n" +
header +
"</thead>\n" +
"<tbody>\n" +
body +
"</tbody>\n" +
"</table>\n";
};
Renderer.prototype.tablerow = function (content) {
return "<tr>\n" + content + "</tr>\n";
};
Renderer.prototype.tablecell = function (content, flags) {
var type = flags.header ? "th" : "td";
var tag = flags.align
? "<" + type + ' style="text-align:' + flags.align + '">'
: "<" + type + ">";
return tag + content + "</" + type + ">\n";
};
// span level renderer
Renderer.prototype.strong = function (text) {
return "<strong>" + text + "</strong>";
};
Renderer.prototype.em = function (text) {
return "<em>" + text + "</em>";
};
Renderer.prototype.codespan = function (text) {
return "<code>" + text + "</code>";
};
Renderer.prototype.br = function () {
return "<br>";
};
Renderer.prototype.del = function (text) {
return "<del>" + text + "</del>";
};
Renderer.prototype.link = function (href, title, text) {
if (this.options.sanitize) {
try {
var prot = decodeURIComponent(unescape(href))
.replace(/[^\w:]/g, "")
.toLowerCase();
} catch (e) {
return "";
}
if (prot.indexOf("javascript:") === 0) {
return "";
}
}
var out = '<a href="' + href + '"';
if (title) {
out += ' title="' + title + '"';
}
out += ">" + text + "</a>";
return out;
};
Renderer.prototype.image = function (href, title, text) {
var out = '<img src="' + href + '" alt="' + text + '"';
if (title) {
out += ' title="' + title + '"';
}
out += ">";
return out;
};
/**
* Parsing & Compiling
*/
function Parser(options) {
this.tokens = [];
this.token = null;
this.options = options || marked.defaults;
this.options.renderer = this.options.renderer || new Renderer();
this.renderer = this.options.renderer;
this.renderer.options = this.options;
}
/**
* Static Parse Method
*/
Parser.parse = function (src, options, renderer) {
var parser = new Parser(options, renderer);
return parser.parse(src);
};
/**
* Parse Loop
*/
Parser.prototype.parse = function (src) {
this.inline = new InlineLexer(
src.links,
this.options,
this.renderer,
);
this.tokens = src.reverse();
var out = "";
while (this.next()) {
out += this.tok();
}
return out;
};
/**
* Next Token
*/
Parser.prototype.next = function () {
return this.token = this.tokens.pop();
};
/**
* Preview Next Token
*/
Parser.prototype.peek = function () {
return this.tokens[this.tokens.length - 1] || 0;
};
/**
* Parse Text Tokens
*/
Parser.prototype.parseText = function () {
var body = this.token.text;
while (this.peek().type === "text") {
body += "\n" + this.next().text;
}
return this.inline.output(body);
};
/**
* Parse Current Token
*/
Parser.prototype.tok = function () {
switch (this.token.type) {
case "space": {
return "";
}
case "hr": {
return this.renderer.hr();
}
case "heading": {
return this.renderer.heading(
this.inline.output(this.token.text),
this.token.depth,
this.token.text,
);
}
case "code": {
return this.renderer.code(
this.token.text,
this.token.lang,
this.token.escaped,
);
}
case "table": {
var header = "",
body = "",
i,
row,
cell,
flags,
j;
// header
cell = "";
for (i = 0; i < this.token.header.length; i++) {
flags = { header: true, align: this.token.align[i] };
cell += this.renderer.tablecell(
this.inline.output(this.token.header[i]),
{ header: true, align: this.token.align[i] },
);
}
header += this.renderer.tablerow(cell);
for (i = 0; i < this.token.cells.length; i++) {
row = this.token.cells[i];
cell = "";
for (j = 0; j < row.length; j++) {
cell += this.renderer.tablecell(
this.inline.output(row[j]),
{ header: false, align: this.token.align[j] },
);
}
body += this.renderer.tablerow(cell);
}
return this.renderer.table(header, body);
}
case "blockquote_start": {
var body = "";
while (this.next().type !== "blockquote_end") {
body += this.tok();
}
return this.renderer.blockquote(body);
}
case "list_start": {
var body = "",
ordered = this.token.ordered;
while (this.next().type !== "list_end") {
body += this.tok();
}
return this.renderer.list(body, ordered);
}
case "list_item_start": {
var body = "";
while (this.next().type !== "list_item_end") {
body += this.token.type === "text"
? this.parseText()
: this.tok();
}
return this.renderer.listitem(body);
}
case "loose_item_start": {
var body = "";
while (this.next().type !== "list_item_end") {
body += this.tok();
}
return this.renderer.listitem(body);
}
case "html": {
var html = !this.token.pre && !this.options.pedantic
? this.inline.output(this.token.text)
: this.token.text;
return this.renderer.html(html);
}
case "paragraph": {
return this.renderer.paragraph(
this.inline.output(this.token.text),
);
}
case "text": {
return this.renderer.paragraph(this.parseText());
}
}
};
/**
* Helpers
*/
function escape(html, encode) {
return html
.replace(!encode ? /&(?!#?\w+;)/g : /&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
function unescape(html) {
return html.replace(/&([#\w]+);/g, function (_, n) {
n = n.toLowerCase();
if (n === "colon") return ":";
if (n.charAt(0) === "#") {
return n.charAt(1) === "x"
? String.fromCharCode(parseInt(n.substring(2), 16))
: String.fromCharCode(+n.substring(1));
}
return "";
});
}
function replace(regex, opt) {
regex = regex.source;
opt = opt || "";
return function self(name, val) {
if (!name) return new RegExp(regex, opt);
val = val.source || val;
val = val.replace(/(^|[^\[])\^/g, "$1");
regex = regex.replace(name, val);
return self;
};
}
function noop() {}
noop.exec = noop;
function merge(obj) {
var i = 1,
target,
key;
for (; i < arguments.length; i++) {
target = arguments[i];
for (key in target) {
if (Object.prototype.hasOwnProperty.call(target, key)) {
obj[key] = target[key];
}
}
}
return obj;
}
/**
* Marked
*/
function marked(src, opt, callback) {
if (callback || typeof opt === "function") {
if (!callback) {
callback = opt;
opt = null;
}
opt = merge({}, marked.defaults, opt || {});
var highlight = opt.highlight,
tokens,
pending,
i = 0;
try {
tokens = Lexer.lex(src, opt);
} catch (e) {
return callback(e);
}
pending = tokens.length;
var done = function () {
var out, err;
try {
out = Parser.parse(tokens, opt);
} catch (e) {
err = e;
}
opt.highlight = highlight;
return err ? callback(err) : callback(null, out);
};
if (!highlight || highlight.length < 3) {
return done();
}
delete opt.highlight;
if (!pending) return done();
for (; i < tokens.length; i++) {
(function (token) {
if (token.type !== "code") {
return --pending || done();
}
return highlight(
token.text,
token.lang,
function (err, code) {
if (code == null || code === token.text) {
return --pending || done();
}
token.text = code;
token.escaped = true;
--pending || done();
},
);
})(tokens[i]);
}
return;
}
try {
if (opt) opt = merge({}, marked.defaults, opt);
return Parser.parse(Lexer.lex(src, opt), opt);
} catch (e) {
e.message +=
"\nPlease report this to https://github.com/chjj/marked.";
if ((opt || marked.defaults).silent) {
return "<p>An error occured:</p><pre>" +
escape(e.message + "", true) +
"</pre>";
}
throw e;
}
}
/**
* Options
*/
marked.options =
marked.setOptions =
function (opt) {
merge(marked.defaults, opt);
return marked;
};
marked.defaults = {
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: false,
smartLists: false,
silent: false,
highlight: null,
langPrefix: "lang-",
smartypants: false,
headerPrefix: "",
renderer: new Renderer(),
};
/**
* Expose
*/
marked.Parser = Parser;
marked.parser = Parser.parse;
marked.Renderer = Renderer;
marked.Lexer = Lexer;
marked.lexer = Lexer.lex;
marked.InlineLexer = InlineLexer;
marked.inlineLexer = InlineLexer.output;
marked.parse = marked;
if (typeof exports === "object") {
module.exports = marked;
} else if (typeof define === "function" && define.amd) {
define(function () {
return marked;
});
} else {
this.marked = marked;
}
}).call(function () {
return this || (typeof window !== "undefined" ? window : global);
}());
}).call(
this,
typeof global !== "undefined"
? global
: typeof self !== "undefined"
? self
: typeof window !== "undefined"
? window
: {},
);
}, {}],
3: [function (require, module, exports) {
exports.apply = function () {
forEach([Array, window.NodeList, window.HTMLCollection], extend);
};
function forEach(list, f) {
var i;
for (i = 0; i < list.length; ++i) {
f(list[i], i);
}
}
function extend(object) {
var prototype = object && object.prototype;
if (!prototype) {
return;
}
prototype.forEach = prototype.forEach || function (f) {
forEach(this, f);
};
prototype.filter = prototype.filter || function (f) {
var result = [];
this.forEach(function (element) {
if (f(element, result.length)) {
result.push(element);
}
});
return result;
};
prototype.map = prototype.map || function (f) {
var result = [];
this.forEach(function (element) {
result.push(f(element, result.length));
});
return result;
};
}
}, {}],
4: [function (require, module, exports) {
var Api = require("./remark/api"),
polyfills = require("./polyfills"),
styler = require("./remark/components/styler/styler");
// Expose API as `remark`
window.remark = new Api();
// Apply polyfills as needed
polyfills.apply();
// Apply embedded styles to document
styler.styleDocument();
}, {
"./polyfills": 3,
"./remark/api": 5,
"./remark/components/styler/styler": "components/styler",
}],
5: [function (require, module, exports) {
var EventEmitter = require("events").EventEmitter,
highlighter = require("./highlighter"),
converter = require("./converter"),
resources = require("./resources"),
Parser = require("./parser"),
Slideshow = require("./models/slideshow"),
SlideshowView = require("./views/slideshowView"),
DefaultController = require("./controllers/defaultController"),
Dom = require("./dom"),
macros = require("./macros");
module.exports = Api;
function Api(dom) {
this.dom = dom || new Dom();
this.macros = macros;
this.version = resources.version;
}
// Expose highlighter to allow enumerating available styles and
// including external language grammars
Api.prototype.highlighter = highlighter;
Api.prototype.convert = function (markdown) {
var parser = new Parser(),
content = parser.parse(markdown || "", macros)[0].content;
return converter.convertMarkdown(content, {}, true);
};
// Creates slideshow initialized from options
Api.prototype.create = function (options, callback) {
var self = this,
events,
slideshow,
slideshowView,
controller;
options = applyDefaults(this.dom, options);
events = new EventEmitter();
events.setMaxListeners(0);
slideshow = new Slideshow(
events,
this.dom,
options,
function (slideshow) {
slideshowView = new SlideshowView(
events,
self.dom,
options.container,
slideshow,
);
controller = options.controller ||
new DefaultController(
events,
self.dom,
slideshowView,
options.navigation,
);
if (typeof callback === "function") {
callback(slideshow);
}
},
);
return slideshow;
};
function applyDefaults(dom, options) {
var sourceElement;
options = options || {};
if (!options.hasOwnProperty("source")) {
sourceElement = dom.getElementById("source");
if (sourceElement) {
options.source = unescape(sourceElement.innerHTML);
sourceElement.style.display = "none";
}
}
if (!(options.container instanceof window.HTMLElement)) {
options.container = dom.getBodyElement();
}
return options;
}
function unescape(source) {
source = source.replace(/&[l|g]t;/g, function (match) {
return match === "<" ? "<" : ">";
});
source = source.replace(/&/g, "&");
source = source.replace(/"/g, '"');
return source;
}
}, {
"./controllers/defaultController": 6,
"./converter": 12,
"./dom": 13,
"./highlighter": 14,
"./macros": 16,
"./models/slideshow": 18,
"./parser": 21,
"./resources": 22,
"./views/slideshowView": 27,
"events": 1,
}],
6: [function (require, module, exports) {
// Allow override of global `location`
/* global location:true */
module.exports = Controller;
var Keyboard = require("./inputs/keyboard"),
mouse = require("./inputs/mouse"),
touch = require("./inputs/touch"),
message = require("./inputs/message"),
location = require("./inputs/location");
function Controller(events, dom, slideshowView, options) {
options = options || {};
var keyboard = new Keyboard(events);
message.register(events);
location.register(events, dom, slideshowView);
mouse.register(events, options);
touch.register(events, options);
addApiEventListeners(events, keyboard, slideshowView, options);
}
function addApiEventListeners(events, keyboard, slideshowView, options) {
events.on("pause", function (event) {
keyboard.deactivate();
mouse.unregister(events);
touch.unregister(events);
});
events.on("resume", function (event) {
keyboard.activate();
mouse.register(events, options);
touch.register(events, options);
});
}
}, {
"./inputs/keyboard": 7,
"./inputs/location": 8,
"./inputs/message": 9,
"./inputs/mouse": 10,
"./inputs/touch": 11,
}],
7: [function (require, module, exports) {
module.exports = Keyboard;
function Keyboard(events) {
this._events = events;
this.activate();
}
Keyboard.prototype.activate = function () {
this._gotoSlideNumber = "";
this.addKeyboardEventListeners();
};
Keyboard.prototype.deactivate = function () {
this.removeKeyboardEventListeners();
};
Keyboard.prototype.addKeyboardEventListeners = function () {
var self = this;
var events = this._events;
events.on("keydown", function (event) {
if (event.metaKey || event.ctrlKey) {
// Bail out if meta or ctrl key was pressed
return;
}
switch (event.keyCode) {
case 33: // Page up
case 37: // Left
case 38: // Up
events.emit("gotoPreviousSlide");
break;
case 32: // Space
case 34: // Page down
case 39: // Right
case 40: // Down
events.emit("gotoNextSlide");
break;
case 36: // Home
events.emit("gotoFirstSlide");
break;
case 35: // End
events.emit("gotoLastSlide");
break;
case 27: // Escape
events.emit("hideOverlay");
break;
case 13: // Return
if (self._gotoSlideNumber) {
events.emit("gotoSlide", self._gotoSlideNumber);
self._gotoSlideNumber = "";
}
break;
}
});
events.on("keypress", function (event) {
if (event.metaKey || event.ctrlKey) {
// Bail out if meta or ctrl key was pressed
return;
}
var key = String.fromCharCode(event.which).toLowerCase();
switch (key) {
case "j":
events.emit("gotoNextSlide");
break;
case "k":
events.emit("gotoPreviousSlide");
break;
case "b":
events.emit("toggleBlackout");
break;
case "m":
events.emit("toggleMirrored");
break;
case "c":
events.emit("createClone");
break;
case "p":
events.emit("togglePresenterMode");
break;
case "f":
events.emit("toggleFullscreen");
break;
case "t":
events.emit("resetTimer");
break;
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
case "0":
self._gotoSlideNumber += key;
break;
case "h":
case "?":
events.emit("toggleHelp");
break;
}
});
};
Keyboard.prototype.removeKeyboardEventListeners = function () {
var events = this._events;
events.removeAllListeners("keydown");
events.removeAllListeners("keypress");
};
}, {}],
8: [function (require, module, exports) {
var utils = require("../../utils.js");
exports.register = function (events, dom, slideshowView) {
addLocationEventListeners(events, dom, slideshowView);
};
function addLocationEventListeners(events, dom, slideshowView) {
// If slideshow is embedded into custom DOM element, we don't
// hook up to location hash changes, so just go to first slide.
if (slideshowView.isEmbedded()) {
events.emit("gotoSlide", 1);
} // When slideshow is not embedded into custom DOM element, but
// rather hosted directly inside document.body, we hook up to
// location hash changes, and trigger initial navigation.
else {
events.on("hashchange", navigateByHash);
events.on("slideChanged", updateHash);
events.on("toggledPresenter", updateHash);
navigateByHash();
}
function navigateByHash() {
var slideNoOrName = (dom.getLocationHash() || "").substr(1);
events.emit("gotoSlide", slideNoOrName);
}
function updateHash(slideNoOrName) {
if (
utils.hasClass(
slideshowView.containerElement,
"remark-presenter-mode",
)
) {
dom.setLocationHash("#p" + slideNoOrName);
} else {
dom.setLocationHash("#" + slideNoOrName);
}
}
}
}, { "../../utils.js": 24 }],
9: [function (require, module, exports) {
exports.register = function (events) {
addMessageEventListeners(events);
};
function addMessageEventListeners(events) {
events.on("message", navigateByMessage);
function navigateByMessage(message) {
var cap;
if ((cap = /^gotoSlide:(\d+)$/.exec(message.data)) !== null) {
events.emit("gotoSlide", parseInt(cap[1], 10), true);
} else if (message.data === "toggleBlackout") {
events.emit("toggleBlackout");
}
}
}
}, {}],
10: [function (require, module, exports) {
exports.register = function (events, options) {
addMouseEventListeners(events, options);
};
exports.unregister = function (events) {
removeMouseEventListeners(events);
};
function addMouseEventListeners(events, options) {
if (options.click) {
events.on("click", function (event) {
if (event.target.nodeName === "A") {
// Don't interfere when clicking link
return;
} else if (event.button === 0) {
events.emit("gotoNextSlide");
}
});
events.on("contextmenu", function (event) {
if (event.target.nodeName === "A") {
// Don't interfere when right-clicking link
return;
}
event.preventDefault();
events.emit("gotoPreviousSlide");
});
}
if (options.scroll !== false) {
var scrollHandler = function (event) {
if (event.wheelDeltaY > 0 || event.detail < 0) {
events.emit("gotoPreviousSlide");
} else if (event.wheelDeltaY < 0 || event.detail > 0) {
events.emit("gotoNextSlide");
}
};
// IE9, Chrome, Safari, Opera
events.on("mousewheel", scrollHandler);
// Firefox
events.on("DOMMouseScroll", scrollHandler);
}
}
function removeMouseEventListeners(events) {
events.removeAllListeners("click");
events.removeAllListeners("contextmenu");
events.removeAllListeners("mousewheel");
}
}, {}],
11: [function (require, module, exports) {
exports.register = function (events, options) {
addTouchEventListeners(events, options);
};
exports.unregister = function (events) {
removeTouchEventListeners(events);
};
function addTouchEventListeners(events, options) {
var touch,
startX,
endX;
if (options.touch === false) {
return;
}
var isTap = function () {
return Math.abs(startX - endX) < 10;
};
var handleTap = function () {
events.emit("tap", endX);
};
var handleSwipe = function () {
if (startX > endX) {
events.emit("gotoNextSlide");
} else {
events.emit("gotoPreviousSlide");
}
};
events.on("touchstart", function (event) {
touch = event.touches[0];
startX = touch.clientX;
});
events.on("touchend", function (event) {
if (event.target.nodeName.toUpperCase() === "A") {
return;
}
touch = event.changedTouches[0];
endX = touch.clientX;
if (isTap()) {
handleTap();
} else {
handleSwipe();
}
});
events.on("touchmove", function (event) {
event.preventDefault();
});
}
function removeTouchEventListeners(events) {
events.removeAllListeners("touchstart");
events.removeAllListeners("touchend");
events.removeAllListeners("touchmove");
}
}, {}],
12: [function (require, module, exports) {
var marked = require("marked"),
converter = module.exports = {},
element = document.createElement("div");
marked.setOptions({
gfm: true,
tables: true,
breaks: false,
// Without this set to true, converting something like
// <p>*</p><p>*</p> will become <p><em></p><p></em></p>
pedantic: true,
sanitize: false,
smartLists: true,
langPrefix: "",
});
converter.convertMarkdown = function (content, links, inline) {
element.innerHTML = convertMarkdown(content, links || {}, inline);
element.innerHTML = element.innerHTML.replace(/<p>\s*<\/p>/g, "");
return element.innerHTML.replace(/\n\r?$/, "");
};
function convertMarkdown(content, links, insideContentClass) {
var i, tag, markdown = "", html;
for (i = 0; i < content.length; ++i) {
if (typeof content[i] === "string") {
markdown += content[i];
} else {
tag = content[i].block ? "div" : "span";
markdown += "<" + tag + ' class="' + content[i].class + '">';
markdown += convertMarkdown(
content[i].content,
links,
!content[i].block,
);
markdown += "</" + tag + ">";
}
}
var tokens = marked.Lexer.lex(markdown.replace(/^\s+/, ""));
tokens.links = links;
html = marked.Parser.parse(tokens);
if (insideContentClass) {
element.innerHTML = html;
if (
element.children.length === 1 && element.children[0].tagName === "P"
) {
html = element.children[0].innerHTML;
}
}
return html;
}
}, { "marked": 2 }],
13: [function (require, module, exports) {
module.exports = Dom;
function Dom() {}
Dom.prototype.XMLHttpRequest = XMLHttpRequest;
Dom.prototype.getHTMLElement = function () {
return document.getElementsByTagName("html")[0];
};
Dom.prototype.getBodyElement = function () {
return document.body;
};
Dom.prototype.getElementById = function (id) {
return document.getElementById(id);
};
Dom.prototype.getLocationHash = function () {
return window.location.hash;
};
Dom.prototype.setLocationHash = function (hash) {
if (
typeof window.history.replaceState === "function" &&
document.origin !== "null"
) {
window.history.replaceState(undefined, undefined, hash);
} else {
window.location.hash = hash;
}
};
}, {}],
14: [function (require, module, exports) {
/* Automatically generated */
var hljs = (function () {
var exports = {};
/*
Syntax highlighting with language autodetection.
https://highlightjs.org/
*/
(function (factory) {
// Find the global object for export to both the browser and web workers.
var globalObject = typeof window === "object" && window ||
typeof self === "object" && self;
// Setup highlight.js for different environments. First is Node.js or
// CommonJS.
if (typeof exports !== "undefined") {
factory(exports);
} else if (globalObject) {
// Export hljs globally even when using AMD for cases when this script
// is loaded with others that may still expect a global hljs.
globalObject.hljs = factory({});
// Finally register the global hljs with AMD.
if (typeof define === "function" && define.amd) {
define([], function () {
return globalObject.hljs;
});
}
}
})(function (hljs) {
// Convenience variables for build-in objects
var ArrayProto = [],
objectKeys = Object.keys;
// Global internal variables used within the highlight.js library.
var languages = {},
aliases = {};
// Regular expressions used throughout the highlight.js library.
var noHighlightRe = /^(no-?highlight|plain|text)$/i,
languagePrefixRe = /\blang(?:uage)?-([\w-]+)\b/i,
fixMarkupRe = /((^(<[^>]+>|\t|)+|(?:\n)))/gm;
var spanEndTag = "</span>";
// Global options used when within external APIs. This is modified when
// calling the `hljs.configure` function.
var options = {
classPrefix: "hljs-",
tabReplace: null,
useBR: false,
languages: undefined,
};
// Object map that is used to escape some common HTML characters.
var escapeRegexMap = {
"&": "&",
"<": "<",
">": ">",
};
/* Utility functions */
function escape(value) {
return value.replace(/[&<>]/gm, function (character) {
return escapeRegexMap[character];
});
}
function tag(node) {
return node.nodeName.toLowerCase();
}
function testRe(re, lexeme) {
var match = re && re.exec(lexeme);
return match && match.index === 0;
}
function isNotHighlighted(language) {
return noHighlightRe.test(language);
}
function blockLanguage(block) {
var i, match, length, _class;
var classes = block.className + " ";
classes += block.parentNode ? block.parentNode.className : "";
// language-* takes precedence over non-prefixed class names.
match = languagePrefixRe.exec(classes);
if (match) {
return getLanguage(match[1]) ? match[1] : "no-highlight";
}
classes = classes.split(/\s+/);
for (i = 0, length = classes.length; i < length; i++) {
_class = classes[i];
if (isNotHighlighted(_class) || getLanguage(_class)) {
return _class;
}
}
}
function inherit(parent, obj) {
var key;
var result = {};
for (key in parent) {
result[key] = parent[key];
}
if (obj) {
for (key in obj) {
result[key] = obj[key];
}
}
return result;
}
/* Stream merging */
function nodeStream(node) {
var result = [];
(function _nodeStream(node, offset) {
for (
var child = node.firstChild;
child;
child = child.nextSibling
) {
if (child.nodeType === 3) {
offset += child.nodeValue.length;
} else if (child.nodeType === 1) {
result.push({
event: "start",
offset: offset,
node: child,
});
offset = _nodeStream(child, offset);
// Prevent void elements from having an end tag that would actually
// double them in the output. There are more void elements in HTML
// but we list only those realistically expected in code display.
if (!tag(child).match(/br|hr|img|input/)) {
result.push({
event: "stop",
offset: offset,
node: child,
});
}
}
}
return offset;
})(node, 0);
return result;
}
function mergeStreams(original, highlighted, value) {
var processed = 0;
var result = "";
var nodeStack = [];
function selectStream() {
if (!original.length || !highlighted.length) {
return original.length ? original : highlighted;
}
if (original[0].offset !== highlighted[0].offset) {
return (original[0].offset < highlighted[0].offset)
? original
: highlighted;
}
/*
To avoid starting the stream just before it should stop the order is
ensured that original always starts first and closes last:
if (event1 == 'start' && event2 == 'start')
return original;
if (event1 == 'start' && event2 == 'stop')
return highlighted;
if (event1 == 'stop' && event2 == 'start')
return original;
if (event1 == 'stop' && event2 == 'stop')
return highlighted;
... which is collapsed to:
*/
return highlighted[0].event === "start"
? original
: highlighted;
}
function open(node) {
function attr_str(a) {
return " " + a.nodeName + '="' + escape(a.value) + '"';
}
result += "<" + tag(node) +
ArrayProto.map.call(node.attributes, attr_str).join("") + ">";
}
function close(node) {
result += "</" + tag(node) + ">";
}
function render(event) {
(event.event === "start" ? open : close)(event.node);
}
while (original.length || highlighted.length) {
var stream = selectStream();
result += escape(
value.substr(processed, stream[0].offset - processed),
);
processed = stream[0].offset;
if (stream === original) {
/*
On any opening or closing tag of the original markup we first close
the entire highlighted node stack, then render the original tag along
with all the following original tags at the same offset and then
reopen all the tags on the highlighted stack.
*/
nodeStack.reverse().forEach(close);
do {
render(stream.splice(0, 1)[0]);
stream = selectStream();
} while (
stream === original && stream.length &&
stream[0].offset === processed
);
nodeStack.reverse().forEach(open);
} else {
if (stream[0].event === "start") {
nodeStack.push(stream[0].node);
} else {
nodeStack.pop();
}
render(stream.splice(0, 1)[0]);
}
}
return result + escape(value.substr(processed));
}
/* Initialization */
function compileLanguage(language) {
function reStr(re) {
return (re && re.source) || re;
}
function langRe(value, global) {
return new RegExp(
reStr(value),
"m" + (language.case_insensitive ? "i" : "") +
(global ? "g" : ""),
);
}
function compileMode(mode, parent) {
if (mode.compiled) {
return;
}
mode.compiled = true;
mode.keywords = mode.keywords || mode.beginKeywords;
if (mode.keywords) {
var compiled_keywords = {};
var flatten = function (className, str) {
if (language.case_insensitive) {
str = str.toLowerCase();
}
str.split(" ").forEach(function (kw) {
var pair = kw.split("|");
compiled_keywords[pair[0]] = [
className,
pair[1] ? Number(pair[1]) : 1,
];
});
};
if (typeof mode.keywords === "string") { // string
flatten("keyword", mode.keywords);
} else {
objectKeys(mode.keywords).forEach(function (className) {
flatten(className, mode.keywords[className]);
});
}
mode.keywords = compiled_keywords;
}
mode.lexemesRe = langRe(mode.lexemes || /\w+/, true);
if (parent) {
if (mode.beginKeywords) {
mode.begin = "\\b(" +
mode.beginKeywords.split(" ").join("|") + ")\\b";
}
if (!mode.begin) {
mode.begin = /\B|\b/;
}
mode.beginRe = langRe(mode.begin);
if (!mode.end && !mode.endsWithParent) {
mode.end = /\B|\b/;
}
if (mode.end) {
mode.endRe = langRe(mode.end);
}
mode.terminator_end = reStr(mode.end) || "";
if (mode.endsWithParent && parent.terminator_end) {
mode.terminator_end += (mode.end ? "|" : "") +
parent.terminator_end;
}
}
if (mode.illegal) {
mode.illegalRe = langRe(mode.illegal);
}
if (mode.relevance == null) {
mode.relevance = 1;
}
if (!mode.contains) {
mode.contains = [];
}
var expanded_contains = [];
mode.contains.forEach(function (c) {
if (c.variants) {
c.variants.forEach(function (v) {
expanded_contains.push(inherit(c, v));
});
} else {
expanded_contains.push(c === "self" ? mode : c);
}
});
mode.contains = expanded_contains;
mode.contains.forEach(function (c) {
compileMode(c, mode);
});
if (mode.starts) {
compileMode(mode.starts, parent);
}
var terminators = mode.contains.map(function (c) {
return c.beginKeywords
? "\\.?(" + c.begin + ")\\.?"
: c.begin;
})
.concat([mode.terminator_end, mode.illegal])
.map(reStr)
.filter(Boolean);
mode.terminators = terminators.length
? langRe(terminators.join("|"), true)
: {
exec: function (/*s*/) {
return null;
},
};
}
compileMode(language);
}
/*
Core highlighting function. Accepts a language name, or an alias, and a
string with the code to highlight. Returns an object with the following
properties:
- relevance (int)
- value (an HTML string with highlighting markup)
*/
function highlight(name, value, ignore_illegals, continuation) {
function subMode(lexeme, mode) {
var i, length;
for (i = 0, length = mode.contains.length; i < length; i++) {
if (testRe(mode.contains[i].beginRe, lexeme)) {
return mode.contains[i];
}
}
}
function endOfMode(mode, lexeme) {
if (testRe(mode.endRe, lexeme)) {
while (mode.endsParent && mode.parent) {
mode = mode.parent;
}
return mode;
}
if (mode.endsWithParent) {
return endOfMode(mode.parent, lexeme);
}
}
function isIllegal(lexeme, mode) {
return !ignore_illegals && testRe(mode.illegalRe, lexeme);
}
function keywordMatch(mode, match) {
var match_str = language.case_insensitive
? match[0].toLowerCase()
: match[0];
return mode.keywords.hasOwnProperty(match_str) &&
mode.keywords[match_str];
}
function buildSpan(classname, insideSpan, leaveOpen, noPrefix) {
var classPrefix = noPrefix ? "" : options.classPrefix,
openSpan = '<span class="' + classPrefix,
closeSpan = leaveOpen ? "" : spanEndTag;
openSpan += classname + '">';
return openSpan + insideSpan + closeSpan;
}
function processKeywords() {
var keyword_match, last_index, match, result;
if (!top.keywords) {
return escape(mode_buffer);
}
result = "";
last_index = 0;
top.lexemesRe.lastIndex = 0;
match = top.lexemesRe.exec(mode_buffer);
while (match) {
result += escape(
mode_buffer.substr(last_index, match.index - last_index),
);
keyword_match = keywordMatch(top, match);
if (keyword_match) {
relevance += keyword_match[1];
result += buildSpan(keyword_match[0], escape(match[0]));
} else {
result += escape(match[0]);
}
last_index = top.lexemesRe.lastIndex;
match = top.lexemesRe.exec(mode_buffer);
}
return result + escape(mode_buffer.substr(last_index));
}
function processSubLanguage() {
var explicit = typeof top.subLanguage === "string";
if (explicit && !languages[top.subLanguage]) {
return escape(mode_buffer);
}
var result = explicit
? highlight(
top.subLanguage,
mode_buffer,
true,
continuations[top.subLanguage],
)
: highlightAuto(
mode_buffer,
top.subLanguage.length ? top.subLanguage : undefined,
);
// Counting embedded language score towards the host language may be disabled
// with zeroing the containing mode relevance. Usecase in point is Markdown that
// allows XML everywhere and makes every XML snippet to have a much larger Markdown
// score.
if (top.relevance > 0) {
relevance += result.relevance;
}
if (explicit) {
continuations[top.subLanguage] = result.top;
}
return buildSpan(result.language, result.value, false, true);
}
function processBuffer() {
result += top.subLanguage != null
? processSubLanguage()
: processKeywords();
mode_buffer = "";
}
function startNewMode(mode) {
result += mode.className
? buildSpan(mode.className, "", true)
: "";
top = Object.create(mode, { parent: { value: top } });
}
function processLexeme(buffer, lexeme) {
mode_buffer += buffer;
if (lexeme == null) {
processBuffer();
return 0;
}
var new_mode = subMode(lexeme, top);
if (new_mode) {
if (new_mode.skip) {
mode_buffer += lexeme;
} else {
if (new_mode.excludeBegin) {
mode_buffer += lexeme;
}
processBuffer();
if (!new_mode.returnBegin && !new_mode.excludeBegin) {
mode_buffer = lexeme;
}
}
startNewMode(new_mode, lexeme);
return new_mode.returnBegin ? 0 : lexeme.length;
}
var end_mode = endOfMode(top, lexeme);
if (end_mode) {
var origin = top;
if (origin.skip) {
mode_buffer += lexeme;
} else {
if (!(origin.returnEnd || origin.excludeEnd)) {
mode_buffer += lexeme;
}
processBuffer();
if (origin.excludeEnd) {
mode_buffer = lexeme;
}
}
do {
if (top.className) {
result += spanEndTag;
}
if (!top.skip) {
relevance += top.relevance;
}
top = top.parent;
} while (top !== end_mode.parent);
if (end_mode.starts) {
startNewMode(end_mode.starts, "");
}
return origin.returnEnd ? 0 : lexeme.length;
}
if (isIllegal(lexeme, top)) {
throw new Error(
'Illegal lexeme "' + lexeme + '" for mode "' +
(top.className || "<unnamed>") + '"',
);
}
/*
Parser should not reach this point as all types of lexemes should be caught
earlier, but if it does due to some bug make sure it advances at least one
character forward to prevent infinite looping.
*/
mode_buffer += lexeme;
return lexeme.length || 1;
}
var language = getLanguage(name);
if (!language) {
throw new Error('Unknown language: "' + name + '"');
}
compileLanguage(language);
var top = continuation || language;
var continuations = {}; // keep continuations for sub-languages
var result = "", current;
for (
current = top;
current !== language;
current = current.parent
) {
if (current.className) {
result = buildSpan(current.className, "", true) + result;
}
}
var mode_buffer = "";
var relevance = 0;
try {
var match, count, index = 0;
while (true) {
top.terminators.lastIndex = index;
match = top.terminators.exec(value);
if (!match) {
break;
}
count = processLexeme(
value.substr(index, match.index - index),
match[0],
);
index = match.index + count;
}
processLexeme(value.substr(index));
for (current = top; current.parent; current = current.parent) { // close dangling modes
if (current.className) {
result += spanEndTag;
}
}
return {
relevance: relevance,
value: result,
language: name,
top: top,
};
} catch (e) {
if (e.message && e.message.indexOf("Illegal") !== -1) {
return {
relevance: 0,
value: escape(value),
};
} else {
throw e;
}
}
}
/*
Highlighting with language detection. Accepts a string with the code to
highlight. Returns an object with the following properties:
- language (detected language)
- relevance (int)
- value (an HTML string with highlighting markup)
- second_best (object with the same structure for second-best heuristically
detected language, may be absent)
*/
function highlightAuto(text, languageSubset) {
languageSubset = languageSubset || options.languages ||
objectKeys(languages);
var result = {
relevance: 0,
value: escape(text),
};
var second_best = result;
languageSubset.filter(getLanguage).forEach(function (name) {
var current = highlight(name, text, false);
current.language = name;
if (current.relevance > second_best.relevance) {
second_best = current;
}
if (current.relevance > result.relevance) {
second_best = result;
result = current;
}
});
if (second_best.language) {
result.second_best = second_best;
}
return result;
}
/*
Post-processing of the highlighted markup:
- replace TABs with something more useful
- replace real line-breaks with '<br>' for non-pre containers
*/
function fixMarkup(value) {
return !(options.tabReplace || options.useBR)
? value
: value.replace(fixMarkupRe, function (match, p1) {
if (options.useBR && match === "\n") {
return "<br>";
} else if (options.tabReplace) {
return p1.replace(/\t/g, options.tabReplace);
}
});
}
function buildClassName(prevClassName, currentLang, resultLang) {
var language = currentLang ? aliases[currentLang] : resultLang,
result = [prevClassName.trim()];
if (!prevClassName.match(/\bhljs\b/)) {
result.push("hljs");
}
if (prevClassName.indexOf(language) === -1) {
result.push(language);
}
return result.join(" ").trim();
}
/*
Applies highlighting to a DOM node containing code. Accepts a DOM node and
two optional parameters for fixMarkup.
*/
function highlightBlock(block) {
var node, originalStream, result, resultNode, text;
var language = blockLanguage(block);
if (isNotHighlighted(language)) {
return;
}
if (options.useBR) {
node = document.createElementNS(
"http://www.w3.org/1999/xhtml",
"div",
);
node.innerHTML = block.innerHTML.replace(/\n/g, "").replace(
/<br[ \/]*>/g,
"\n",
);
} else {
node = block;
}
text = node.textContent;
result = language
? highlight(language, text, true)
: highlightAuto(text);
originalStream = nodeStream(node);
if (originalStream.length) {
resultNode = document.createElementNS(
"http://www.w3.org/1999/xhtml",
"div",
);
resultNode.innerHTML = result.value;
result.value = mergeStreams(
originalStream,
nodeStream(resultNode),
text,
);
}
result.value = fixMarkup(result.value);
block.innerHTML = result.value;
block.className = buildClassName(
block.className,
language,
result.language,
);
block.result = {
language: result.language,
re: result.relevance,
};
if (result.second_best) {
block.second_best = {
language: result.second_best.language,
re: result.second_best.relevance,
};
}
}
/*
Updates highlight.js global options with values passed in the form of an object.
*/
function configure(user_options) {
options = inherit(options, user_options);
}
/*
Applies highlighting to all <pre><code>..</code></pre> blocks on a page.
*/
function initHighlighting() {
if (initHighlighting.called) {
return;
}
initHighlighting.called = true;
var blocks = document.querySelectorAll("pre code");
ArrayProto.forEach.call(blocks, highlightBlock);
}
/*
Attaches highlighting to the page load event.
*/
function initHighlightingOnLoad() {
addEventListener("DOMContentLoaded", initHighlighting, false);
addEventListener("load", initHighlighting, false);
}
function registerLanguage(name, language) {
var lang = languages[name] = language(hljs);
if (lang.aliases) {
lang.aliases.forEach(function (alias) {
aliases[alias] = name;
});
}
}
function listLanguages() {
return objectKeys(languages);
}
function getLanguage(name) {
name = (name || "").toLowerCase();
return languages[name] || languages[aliases[name]];
}
/* Interface definition */
hljs.highlight = highlight;
hljs.highlightAuto = highlightAuto;
hljs.fixMarkup = fixMarkup;
hljs.highlightBlock = highlightBlock;
hljs.configure = configure;
hljs.initHighlighting = initHighlighting;
hljs.initHighlightingOnLoad = initHighlightingOnLoad;
hljs.registerLanguage = registerLanguage;
hljs.listLanguages = listLanguages;
hljs.getLanguage = getLanguage;
hljs.inherit = inherit;
// Common regexps
hljs.IDENT_RE = "[a-zA-Z]\\w*";
hljs.UNDERSCORE_IDENT_RE = "[a-zA-Z_]\\w*";
hljs.NUMBER_RE = "\\b\\d+(\\.\\d+)?";
hljs.C_NUMBER_RE =
"(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)"; // 0x..., 0..., decimal, float
hljs.BINARY_NUMBER_RE = "\\b(0b[01]+)"; // 0b...
hljs.RE_STARTERS_RE =
"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";
// Common modes
hljs.BACKSLASH_ESCAPE = {
begin: "\\\\[\\s\\S]",
relevance: 0,
};
hljs.APOS_STRING_MODE = {
className: "string",
begin: "'",
end: "'",
illegal: "\\n",
contains: [hljs.BACKSLASH_ESCAPE],
};
hljs.QUOTE_STRING_MODE = {
className: "string",
begin: '"',
end: '"',
illegal: "\\n",
contains: [hljs.BACKSLASH_ESCAPE],
};
hljs.PHRASAL_WORDS_MODE = {
begin:
/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|like)\b/,
};
hljs.COMMENT = function (begin, end, inherits) {
var mode = hljs.inherit(
{
className: "comment",
begin: begin,
end: end,
contains: [],
},
inherits || {},
);
mode.contains.push(hljs.PHRASAL_WORDS_MODE);
mode.contains.push({
className: "doctag",
begin: "(?:TODO|FIXME|NOTE|BUG|XXX):",
relevance: 0,
});
return mode;
};
hljs.C_LINE_COMMENT_MODE = hljs.COMMENT("//", "$");
hljs.C_BLOCK_COMMENT_MODE = hljs.COMMENT("/\\*", "\\*/");
hljs.HASH_COMMENT_MODE = hljs.COMMENT("#", "$");
hljs.NUMBER_MODE = {
className: "number",
begin: hljs.NUMBER_RE,
relevance: 0,
};
hljs.C_NUMBER_MODE = {
className: "number",
begin: hljs.C_NUMBER_RE,
relevance: 0,
};
hljs.BINARY_NUMBER_MODE = {
className: "number",
begin: hljs.BINARY_NUMBER_RE,
relevance: 0,
};
hljs.CSS_NUMBER_MODE = {
className: "number",
begin: hljs.NUMBER_RE + "(" +
"%|em|ex|ch|rem" +
"|vw|vh|vmin|vmax" +
"|cm|mm|in|pt|pc|px" +
"|deg|grad|rad|turn" +
"|s|ms" +
"|Hz|kHz" +
"|dpi|dpcm|dppx" +
")?",
relevance: 0,
};
hljs.REGEXP_MODE = {
className: "regexp",
begin: /\//,
end: /\/[gimuy]*/,
illegal: /\n/,
contains: [
hljs.BACKSLASH_ESCAPE,
{
begin: /\[/,
end: /\]/,
relevance: 0,
contains: [hljs.BACKSLASH_ESCAPE],
},
],
};
hljs.TITLE_MODE = {
className: "title",
begin: hljs.IDENT_RE,
relevance: 0,
};
hljs.UNDERSCORE_TITLE_MODE = {
className: "title",
begin: hljs.UNDERSCORE_IDENT_RE,
relevance: 0,
};
hljs.METHOD_GUARD = {
// excludes method names from keyword processing
begin: "\\.\\s*" + hljs.UNDERSCORE_IDENT_RE,
relevance: 0,
};
return hljs;
});
return exports;
}()),
languages = [{
name: "lisp",
create: /*
Language: Lisp
Description: Generic lisp syntax
Author: Vasily Polovnyov <vast@whiteants.net>
Category: lisp
*/
function (hljs) {
var LISP_IDENT_RE =
"[a-zA-Z_\\-\\+\\*\\/\\<\\=\\>\\&\\#][a-zA-Z0-9_\\-\\+\\*\\/\\<\\=\\>\\&\\#!]*";
var MEC_RE = "\\|[^]*?\\|";
var LISP_SIMPLE_NUMBER_RE =
"(\\-|\\+)?\\d+(\\.\\d+|\\/\\d+)?((d|e|f|l|s|D|E|F|L|S)(\\+|\\-)?\\d+)?";
var SHEBANG = {
className: "meta",
begin: "^#!",
end: "$",
};
var LITERAL = {
className: "literal",
begin: "\\b(t{1}|nil)\\b",
};
var NUMBER = {
className: "number",
variants: [
{ begin: LISP_SIMPLE_NUMBER_RE, relevance: 0 },
{ begin: "#(b|B)[0-1]+(/[0-1]+)?" },
{ begin: "#(o|O)[0-7]+(/[0-7]+)?" },
{ begin: "#(x|X)[0-9a-fA-F]+(/[0-9a-fA-F]+)?" },
{
begin: "#(c|C)\\(" + LISP_SIMPLE_NUMBER_RE + " +" +
LISP_SIMPLE_NUMBER_RE,
end: "\\)",
},
],
};
var STRING = hljs.inherit(hljs.QUOTE_STRING_MODE, {
illegal: null,
});
var COMMENT = hljs.COMMENT(
";",
"$",
{
relevance: 0,
},
);
var VARIABLE = {
begin: "\\*",
end: "\\*",
};
var KEYWORD = {
className: "symbol",
begin: "[:&]" + LISP_IDENT_RE,
};
var IDENT = {
begin: LISP_IDENT_RE,
relevance: 0,
};
var MEC = {
begin: MEC_RE,
};
var QUOTED_LIST = {
begin: "\\(",
end: "\\)",
contains: ["self", LITERAL, STRING, NUMBER, IDENT],
};
var QUOTED = {
contains: [
NUMBER,
STRING,
VARIABLE,
KEYWORD,
QUOTED_LIST,
IDENT,
],
variants: [
{
begin: "['`]\\(",
end: "\\)",
},
{
begin: "\\(quote ",
end: "\\)",
keywords: { name: "quote" },
},
{
gitextract_o9ditkzz/
├── .bmp.yml
├── .editorconfig
├── .github/
│ └── workflows/
│ └── ci.yml
├── .gitignore
├── LICENSE
├── README.md
├── assets/
│ ├── default.css
│ └── help-message.txt
├── examples/
│ ├── add-scripts/
│ │ ├── bar.css
│ │ ├── baz.js
│ │ ├── foo.css
│ │ ├── qux.js
│ │ ├── remarker.yml
│ │ └── slides.md
│ ├── favicon/
│ │ ├── remarker.yml
│ │ └── slides.md
│ ├── has-assets/
│ │ └── slides.md
│ ├── latex-mathjax/
│ │ ├── remarker.yml
│ │ └── slides.md
│ ├── livereload-false/
│ │ ├── remarker.yml
│ │ └── slides.md
│ ├── livereload-port/
│ │ ├── remarker.yml
│ │ └── slides.md
│ ├── metatags/
│ │ ├── README.md
│ │ ├── my-slides-2.md
│ │ ├── my-slides.md
│ │ ├── remarker.yml
│ │ └── slides.md
│ ├── remark/
│ │ ├── README.md
│ │ ├── remarker.yml
│ │ └── slides.md
│ ├── replace-remark/
│ │ ├── my-own-remark.js
│ │ ├── remarker.yml
│ │ └── slides.md
│ └── simple/
│ ├── README.md
│ ├── my-slides-2.md
│ ├── my-slides.md
│ └── slides.md
├── index.js
├── layout.njk
├── package.json
├── test.js
└── vendor/
├── livereload.js
└── remark.js
SYMBOL INDEX (116 symbols across 2 files)
FILE: vendor/livereload.js
function s (line 2) | function s(o, u) {
function Connector (line 45) | function Connector(options, WebSocket, Timer, handlers) {
function LessPlugin (line 272) | function LessPlugin(window, host) {
function LiveReload (line 352) | function LiveReload(window) {
function Options (line 614) | function Options() {
function ProtocolError (line 713) | function ProtocolError(reason, data) {
function Parser (line 722) | function Parser(handlers) {
function Reloader (line 918) | function Reloader(window, console, Timer) {
function Timer (line 1453) | function Timer(func) {
FILE: vendor/remark.js
function s (line 2) | function s(o, u) {
function EventEmitter (line 55) | function EventEmitter() {
function g (line 210) | function g() {
function isFunction (line 351) | function isFunction(arg) {
function isNumber (line 355) | function isNumber(arg) {
function isObject (line 359) | function isObject(arg) {
function isUndefined (line 363) | function isUndefined(arg) {
function Lexer (line 464) | function Lexer(options) {
function InlineLexer (line 874) | function InlineLexer(links, options) {
function Renderer (line 1098) | function Renderer(options) {
function Parser (line 1241) | function Parser(options) {
function escape (line 1430) | function escape(html, encode) {
function unescape (line 1439) | function unescape(html) {
function replace (line 1452) | function replace(regex, opt) {
function noop (line 1464) | function noop() {}
function merge (line 1467) | function merge(obj) {
function marked (line 1488) | function marked(src, opt, callback) {
function forEach (line 1640) | function forEach(list, f) {
function extend (line 1648) | function extend(object) {
function Api (line 1714) | function Api(dom) {
function applyDefaults (line 1771) | function applyDefaults(dom, options) {
function unescape (line 1791) | function unescape(source) {
function Controller (line 1825) | function Controller(events, dom, slideshowView, options) {
function addApiEventListeners (line 1838) | function addApiEventListeners(events, keyboard, slideshowView, options) {
function Keyboard (line 1861) | function Keyboard(events) {
function addLocationEventListeners (line 1984) | function addLocationEventListeners(events, dom, slideshowView) {
function addMessageEventListeners (line 2024) | function addMessageEventListeners(events) {
function addMouseEventListeners (line 2047) | function addMouseEventListeners(events, options) {
function removeMouseEventListeners (line 2083) | function removeMouseEventListeners(events) {
function addTouchEventListeners (line 2098) | function addTouchEventListeners(events, options) {
function removeTouchEventListeners (line 2148) | function removeTouchEventListeners(events) {
function convertMarkdown (line 2179) | function convertMarkdown(content, links, insideContentClass) {
function Dom (line 2216) | function Dom() {}
function escape (line 2312) | function escape(value) {
function tag (line 2318) | function tag(node) {
function testRe (line 2322) | function testRe(re, lexeme) {
function isNotHighlighted (line 2327) | function isNotHighlighted(language) {
function blockLanguage (line 2331) | function blockLanguage(block) {
function inherit (line 2354) | function inherit(parent, obj) {
function nodeStream (line 2371) | function nodeStream(node) {
function mergeStreams (line 2405) | function mergeStreams(original, highlighted, value) {
function compileLanguage (line 2492) | function compileLanguage(language) {
function highlight (line 2617) | function highlight(name, value, ignore_illegals, continuation) {
function highlightAuto (line 2875) | function highlightAuto(text, languageSubset) {
function fixMarkup (line 2907) | function fixMarkup(value) {
function buildClassName (line 2919) | function buildClassName(prevClassName, currentLang, resultLang) {
function highlightBlock (line 2938) | function highlightBlock(block) {
function configure (line 2999) | function configure(user_options) {
function initHighlighting (line 3006) | function initHighlighting() {
function initHighlightingOnLoad (line 3019) | function initHighlightingOnLoad() {
function registerLanguage (line 3024) | function registerLanguage(name, language) {
function listLanguages (line 3033) | function listLanguages() {
function getLanguage (line 3037) | function getLanguage(name) {
function recursiveParen (line 6186) | function recursiveParen(begin, end) {
function Lexer (line 20295) | function Lexer() {}
function lex (line 20311) | function lex(src, regex, tokens) {
function replace (line 20406) | function replace(regex, replacements) {
function trim (line 20412) | function trim(text) {
function getTextInBrackets (line 20420) | function getTextInBrackets(src, offset) {
function Slide (line 20448) | function Slide(slideIndex, slide, template) {
function inherit (line 20465) | function inherit(slide, template) {
function inheritProperties (line 20471) | function inheritProperties(slide, template) {
function ignoreProperty (line 20497) | function ignoreProperty(property) {
function inheritContent (line 20503) | function inheritContent(slide, template) {
function inheritNotes (line 20518) | function inheritNotes(slide, template) {
function expand (line 20546) | function expand(match, escaped, unescapedMatch, property) {
function Slideshow (line 20581) | function Slideshow(events, dom, options, callback) {
function createSlides (line 20742) | function createSlides(slideshowSource, options) {
function expandVariables (line 20793) | function expandVariables(slides) {
function Events (line 20811) | function Events(events) {
function Navigation (line 20841) | function Navigation(events) {
function Parser (line 21000) | function Parser() {}
function createSlide (line 21135) | function createSlide() {
function createContentClass (line 21145) | function createContentClass(token) {
function appendTo (line 21153) | function appendTo(element, content) {
function extractProperties (line 21172) | function extractProperties(source, properties) {
function cleanInput (line 21193) | function cleanInput(source) {
function Scaler (line 21242) | function Scaler(events, slideshow) {
function getRatio (line 21289) | function getRatio(slideshow) {
function getDimensions (line 21303) | function getDimensions(ratio) {
function NotesView (line 21364) | function NotesView(events, element, slideViewsAccessor) {
function SlideView (line 21448) | function SlideView(events, slideshow, scaler, slide) {
function createContentElement (line 21591) | function createContentElement(events, slideshow, slide) {
function styleContentElement (line 21610) | function styleContentElement(slideshow, element, properties) {
function createNotesElement (line 21618) | function createNotesElement(slideshow, notes) {
function setBackgroundFromProperties (line 21630) | function setBackgroundFromProperties(element, properties) {
function setHighlightStyleFromProperties (line 21650) | function setHighlightStyleFromProperties(element, properties, slideshow) {
function setClassFromProperties (line 21659) | function setClassFromProperties(element, properties) {
function highlightCodeBlocks (line 21671) | function highlightCodeBlocks(content, slideshow) {
function extractMetadata (line 21713) | function extractMetadata(block) {
function wrapLines (line 21732) | function wrapLines(block) {
function highlightBlockLines (line 21745) | function highlightBlockLines(block, lines) {
function highlightBlockSpans (line 21751) | function highlightBlockSpans(block) {
function SlideshowView (line 21784) | function SlideshowView(events, dom, containerElement, slideshow) {
function handleFullscreen (line 21873) | function handleFullscreen(self) {
function forwardEvents (line 21958) | function forwardEvents(target, source, events) {
function onResize (line 22009) | function onResize() {
function onPrint (line 22013) | function onPrint(e) {
function PrintComponent (line 22140) | function PrintComponent() {}
function SlideNumberViewModel (line 22198) | function SlideNumberViewModel(slide, slideshow) {
function formatSlideNumber (line 22209) | function formatSlideNumber(slide, slideshow) {
function getSlideNo (line 22224) | function getSlideNo(slide, slideshow) {
function styleDocument (line 22246) | function styleDocument() {
function setPageSize (line 22276) | function setPageSize(size) {
function getRemarkStylesheet (line 22284) | function getRemarkStylesheet() {
function getPageRule (line 22295) | function getPageRule(stylesheet) {
function TimerViewModel (line 22310) | function TimerViewModel(events, element) {
Condensed preview — 44 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,313K chars).
[
{
"path": ".bmp.yml",
"chars": 120,
"preview": "version: 1.15.0\ncommit: Bump to version v%.%.%\nfiles:\n README.md: remarker v%.%.%\n package.json: '\"version\": \"%.%.%\"'\n"
},
{
"path": ".editorconfig",
"chars": 103,
"preview": "root=true\n[*]\nindent_style=space\nindent_size=2\ntrim_trailing_whitespace=true\ninsert_final_newline=true\n"
},
{
"path": ".github/workflows/ci.yml",
"chars": 352,
"preview": "name: ci\non:\n push:\n branches: [main]\n pull_request:\n branches: [main]\njobs:\n build:\n runs-on: ubuntu-latest"
},
{
"path": ".gitignore",
"chars": 109,
"preview": "# npm\n/node_modules\n\n# Sorry, npm. We prefer yarn.lock\n/package-lock.json\n\n# coverage\n/coverage\n/.nyc_output\n"
},
{
"path": "LICENSE",
"chars": 1084,
"preview": "The MIT License\nCopyright © 2016 Yoshiya Hinosawa ( @kt3k )\n\nPermission is hereby granted, free of charge, to any person"
},
{
"path": "README.md",
"chars": 7427,
"preview": "# remarker v1.15.0\n\n[](https://github.com/kt3k"
},
{
"path": "assets/default.css",
"chars": 314,
"preview": "body {\n font-family: 'Avenir Next', 'Hiragino Kaku Gothic ProN', 'Meiryo', 'メイリオ', sans-serif;\n}\nh1, h2, h3 {\n font-we"
},
{
"path": "assets/help-message.txt",
"chars": 813,
"preview": "\nUsage:\n remarker [options] serve Serves all the assets at localhost\n remarker [options] build Builds all th"
},
{
"path": "examples/add-scripts/bar.css",
"chars": 0,
"preview": ""
},
{
"path": "examples/add-scripts/baz.js",
"chars": 0,
"preview": ""
},
{
"path": "examples/add-scripts/foo.css",
"chars": 0,
"preview": ""
},
{
"path": "examples/add-scripts/qux.js",
"chars": 0,
"preview": ""
},
{
"path": "examples/add-scripts/remarker.yml",
"chars": 137,
"preview": "cssFiles:\n - foo.css\n - bar.css\n - https://example.com/style.css\nscriptFiles:\n - baz.js\n - qux.js\n - https://examp"
},
{
"path": "examples/add-scripts/slides.md",
"chars": 21,
"preview": "# add script example\n"
},
{
"path": "examples/favicon/remarker.yml",
"chars": 24,
"preview": "assets:\n - favicon.ico\n"
},
{
"path": "examples/favicon/slides.md",
"chars": 234,
"preview": "class: center, middle\n\n# My Awesome Presentation\n\nThis is my-slides.md\n\n---\n\n# Agenda\n\n1. Introduction\n2. Deep-dive\n3. ."
},
{
"path": "examples/has-assets/slides.md",
"chars": 247,
"preview": "class: center, middle\n\n# My Awesome Presentation\n\n???\n\nNotes for the _first_ slide!\n\n---\n\n# Agenda\n\n1. Introduction\n2. D"
},
{
"path": "examples/latex-mathjax/remarker.yml",
"chars": 271,
"preview": "scriptFiles:\n - https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS_HTML&delayStartupUntil"
},
{
"path": "examples/latex-mathjax/slides.md",
"chars": 1627,
"preview": "class: center, middle\n\n# Configuring remarker to display LaTeX via MathJax\n\nMichael Liebling\n\n26 September 2019\n\nThis is"
},
{
"path": "examples/livereload-false/remarker.yml",
"chars": 18,
"preview": "livereload: false\n"
},
{
"path": "examples/livereload-false/slides.md",
"chars": 6,
"preview": "# hey\n"
},
{
"path": "examples/livereload-port/remarker.yml",
"chars": 22,
"preview": "livereloadPort: 12345\n"
},
{
"path": "examples/livereload-port/slides.md",
"chars": 53,
"preview": "# demo of livereloading in different port\n\ntest test\n"
},
{
"path": "examples/metatags/README.md",
"chars": 77,
"preview": "run:\n\n node ../../index.js\n\nand slides are up at `http://localhost:6275/`\n"
},
{
"path": "examples/metatags/my-slides-2.md",
"chars": 236,
"preview": "class: center, middle\n\n# My Awesome Presentation\n\nThis is my-slides-2.md\n\n---\n\n# Agenda\n\n1. Introduction\n2. Deep-dive\n3."
},
{
"path": "examples/metatags/my-slides.md",
"chars": 234,
"preview": "class: center, middle\n\n# My Awesome Presentation\n\nThis is my-slides.md\n\n---\n\n# Agenda\n\n1. Introduction\n2. Deep-dive\n3. ."
},
{
"path": "examples/metatags/remarker.yml",
"chars": 251,
"preview": "title: Example slides\ndescription: This is example slides\nogImage: https://avatars.githubusercontent.com/kt3k\nogImageWid"
},
{
"path": "examples/metatags/slides.md",
"chars": 263,
"preview": "class: center, middle\n\n# My Awesome Presentation\n\n???\n\nNotes for the _first_ slide!\n\n---\n\n# Agenda\n\n1. Introduction :mag"
},
{
"path": "examples/remark/README.md",
"chars": 77,
"preview": "run:\n\n node ../../index.js\n\nand slides are up at `http://localhost:6275/`\n"
},
{
"path": "examples/remark/remarker.yml",
"chars": 2546,
"preview": "remarkConfig:\n highlightStyle: monokai\n highlightLanguage: remark\n highlightLines: true\nassets:\n - unknown-assets\n "
},
{
"path": "examples/remark/slides.md",
"chars": 7506,
"preview": "name: inverse\n\n## layout: true class: center, middle, inverse\n\n## #remark [ri-mahrk] .footnote[Go directly to [project s"
},
{
"path": "examples/replace-remark/my-own-remark.js",
"chars": 26,
"preview": "console.log(\"remark.js\");\n"
},
{
"path": "examples/replace-remark/remarker.yml",
"chars": 68,
"preview": "remarkPath: my-own-remark.js\nscript: console.log(\"injected script\")\n"
},
{
"path": "examples/replace-remark/slides.md",
"chars": 36,
"preview": "Slide 0\n\n---\n\nSlide 1\n\n---\n\nSlide 2\n"
},
{
"path": "examples/simple/README.md",
"chars": 77,
"preview": "run:\n\n node ../../index.js\n\nand slides are up at `http://localhost:6275/`\n"
},
{
"path": "examples/simple/my-slides-2.md",
"chars": 236,
"preview": "class: center, middle\n\n# My Awesome Presentation\n\nThis is my-slides-2.md\n\n---\n\n# Agenda\n\n1. Introduction\n2. Deep-dive\n3."
},
{
"path": "examples/simple/my-slides.md",
"chars": 234,
"preview": "class: center, middle\n\n# My Awesome Presentation\n\nThis is my-slides.md\n\n---\n\n# Agenda\n\n1. Introduction\n2. Deep-dive\n3. ."
},
{
"path": "examples/simple/slides.md",
"chars": 263,
"preview": "class: center, middle\n\n# My Awesome Presentation\n\n???\n\nNotes for the _first_ slide!\n\n---\n\n# Agenda\n\n1. Introduction :mag"
},
{
"path": "index.js",
"chars": 5762,
"preview": "#!/usr/bin/env node\n\nconst {\n asset,\n dest,\n name,\n on,\n port,\n debugPagePath,\n helpMessage,\n loggerTitle,\n add"
},
{
"path": "layout.njk",
"chars": 2552,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <title>{{ title }}</title>\n <meta http-equiv=\"Content-Type\" content=\"text/html; c"
},
{
"path": "package.json",
"chars": 1310,
"preview": "{\n \"name\": \"remarker\",\n \"version\": \"1.15.0\",\n \"description\": \"Remark cli\",\n \"main\": \"index.js\",\n \"bin\": \"index.js\","
},
{
"path": "test.js",
"chars": 6061,
"preview": "const { before, after, describe, it, context, timeout } = require(\"kocha\");\nconst { expect } = require(\"chai\");\nconst { "
},
{
"path": "vendor/livereload.js",
"chars": 50884,
"preview": "(function e(t, n, r) {\n function s(o, u) {\n if (!n[o]) {\n if (!t[o]) {\n var a = typeof require == \"funct"
},
{
"path": "vendor/remark.js",
"chars": 1168536,
"preview": "require = (function e(t, n, r) {\n function s(o, u) {\n if (!n[o]) {\n if (!t[o]) {\n var a = typeof require"
}
]
About this extraction
This page contains the full source code of the kt3k/remarker GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 44 files (1.2 MB), approximately 280.0k tokens, and a symbol index with 116 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.