├── .github ├── FUNDING.yml └── workflows │ └── ci.yml ├── .gitignore ├── .gitmodules ├── .hgignore ├── .travis.yml ├── BLUETRIP-LICENSE ├── CHANGES ├── HCAR-gitit.tex ├── LICENSE ├── Makefile ├── README.markdown ├── RELANN-0.6.1 ├── Setup.lhs ├── TANGOICONS ├── YUI-LICENSE ├── cabal.project ├── data ├── FrontPage.page ├── Help.page ├── Paths_gitit.hs ├── default.conf ├── markup.DocBook ├── markup.HTML ├── markup.LaTeX ├── markup.Markdown ├── markup.Org ├── markup.RST ├── markup.Textile ├── markupHelp │ ├── HTML │ ├── LaTeX │ ├── LaTeX+LHS │ ├── Markdown │ ├── Markdown+LHS │ ├── Org │ ├── RST │ └── RST+LHS ├── post-update ├── s5 │ └── default │ │ ├── blank.gif │ │ ├── bodybg.gif │ │ ├── framing.css │ │ ├── iepngfix.htc │ │ ├── opera.css │ │ ├── outline.css │ │ ├── pretty.css │ │ ├── print.css │ │ ├── s5-core.css │ │ ├── slides.css │ │ ├── slides.js │ │ └── slides.min.js ├── static │ ├── css │ │ ├── custom.css │ │ ├── highlighting.css │ │ ├── ie.css │ │ ├── print.css │ │ ├── reset-fonts-grids.css │ │ └── screen.css │ ├── img │ │ ├── icons │ │ │ ├── feed.png │ │ │ ├── folder.png │ │ │ └── page.png │ │ ├── lambda-bann.png │ │ └── logo.png │ ├── js │ │ ├── MathMLinHTML.js │ │ ├── dragdiff.js │ │ ├── footnotes.js │ │ ├── jquery-1.2.6.js │ │ ├── jquery-1.2.6.min.js │ │ ├── jquery-ui-combined-1.6rc2.min.js │ │ ├── jquery-ui.core-1.6rc2.js │ │ ├── jquery-ui.draggable-1.6rc2.js │ │ ├── jquery-ui.droppable-1.6rc2.js │ │ ├── jquery-ui.tabs-1.6rc2.js │ │ ├── jquery.hotkeys-0.7.9.js │ │ ├── jquery.hotkeys-0.7.9.min.js │ │ ├── preview.js │ │ ├── search.js │ │ └── uploadForm.js │ └── robots.txt └── templates │ ├── content.st │ ├── expire.st │ ├── footer.st │ ├── getuser.st │ ├── listitem.st │ ├── logo.st │ ├── markuphelp.st │ ├── messages.st │ ├── page.st │ ├── pagetools.st │ ├── sitenav.st │ └── userbox.st ├── expireGititCache.hs ├── gitit.cabal ├── gitit.hs ├── plugins ├── CapitalizeEmphasis.hs ├── Deprofanizer.hs ├── Dot.hs ├── ImgTex.hs ├── Interwiki.hs ├── MTable.hs ├── PigLatin.hs ├── ShowUser.hs ├── Signature.hs ├── Subst.hs ├── WebArchiver.hs └── WebArchiverBot.hs ├── src └── Network │ ├── Gitit.hs │ └── Gitit │ ├── Authentication.hs │ ├── Authentication │ └── Github.hs │ ├── Cache.hs │ ├── Compat │ └── Except.hs │ ├── Config.hs │ ├── ContentTransformer.hs │ ├── Feed.hs │ ├── Framework.hs │ ├── Handlers.hs │ ├── Initialize.hs │ ├── Interface.hs │ ├── Layout.hs │ ├── Page.hs │ ├── Plugins.hs │ ├── Server.hs │ ├── State.hs │ ├── Types.hs │ └── Util.hs └── stack.yaml /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [jgm] 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | linux: 7 | 8 | runs-on: ubuntu-latest 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | versions: 13 | - ghc: '9.0' 14 | cabal: '3.8' 15 | - ghc: '9.2' 16 | cabal: '3.10' 17 | - ghc: '9.4' 18 | cabal: '3.10' 19 | - ghc: '9.6' 20 | cabal: 'latest' 21 | - ghc: '9.8' 22 | cabal: 'latest' 23 | steps: 24 | - uses: actions/checkout@v1 25 | - name: Install cabal/ghc 26 | run: | 27 | ghcup install ghc --set ${{ matrix.versions.ghc }} 28 | ghcup install cabal --set ${{ matrix.versions.cabal }} 29 | 30 | - name: Cache cabal global package db 31 | id: cabal-global 32 | uses: actions/cache@v3 33 | with: 34 | path: | 35 | ~/.cabal 36 | key: ${{ runner.os }}-${{ matrix.versions.ghc }}-${{ matrix.versions.cabal }}-cabal-global-${{ secrets.CACHE_VERSION }} 37 | 38 | - name: Cache cabal work 39 | id: cabal-local 40 | uses: actions/cache@v3 41 | with: 42 | path: | 43 | dist-newstyle 44 | key: ${{ runner.os }}-${{ matrix.versions.ghc }}-${{ matrix.versions.cabal }}-cabal-local-${{ secrets.CACHE_VERSION }} 45 | 46 | - name: Install dependencies 47 | run: | 48 | cabal v2-update 49 | cabal v2-build --dependencies-only --enable-tests --disable-optimization -fexecutable all 50 | - name: Build and test 51 | run: | 52 | cabal v2-build --enable-tests --disable-optimization -fexecutable all 53 | 54 | windows: 55 | 56 | runs-on: windows-latest 57 | 58 | steps: 59 | - uses: actions/checkout@v1 60 | - name: Install stack 61 | shell: cmd 62 | run: | 63 | choco install haskell-stack 64 | - name: Install dependencies 65 | run: | 66 | stack update 67 | stack test --dependencies-only --fast 68 | - name: Build and test 69 | shell: cmd 70 | run: | 71 | chcp 65001 72 | stack install --test --fast 73 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | cabal.sandbox.config 2 | TAGS 3 | dist 4 | wikidata 5 | templates 6 | ./static/ 7 | gitit.log 8 | my.conf 9 | gitit-users 10 | .cabal-sandbox 11 | github.conf 12 | /.stack-work/ 13 | /static/ 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "website"] 2 | path = website 3 | url = git@github.com:jgm/gitit.git 4 | -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | ^dist$ 2 | \.(?:aux|eventlog|h[ip]|log|[oa]|orig|prof|ps|rej|swp)$ 3 | ~$ 4 | syntax: glob 5 | .\#* 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # This .travis.yml is modified from the sample at 2 | # https://docs.haskellstack.org/en/stable/GUIDE/#travis-with-caching 3 | 4 | # Use new container infrastructure to enable caching 5 | sudo: false 6 | 7 | # Do not choose a language; we provide our own build tools. 8 | language: generic 9 | 10 | # Caching so the next build will be fast too. 11 | cache: 12 | directories: 13 | - $HOME/.ghc 14 | - $HOME/.cabal 15 | - $HOME/.stack 16 | 17 | # The different configurations we want to test. We have BUILD=cabal which uses 18 | # cabal-install, and BUILD=stack which uses Stack. More documentation on each 19 | # of those below. 20 | # 21 | # We set the compiler values here to tell Travis to use a different 22 | # cache file per set of arguments. 23 | # 24 | # If you need to have different apt packages for each combination in the 25 | # matrix, you can use a line such as: 26 | # addons: {apt: {packages: [libfcgi-dev,libgmp-dev]}} 27 | matrix: 28 | include: 29 | # We grab the appropriate GHC and cabal-install versions from hvr's PPA. See: 30 | # https://github.com/hvr/multi-ghc-travis 31 | - env: BUILD=cabal GHCVER=8.0.2 CABALVER=1.24 32 | compiler: ": #GHC 8.0.2" 33 | addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.2], sources: [hvr-ghc]}} 34 | - env: BUILD=cabal GHCVER=8.4.3 CABALVER=2.2 35 | compiler: ": #GHC 8.4.3" 36 | addons: {apt: {packages: [cabal-install-2.2,ghc-8.4.3], sources: [hvr-ghc]}} 37 | 38 | # The Stack builds. We can pass in arbitrary Stack arguments via the ARGS 39 | # variable, such as using --stack-yaml to point to a different file. 40 | - env: BUILD=stack 41 | compiler: ": #stack 8.4.3" 42 | addons: {apt: {packages: [ghc-8.4.3], sources: [hvr-ghc]}} 43 | 44 | # Nightly builds are allowed to fail 45 | # - env: BUILD=stack ARGS="--resolver nightly" 46 | # compiler: ": #stack nightly" 47 | # addons: {apt: {packages: [libgmp-dev]}} 48 | 49 | # - env: BUILD=stack ARGS="--resolver lts-8" 50 | # compiler: ": #stack 8.0.1 osx" 51 | # os: osx 52 | 53 | # - env: BUILD=stack ARGS="--resolver nightly" 54 | # compiler: ": #stack nightly osx" 55 | # os: osx 56 | 57 | allow_failures: 58 | - env: BUILD=cabal GHCVER=head CABALVER=head 59 | 60 | fast_finish: true 61 | 62 | before_install: 63 | # Using compiler above sets CC to an invalid value, so unset it 64 | - unset CC 65 | 66 | # We want to always allow newer versions of packages when building on GHC HEAD 67 | - CABALARGS="" 68 | - if [ "x$GHCVER" = "xhead" ]; then CABALARGS=--allow-newer; fi 69 | 70 | # Download and unpack the stack executable 71 | - export PATH=$PATH:/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$HOME/.local/bin 72 | - mkdir -p ~/.local/bin 73 | - | 74 | if [ `uname` = "Darwin" ] 75 | then 76 | curl --insecure -L https://www.stackage.org/stack/osx-x86_64 | tar xz --strip-components=1 --include '*/stack' -C ~/.local/bin 77 | else 78 | curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack' 79 | fi 80 | 81 | install: 82 | - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]" 83 | - if [ -f configure.ac ]; then autoreconf -i; fi 84 | - | 85 | case "$BUILD" in 86 | stack) 87 | ulimit -n 4096 88 | stack --no-terminal --install-ghc install --only-dependencies 89 | ;; 90 | cabal) 91 | cabal --version 92 | travis_retry cabal update 93 | cabal install -j alex happy 94 | cabal install -j --only-dependencies -ffast --force-reinstalls --ghc-options=-O0 --reorder-goals --max-backjumps=-1 $CABALARGS 95 | ;; 96 | esac 97 | 98 | script: 99 | - | 100 | case "$BUILD" in 101 | stack) 102 | ulimit -n 4096 103 | stack --no-terminal install 104 | ;; 105 | cabal) 106 | cabal configure -fplugins -v2 -ffast --ghc-options="-O0 -Wall -fno-warn-unused-do-bind -Werror" 107 | cabal build -j 108 | cabal check 109 | cabal copy 110 | cabal sdist 111 | SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz && \ 112 | (cd dist && cabal install -j --force-reinstalls "$SRC_TGZ") 113 | ;; 114 | esac 115 | -------------------------------------------------------------------------------- /HCAR-gitit.tex: -------------------------------------------------------------------------------- 1 | % gitit-Jg.tex 2 | \begin{hcarentry}[updated]{gitit} 3 | \label{gitit} 4 | \report{John MacFarlane}%11/10 5 | \participants{Gwern Branwen, Simon Michael, Henry Laxen, Anton 6 | van Straaten, Robin Green, Thomas Hartman, Justin Bogner, Kohei Ozaki, 7 | Dmitry Golubovsky, Anton Tayanovskyy, Dan Cook, Jinjing Wang} 8 | \status{active development} 9 | \makeheader 10 | 11 | Gitit is a wiki built on Happstack~\cref{happstack} and backed by a git, darcs, or mercurial 12 | filestore. Pages and uploaded files can be modified either directly 13 | via the VCS's command-line tools or through the wiki's web interface. 14 | Pandoc~\cref{pandoc} is used for markup processing, so pages may be written in 15 | (extended) markdown, reStructuredText, LaTeX, HTML, or literate Haskell, 16 | and exported in thirteen different formats, including LaTeX, ConTeXt, 17 | DocBook, RTF, OpenOffice ODT, MediaWiki markup, EPUB, and PDF. 18 | 19 | Notable features of gitit include: 20 | \begin{compactitem} 21 | \item 22 | Plugins: users can write their own dynamically loaded page transformations, 23 | which operate directly on the abstract syntax tree. 24 | \item 25 | Math support: LaTeX inline and display math is automatically converted 26 | to MathML, using the \texttt{texmath} library. 27 | \item 28 | Highlighting: Any git, darcs, or mercurial repository can be made a gitit wiki. 29 | Directories can be browsed, and source code files are 30 | automatically syntax-highlighted. Code snippets in wiki pages 31 | can also be highlighted. 32 | \item 33 | Library: Gitit now exports a library, \texttt{Network.Gitit}, that makes it 34 | easy to include a gitit wiki (or wikis) in any Happstack application. 35 | \item 36 | Literate Haskell: Pages can be written directly in literate Haskell. 37 | \end{compactitem} 38 | 39 | \FurtherReading 40 | \url{http://gitit.net} (itself 41 | a running demo of gitit) 42 | \end{hcarentry} 43 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cabal v2-configure -fplugins --prefix=/usr/local 3 | cabal v2-build 4 | 5 | install: 6 | cabal v2-copy 7 | 8 | .PHONY: all clean install 9 | -------------------------------------------------------------------------------- /RELANN-0.6.1: -------------------------------------------------------------------------------- 1 | I'm pleased to announce the release of gitit 0.6.1. 2 | 3 | Gitit is a wiki program that runs on happstack, the Haskell web 4 | application server stack, and stores pages and other content in a 5 | git or darcs filestore. The wiki can be updated either directly 6 | through the VCS or through gitit's web interface. Pages can be written 7 | in (extended) markdown, reStructuredText, HTML, or LaTeX, and exported 8 | in ten different formats. TeX math is rendered using MathML by default, 9 | and syntax highlighting is provided for over fifty languages. 10 | 11 | demo: http://gitit.johnmacfarlane.net 12 | manual: http://gitit.johnmacfarlane.net/README 13 | api: http://hackage.haskell.org/package/gitit-0.6.1 14 | code: http://github.com/jgm/gitit 15 | bugs: http://code.google.com/p/gitit/issues/list 16 | group: http://groups.google.com/group/gitit-discuss 17 | 18 | Here is how you can install and run gitit. You'll need GHC and 19 | cabal-install. If you don't have these, install the Haskell Platform 20 | . Then: 21 | 22 | cabal update 23 | cabal install gitit 24 | mkdir mywiki 25 | cd mywiki 26 | gitit # now browse to http://localhost:5001 27 | 28 | Or, if you want to change the defaults (say, reStructuredText 29 | instead of markdown, or darcs instead of git): 30 | 31 | gitit --print-default-config > gitit.conf 32 | # edit gitit.conf, which is self-documenting 33 | gitit -f gitit.conf 34 | 35 | The whole code base has been overhauled since the last release. 36 | Gitit is now faster, more memory efficient, more modular, and more 37 | secure. It also has many new features, including 38 | 39 | - page metadata and categories 40 | - atom feeds (sitewide and per-page) 41 | - support for literate Haskell 42 | - a better configuration system 43 | - an improved caching system 44 | - a Haskell library exporting happstack wiki handlers 45 | - a plugin system 46 | 47 | The last two items are the most exciting and deserve special comment. 48 | 49 | First, in addition to providing an executable, gitit now provides a 50 | library, Network.Gitit, which makes it easy to include a gitit 51 | wiki (or many of them) in any happstack application. It is 52 | even possible to use the containing application's authentication 53 | system for the wiki. 54 | 55 | Second, gitit can now be extended through plugins, short Haskell 56 | programs that are loaded dynamically when the server starts. For 57 | examples of the things that can be done with plugins, see the 58 | plugins directory, which contains (among other things) a plugin 59 | for adding graphviz diagrams to pages and a plugin for adding 60 | interwiki links. For a full description of the plugin system, 61 | see the haddock documentation for Network.Gitit.Interface. 62 | 63 | Full changes from version 0.5.3, as well as upgrade instructions, 64 | are available in the file CHANGES. 65 | 66 | Thanks are due to 67 | 68 | - the happstack team, for big improvements in happstack-server 69 | that make it much easier to work with, 70 | 71 | - the darcs team, for using gitit/darcsit for , 72 | giving gitit a real-world test, 73 | 74 | - Gwern Branwen, who helped to optimize gitit, wrote the 75 | InterwikiPlugin, and wrote the guts of the Feed module, 76 | 77 | - Simon Michael, who contributed several patches, 78 | 79 | - Henry Laxen, who added support for password resets and helped with 80 | the apache proxy instructions, 81 | 82 | - Anton van Straaten, who made the process of page generation 83 | more modular by adding Gitit.ContentTransformer, 84 | 85 | - Robin Green, who helped improve the plugin API and interface, 86 | fixed a security problem with the reset password code, and made 87 | saving of the user's file more robust, 88 | 89 | - Thomas Hartman, who helped improve the index page, making directory 90 | browsing persistent, 91 | 92 | - Kohei Ozaki, who contributed the ImgTexPlugin, 93 | 94 | - mightybyte, who suggested making gitit available as a library, 95 | and contributed a patch to the authentication system, 96 | 97 | - and everyone else who contributed suggestions and bug reports. 98 | 99 | -------------------------------------------------------------------------------- /Setup.lhs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env runhaskell 2 | > import Distribution.Simple 3 | > main = defaultMain 4 | -------------------------------------------------------------------------------- /YUI-LICENSE: -------------------------------------------------------------------------------- 1 | Software License Agreement (BSD License) 2 | Copyright (c) 2009, Yahoo! Inc. 3 | All rights reserved. 4 | 5 | Redistribution and use of this software in source and binary forms, 6 | with or without modification, are permitted provided that the following 7 | conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | * Neither the name of Yahoo! Inc. nor the names of its contributors 17 | may be used to endorse or promote products derived from this software 18 | without specific prior written permission of Yahoo! Inc. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /cabal.project: -------------------------------------------------------------------------------- 1 | packages: gitit.cabal 2 | tests: True 3 | flags: +plugins 4 | 5 | package pandoc 6 | flags: +embed_data_files 7 | -------------------------------------------------------------------------------- /data/FrontPage.page: -------------------------------------------------------------------------------- 1 | # Welcome to Gitit! 2 | 3 | This is the front page of your new gitit wiki. You can edit this 4 | page by clicking on the "edit" tab at the top of the screen. 5 | For instructions on how to make a link to another wiki page, see [the 6 | Help page](Help#wiki-links). To create a new wiki page, just create a 7 | link to it and follow the link. 8 | 9 | Help is always available through the "Help" link in the sidebar. 10 | More details on installing and configurating gitit are available 11 | in the [Gitit User’s Guide](). 12 | 13 | -------------------------------------------------------------------------------- /data/Help.page: -------------------------------------------------------------------------------- 1 | # Navigating 2 | 3 | The most natural way of navigating is by clicking wiki links that 4 | connect one page with another. The "Front page" link in the navigation 5 | bar will always take you to the Front Page of the wiki. The "All pages" 6 | link will take you to a list of all pages on the wiki (organized into 7 | folders if directories are used). Alternatively, you can search using 8 | the search box. Note that the search is set to look for whole words, so 9 | if you are looking for "gremlins", type that and not "gremlin". 10 | The "go" box will take you directly to the page you type. 11 | 12 | # Creating and modifying pages 13 | 14 | ## Registering for an account 15 | 16 | In order to modify pages, you'll need to be logged in. To register 17 | for an account, just click the "register" button in the bar on top 18 | of the screen. You'll be asked to choose a username and a password, 19 | which you can use to log in in the future by clicking the "login" 20 | button. While you are logged in, these buttons are replaced by 21 | a "logout so-and-so" button, which you should click to log out 22 | when you are finished. 23 | 24 | Note that logins are persistent through session cookies, so if you 25 | don't log out, you'll still be logged in when you return to the 26 | wiki from the same browser in the future. 27 | 28 | ## Editing a page 29 | 30 | To edit a page, just click the "edit" button at the bottom right corner 31 | of the page. 32 | 33 | You can click "Preview" at any time to see how your changes will look. 34 | Nothing is saved until you press "Save." 35 | 36 | Note that you must provide a description of your changes. This is to 37 | make it easier for others to see how a wiki page has been changed. 38 | 39 | ## Page metadata 40 | 41 | Pages may optionally begin with a metadata block. Here is an example: 42 | 43 | --- 44 | format: latex+lhs 45 | categories: haskell math 46 | toc: no 47 | title: Haskell and 48 | Category Theory 49 | ... 50 | 51 | \section{Why Category Theory?} 52 | 53 | The metadata block consists of a list of key-value pairs, each on a 54 | separate line. If needed, the value can be continued on one or more 55 | additional line, which must begin with a space. (This is illustrated by 56 | the "title" example above.) The metadata block must begin with a line 57 | `---` and end with a line `...` optionally followed by one or more blank 58 | lines. 59 | 60 | Currently the following keys are supported: 61 | 62 | format 63 | : Overrides the default page type as specified in the configuration file. 64 | Possible values are `markdown`, `rst`, `latex`, `html`, `markdown+lhs`, 65 | `rst+lhs`, `latex+lhs`. (Capitalization is ignored, so you can also 66 | use `LaTeX`, `HTML`, etc.) The `+lhs` variants indicate that the page 67 | is to be interpreted as literate Haskell. If this field is missing, 68 | the default page type will be used. 69 | 70 | categories 71 | : A space or comma separated list of categories to which the page belongs. 72 | 73 | toc 74 | : Overrides default setting for table-of-contents in the configuration file. 75 | Values can be `yes`, `no`, `true`, or `false` (capitalization is ignored). 76 | 77 | title 78 | : By default the displayed page title is the page name. This metadata element 79 | overrides that default. 80 | 81 | ## Creating a new page 82 | 83 | To create a new page, just create a wiki link that links to it, and 84 | click the link. If the page does not exist, you will be editing it 85 | immediately. 86 | 87 | ## Reverting to an earlier version 88 | 89 | If you click the "history" button at the bottom of the page, you will 90 | get a record of previous versions of the page. You can see the differences 91 | between two versions by dragging one onto the other; additions will be 92 | highlighted in yellow, and deletions will be crossed out with a horizontal 93 | line. Clicking on the description of changes will take you to the page 94 | as it existed after those changes. To revert the page to the revision 95 | you're currently looking at, just click the "revert" button at the bottom 96 | of the page, then "Save". 97 | 98 | ## Deleting a page 99 | 100 | The "delete" button at the bottom of the page will delete a page. Note 101 | that deleted pages can be recovered, since a record of them will still be 102 | accessible via the "activity" button on the top of the page. 103 | 104 | # Uploading files 105 | 106 | To upload a file--a picture, a PDF, or some other resource--click the 107 | "upload" button in the navigation bar. You will be prompted to select 108 | the file to upload. As with edits, you will be asked to provide a 109 | description of the resource (or of the change, if you are overwriting 110 | an existing file). 111 | 112 | Often you may leave "Name on wiki" blank, since the existing name of the 113 | file will be used by default. If that isn't desired, supply a name. 114 | Note that uploaded files *must* include a file extension (e.g. `.pdf`). 115 | 116 | If you are providing a new version of a file that already exists on the 117 | wiki, check the box "Overwrite existing file." Otherwise, leave it 118 | unchecked. 119 | 120 | To link to an uploaded file, just use its name in a regular wiki link. 121 | For example, if you uploaded a picture `fido.jpg`, you can insert the 122 | picture into a (markdown-formatted) page as follows: `![fido](fido.jpg)`. 123 | If you uploaded a PDF `projection.pdf`, you can insert a link to it 124 | using: `[projection](projection.pdf)`. 125 | 126 | -------------------------------------------------------------------------------- /data/Paths_gitit.hs: -------------------------------------------------------------------------------- 1 | module Paths_gitit where 2 | 3 | getDataFileName :: FilePath -> IO FilePath 4 | getDataFileName = return 5 | -------------------------------------------------------------------------------- /data/markup.DocBook: -------------------------------------------------------------------------------- 1 | 2 | Markdown 3 | 4 | This wiki's pages are written in 5 | pandoc's 6 | extended form of 7 | markdown. 8 | If you're not familiar with markdown, you should start by looking at 9 | the 10 | markdown 11 | "basics" page and the 12 | markdown 13 | syntax description. Consult the 14 | pandoc 15 | User's Guide for information about pandoc's syntax for 16 | footnotes, tables, description lists, and other elements not present 17 | in standard markdown. 18 | 19 | 20 | Markdown is pretty intuitive, since it is based on email 21 | conventions. Here are some examples to get you started: 22 | 23 | 24 | 25 | 28 | 31 | 32 | 33 | 36 | 39 | 40 | 41 | 44 | 47 | 48 | 49 | 52 | 55 | 56 | 57 | 60 | 63 | 64 | 65 | 68 | 75 | 76 | 77 | 80 | 83 | 84 | 85 | 88 | 91 | 92 | 93 | 96 | 99 | 100 | 101 | 104 | 107 | 108 | 109 | 112 | 120 | 121 | 122 | 125 | 132 | 133 | 134 | 140 | 147 | 148 | 155 | 162 | 163 | 164 | 177 | 232 | 233 | 234 | 245 | 292 | 293 |
26 | *emphasized text* 27 | 29 | emphasized text 30 |
34 | **strong emphasis** 35 | 37 | strong emphasis 38 |
42 | `literal text` 43 | 45 | literal text 46 |
50 | \*escaped special characters\* 51 | 53 | *escaped special characters* 54 |
58 | [external link](http://google.com) 59 | 61 | external link 62 |
66 | ![folder](/img/icons/folder.png) 67 | 69 | 70 | 71 | 72 | 73 | 74 |
78 | Wikilink: [Front Page]() 79 | 81 | Wikilink: Front Page 82 |
86 | H~2~O 87 | 89 | H2O 90 |
94 | 10^100^ 95 | 97 | 10100 98 |
102 | ~~strikeout~~ 103 | 105 | strikeout 106 |
110 | $x = \frac{{ - b \pm \sqrt {b^2 - 4ac} }}{{2a}}$ 111 | 113 | $x = \frac{{ - b \pm \sqrt {b^2 - 4ac} }}{{2a}}$ 114 | 115 | If this looks like code, it's because MathJax is not installed on 116 | your system. Contact your administrator to request it. 117 | 118 | 119 |
123 | A simple footnote.^[Or is it so simple?] 124 | 126 | A simple footnote. 127 | 128 | Or is it so simple? 129 | 130 | 131 |
135 |
136 |   > an indented paragraph,
137 |   > usually used for quotations
138 |   
139 |
141 |
142 | 143 | an indented paragraph, usually used for quotations 144 | 145 |
146 |
149 |
150 |       #!/bin/sh -e
151 |       # code, indented four spaces
152 |       echo "Hello world"
153 |   
154 |
156 | 157 | #!/bin/sh -e 158 | # code, indented four spaces 159 | echo "Hello world" 160 | 161 |
165 |
166 |   * a bulleted list
167 |   * second item
168 |       - sublist
169 |       - and more
170 |   * back to main list
171 |       1. this item has an ordered
172 |       2. sublist
173 |           a) you can also use letters
174 |           b) another item
175 |   
176 |
178 | 179 | 180 | 181 | a bulleted list 182 | 183 | 184 | 185 | 186 | second item 187 | 188 | 189 | 190 | 191 | sublist 192 | 193 | 194 | 195 | 196 | and more 197 | 198 | 199 | 200 | 201 | 202 | 203 | back to main list 204 | 205 | 206 | 207 | 208 | this item has an ordered 209 | 210 | 211 | 212 | 213 | sublist 214 | 215 | 216 | 217 | 218 | you can also use letters 219 | 220 | 221 | 222 | 223 | another item 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 |
235 |
236 |   Fruit        Quantity
237 |   --------  -----------
238 |   apples         30,200
239 |   oranges         1,998
240 |   pears              42
241 | 
242 |   Table:  Our fruit inventory
243 |   
244 |
246 | 247 | 248 | Our fruit inventory 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | Fruit 257 | 258 | 259 | Quantity 260 | 261 | 262 | 263 | 264 | 265 | 266 | apples 267 | 268 | 269 | 30,200 270 | 271 | 272 | 273 | 274 | oranges 275 | 276 | 277 | 1,998 278 | 279 | 280 | 281 | 282 | pears 283 | 284 | 285 | 42 286 | 287 | 288 | 289 | 290 |
291 |
294 | 295 | For headings, prefix a line with one or more # 296 | signs: one for a major heading, two for a subheading, three for a 297 | subsubheading. Be sure to leave space before and after the heading. 298 | 299 | 300 | # Markdown 301 | 302 | Text... 303 | 304 | ## Some examples... 305 | 306 | Text... 307 | 308 | 309 | Wiki links 310 | 311 | Links to other wiki pages are formed this way: 312 | [Page Name](). (Gitit converts markdown links 313 | with empty targets into wikilinks.) 314 | 315 | 316 | To link to a wiki page using something else as the link text: 317 | [something else](Page Name). 318 | 319 | 320 | Note that page names may contain spaces and some special 321 | characters. They need not be CamelCase. CamelCase words are 322 | not automatically converted to wiki links. 323 | 324 | 325 | Wiki pages may be organized into directories. So, if you have 326 | several pages on wine, you may wish to organize them like so: 327 | 328 | 329 | Wine/Pinot Noir 330 | Wine/Burgundy 331 | Wine/Cabernet Sauvignon 332 | 333 | 334 | Note that a wiki link [Burgundy]() that occurs 335 | inside the Wine directory will link to 336 | Wine/Burgundy, and not to 337 | Burgundy. To link to a top-level page called 338 | Burgundy, you'd have to use 339 | [Burgundy](/Burgundy). 340 | 341 | 342 | To link to a directory listing for a subdirectory, use a trailing 343 | slash: [Wine/]() will link to a listing of the 344 | Wine subdirectory. 345 | 346 | 347 |
348 | -------------------------------------------------------------------------------- /data/markup.HTML: -------------------------------------------------------------------------------- 1 | # Markup 2 | 3 | The syntax for wiki pages is standard HTML 5. All tags must be 4 | properly closed. 5 | 6 | ## Wiki links 7 | 8 | Links to other wiki pages are formed this way: 9 | `Page Name`. (Gitit converts links with empty 10 | targets into wikilinks.) 11 | 12 | To link to a wiki page using something else as the link text: 13 | `something else`. 14 | 15 | Note that page names may contain spaces and some special 16 | characters. They need not be CamelCase. CamelCase words are *not* 17 | automatically converted to wiki links. 18 | 19 | Wiki pages may be organized into directories. So, if you have 20 | several pages on wine, you may wish to organize them like so: 21 | 22 | Wine/Pinot Noir 23 | Wine/Burgundy 24 | Wine/Cabernet Sauvignon 25 | 26 | Note that a wiki link `Burgundy` that occurs inside 27 | the `Wine` directory will link to `Wine/Burgundy`, and not to 28 | `Burgundy`. To link to a top-level page called `Burgundy`, you'd 29 | have to use `Burgundy`. 30 | 31 | To link to a directory listing for a subdirectory, use a trailing 32 | slash: `Wine/` will link to a listing of the `Wine` subdirectory. 33 | -------------------------------------------------------------------------------- /data/markup.LaTeX: -------------------------------------------------------------------------------- 1 | # Markup 2 | 3 | This wiki's pages are written in (a subset of) [LaTeX]. 4 | 5 | [LaTeX]: http://www.latex-project.org/ 6 | 7 | The following commands and environments are recognized: 8 | 9 | - `\emph{emphasis}` 10 | 11 | - `\textbf{bold}` 12 | 13 | - `verb!verbatim@@\#!` 14 | 15 | - `\textsubscr{2}` 16 | 17 | - `\sout{strikeout}` 18 | 19 | - `\textsuperscript{2}` 20 | 21 | - `$e = mc^2$` 22 | 23 | - `$$e = mc^2$$` 24 | 25 | - `\footnote{a footnote}` 26 | 27 | - `\section{section}`, `\subsection{subsection}`, etc. 28 | 29 | - `\begin{quote} . . . \end{quote}` 30 | 31 | - `\begin{verbatim} . . . \end{verbatim}` 32 | 33 | - `\begin{itemize} . . . \end{itemize}` 34 | 35 | - `\begin{enumerate} . . . \end{enumerate}` 36 | 37 | ## Wiki links 38 | 39 | Links to other wiki pages are formed this way: `\href{}{Page Name}`. 40 | (Gitit converts markdown links with empty targets into wikilinks.) 41 | 42 | To link to a wiki page using something else as the link text: 43 | `\href{Page Name}{Something else}`. 44 | 45 | Note that page names may contain spaces and some special 46 | characters. They need not be CamelCase. CamelCase words are *not* 47 | automatically converted to wiki links. 48 | 49 | Wiki pages may be organized into directories. So, if you have 50 | several pages on wine, you may wish to organize them like so: 51 | 52 | Wine/Pinot Noir 53 | Wine/Burgundy 54 | Wine/Cabernet Sauvignon 55 | 56 | Note that a wiki link `\href{}{Burgundy}` that occurs inside the `Wine` 57 | directory will link to `Wine/Burgundy`, and not to `Burgundy`. To 58 | link to a top-level page called `Burgundy`, you'd have to use 59 | `\href{/Burgundy}{Burgundy}`. 60 | 61 | To link to a directory listing for a subdirectory, use a trailing 62 | slash: `\href{}{Wine/}` will link to a listing of the `Wine` subdirectory. 63 | 64 | -------------------------------------------------------------------------------- /data/markup.Markdown: -------------------------------------------------------------------------------- 1 | # Markdown 2 | 3 | This wiki's pages are written in [pandoc]'s extended form of [markdown]. 4 | If you're not familiar with markdown, you should start by looking 5 | at the [markdown "basics" page] and the [markdown syntax description]. 6 | Consult the [pandoc User's Guide] for information about pandoc's syntax 7 | for footnotes, tables, description lists, and other elements not present 8 | in standard markdown. 9 | 10 | [pandoc]: http://pandoc.org 11 | [pandoc User's Guide]: http://pandoc.org/README.html 12 | [markdown]: http://daringfireball.net/projects/markdown 13 | [markdown "basics" page]: http://daringfireball.net/projects/markdown/basics 14 | [markdown syntax description]: http://daringfireball.net/projects/markdown/syntax 15 | 16 | Markdown is pretty intuitive, since it is based on email conventions. 17 | Here are some examples to get you started: 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 64 | 69 | 70 | 71 | 74 | 77 | 78 | 79 | 85 | 91 | 92 | 99 | 106 | 107 | 108 | 121 | 134 | 135 | 136 | 147 | 158 | 159 |
`*emphasized text*`*emphasized text*
`**strong emphasis**`**strong emphasis**
`` `literal text` ```literal text`
`\*escaped special characters\*`\*escaped special characters\*
`[external link](http://google.com)`[external link](http://google.com)
`![folder](/img/icons/folder.png)`![folder](/img/icons/folder.png)
Wikilink: `[Front Page]()`Wikilink: [Front Page]()
`H~2~O`H~2~O
`10^100^`10^100^
`~~strikeout~~`~~strikeout~~
62 | `$x = \frac{{ - b \pm \sqrt {b^2 - 4ac} }}{{2a}}$` 63 | 65 | $x = \frac{{ - b \pm \sqrt {b^2 - 4ac} }}{{2a}}$^[If this looks like 66 | code, it's because MathJax is 67 | not installed on your system. Contact your administrator to request it.] 68 |
72 | `A simple footnote.^[Or is it so simple?]` 73 | 75 | A simple footnote.^[Or is it so simple?] 76 |
80 |
 81 | > an indented paragraph,
 82 | > usually used for quotations
 83 | 
84 |
86 | 87 | > an indented paragraph, 88 | > usually used for quotations 89 | 90 |
93 |
 94 |     #!/bin/sh -e
 95 |     # code, indented four spaces
 96 |     echo "Hello world"
 97 | 
98 |
100 | 101 | #!/bin/sh -e 102 | # code, indented four spaces 103 | echo "Hello world" 104 | 105 |
109 |
110 | * a bulleted list
111 | * second item
112 |     - sublist
113 |     - and more
114 | * back to main list
115 |     1. this item has an ordered
116 |     2. sublist
117 |         a) you can also use letters
118 |         b) another item
119 | 
120 |
122 | 123 | * a bulleted list 124 | * second item 125 | - sublist 126 | - and more 127 | * back to main list 128 | 1. this item has an ordered 129 | 2. sublist 130 | a) you can also use letters 131 | b) another item 132 | 133 |
137 |
138 | Fruit        Quantity
139 | --------  -----------
140 | apples         30,200
141 | oranges         1,998
142 | pears              42
143 | 
144 | Table:  Our fruit inventory
145 | 
146 |
148 | 149 | Fruit Quantity 150 | -------- ----------- 151 | apples 30,200 152 | oranges 1,998 153 | pears 42 154 | 155 | Table: Our fruit inventory 156 | 157 |
160 | 161 | For headings, prefix a line with one or more `#` signs: one for a major heading, 162 | two for a subheading, three for a subsubheading. Be sure to leave space before 163 | and after the heading. 164 | 165 | # Markdown 166 | 167 | Text... 168 | 169 | ## Some examples... 170 | 171 | Text... 172 | 173 | ## Wiki links 174 | 175 | Links to other wiki pages are formed this way: `[Page Name]()`. 176 | (Gitit converts markdown links with empty targets into wikilinks.) 177 | 178 | To link to a wiki page using something else as the link text: 179 | `[something else](Page Name)`. 180 | 181 | Note that page names may contain spaces and some special characters. 182 | They need not be CamelCase. CamelCase words are *not* automatically 183 | converted to wiki links. 184 | 185 | Wiki pages may be organized into directories. So, if you have 186 | several pages on wine, you may wish to organize them like so: 187 | 188 | Wine/Pinot Noir 189 | Wine/Burgundy 190 | Wine/Cabernet Sauvignon 191 | 192 | Note that a wiki link `[Burgundy]()` that occurs inside the `Wine` 193 | directory will link to `Wine/Burgundy`, and not to `Burgundy`. 194 | To link to a top-level page called `Burgundy`, you'd have to use 195 | `[Burgundy](/Burgundy)`. 196 | 197 | To link to a directory listing for a subdirectory, use a trailing 198 | slash: `[Wine/]()` will link to a listing of the `Wine` subdirectory. 199 | -------------------------------------------------------------------------------- /data/markup.Org: -------------------------------------------------------------------------------- 1 | * Markdown 2 | 3 | This wiki's pages are written in 4 | [[http://pandoc.org][pandoc]]'s extended form of 5 | [[http://daringfireball.net/projects/markdown][markdown]]. If you're not 6 | familiar with markdown, you should start by looking at the 7 | [[http://daringfireball.net/projects/markdown/basics][markdown "basics" 8 | page]] and the 9 | [[http://daringfireball.net/projects/markdown/syntax][markdown syntax 10 | description]]. Consult the 11 | [[http://pandoc.org/README.html][pandoc User's Guide]] 12 | for information about pandoc's syntax for footnotes, tables, description 13 | lists, and other elements not present in standard markdown. 14 | 15 | Markdown is pretty intuitive, since it is based on email conventions. 16 | Here are some examples to get you started: 17 | 18 | #+BEGIN_HTML 19 | 20 | 21 | 28 | 35 | 36 | 37 | 44 | 51 | 52 | 53 | 60 | 67 | 68 | 69 | 76 | 83 | 84 | 85 | 92 | 99 | 100 | 101 | 108 | 115 | 116 | 117 | 124 | 131 | 132 | 133 | 140 | 147 | 148 | 149 | 156 | 163 | 164 | 165 | 172 | 179 | 180 | 181 | 188 | 195 | 196 | 197 | 204 | 211 | 212 | 213 | 219 | 228 | 229 | 236 | 247 | 248 | 249 | 262 | 281 | 282 | 283 | 294 | 306 | 307 |
22 | #+END_HTML 23 | 24 | =*emphasized text*= 25 | 26 | #+BEGIN_HTML 27 | 29 | #+END_HTML 30 | 31 | /emphasized text/ 32 | 33 | #+BEGIN_HTML 34 |
38 | #+END_HTML 39 | 40 | =**strong emphasis**= 41 | 42 | #+BEGIN_HTML 43 | 45 | #+END_HTML 46 | 47 | *strong emphasis* 48 | 49 | #+BEGIN_HTML 50 |
54 | #+END_HTML 55 | 56 | =`literal text`= 57 | 58 | #+BEGIN_HTML 59 | 61 | #+END_HTML 62 | 63 | =literal text= 64 | 65 | #+BEGIN_HTML 66 |
70 | #+END_HTML 71 | 72 | =\*escaped special characters\*= 73 | 74 | #+BEGIN_HTML 75 | 77 | #+END_HTML 78 | 79 | *escaped special characters* 80 | 81 | #+BEGIN_HTML 82 |
86 | #+END_HTML 87 | 88 | =[external link](http://google.com)= 89 | 90 | #+BEGIN_HTML 91 | 93 | #+END_HTML 94 | 95 | [[http://google.com][external link]] 96 | 97 | #+BEGIN_HTML 98 |
102 | #+END_HTML 103 | 104 | =![folder](/img/icons/folder.png)= 105 | 106 | #+BEGIN_HTML 107 | 109 | #+END_HTML 110 | 111 | [[/img/icons/folder.png]] 112 | 113 | #+BEGIN_HTML 114 |
118 | #+END_HTML 119 | 120 | Wikilink: =[Front Page]()= 121 | 122 | #+BEGIN_HTML 123 | 125 | #+END_HTML 126 | 127 | Wikilink: [[][Front Page]] 128 | 129 | #+BEGIN_HTML 130 |
134 | #+END_HTML 135 | 136 | =H~2~O= 137 | 138 | #+BEGIN_HTML 139 | 141 | #+END_HTML 142 | 143 | H_{2}O 144 | 145 | #+BEGIN_HTML 146 |
150 | #+END_HTML 151 | 152 | =10^100^= 153 | 154 | #+BEGIN_HTML 155 | 157 | #+END_HTML 158 | 159 | 10^{100} 160 | 161 | #+BEGIN_HTML 162 |
166 | #+END_HTML 167 | 168 | =~~strikeout~~= 169 | 170 | #+BEGIN_HTML 171 | 173 | #+END_HTML 174 | 175 | +strikeout+ 176 | 177 | #+BEGIN_HTML 178 |
182 | #+END_HTML 183 | 184 | =$x = \frac{{ - b \pm \sqrt {b^2 - 4ac} }}{{2a}}$= 185 | 186 | #+BEGIN_HTML 187 | 189 | #+END_HTML 190 | 191 | $x = \frac{{ - b \pm \sqrt {b^2 - 4ac} }}{{2a}}$ [1] 192 | 193 | #+BEGIN_HTML 194 |
198 | #+END_HTML 199 | 200 | =A simple footnote.^[Or is it so simple?]= 201 | 202 | #+BEGIN_HTML 203 | 205 | #+END_HTML 206 | 207 | A simple footnote. [2] 208 | 209 | #+BEGIN_HTML 210 |
214 |
215 |   > an indented paragraph,
216 |   > usually used for quotations
217 |   
218 |
220 | #+END_HTML 221 | 222 | #+BEGIN_QUOTE 223 | an indented paragraph, usually used for quotations 224 | #+END_QUOTE 225 | 226 | #+BEGIN_HTML 227 |
230 |
231 |       #!/bin/sh -e
232 |       # code, indented four spaces
233 |       echo "Hello world"
234 |   
235 |
237 | #+END_HTML 238 | 239 | #+BEGIN_EXAMPLE 240 | #!/bin/sh -e 241 | # code, indented four spaces 242 | echo "Hello world" 243 | #+END_EXAMPLE 244 | 245 | #+BEGIN_HTML 246 |
250 |
251 |   * a bulleted list
252 |   * second item
253 |       - sublist
254 |       - and more
255 |   * back to main list
256 |       1. this item has an ordered
257 |       2. sublist
258 |           a) you can also use letters
259 |           b) another item
260 |   
261 |
263 | #+END_HTML 264 | 265 | - a bulleted list 266 | - second item 267 | 268 | - sublist 269 | - and more 270 | 271 | - back to main list 272 | 273 | 1. this item has an ordered 274 | 2. sublist 275 | 276 | 1) you can also use letters 277 | 2) another item 278 | 279 | #+BEGIN_HTML 280 |
284 |
285 |   Fruit        Quantity
286 |   --------  -----------
287 |   apples         30,200
288 |   oranges         1,998
289 |   pears              42
290 | 
291 |   Table:  Our fruit inventory
292 |   
293 |
295 | #+END_HTML 296 | 297 | | Fruit | Quantity | 298 | |-----------+------------| 299 | | apples | 30,200 | 300 | | oranges | 1,998 | 301 | | pears | 42 | 302 | #+CAPTION: Our fruit inventory 303 | 304 | #+BEGIN_HTML 305 |
308 | #+END_HTML 309 | 310 | For headings, prefix a line with one or more =#= signs: one for a major 311 | heading, two for a subheading, three for a subsubheading. Be sure to 312 | leave space before and after the heading. 313 | 314 | #+BEGIN_EXAMPLE 315 | # Markdown 316 | 317 | Text... 318 | 319 | ## Some examples... 320 | 321 | Text... 322 | #+END_EXAMPLE 323 | 324 | ** Wiki links 325 | 326 | Links to other wiki pages are formed this way: =[Page Name]()=. (Gitit 327 | converts markdown links with empty targets into wikilinks.) 328 | 329 | To link to a wiki page using something else as the link text: 330 | =[something else](Page Name)=. 331 | 332 | Note that page names may contain spaces and some special characters. 333 | They need not be CamelCase. CamelCase words are /not/ automatically 334 | converted to wiki links. 335 | 336 | Wiki pages may be organized into directories. So, if you have several 337 | pages on wine, you may wish to organize them like so: 338 | 339 | #+BEGIN_EXAMPLE 340 | Wine/Pinot Noir 341 | Wine/Burgundy 342 | Wine/Cabernet Sauvignon 343 | #+END_EXAMPLE 344 | 345 | Note that a wiki link =[Burgundy]()= that occurs inside the =Wine= 346 | directory will link to =Wine/Burgundy=, and not to =Burgundy=. To link 347 | to a top-level page called =Burgundy=, you'd have to use 348 | =[Burgundy](/Burgundy)=. 349 | 350 | To link to a directory listing for a subdirectory, use a trailing slash: 351 | =[Wine/]()= will link to a listing of the =Wine= subdirectory. 352 | 353 | [1] If this looks like code, it's because MathJax is not installed on 354 | your system. Contact your administrator to request it. 355 | 356 | [2] Or is it so simple? 357 | -------------------------------------------------------------------------------- /data/markup.RST: -------------------------------------------------------------------------------- 1 | # Markup 2 | 3 | This wiki's pages are written in [reStructuredText]. If you're 4 | not familiar with reStructuredText, you should start by looking at 5 | the [primer] and the [quick reference guide]. Note that not all 6 | reStructuredText constructs are currently supported. Use the 7 | preview button if you're in doubt. 8 | 9 | [reStructuredText]: http://docutils.sourceforge.net/rst.html 10 | [primer]: http://docutils.sourceforge.net/docs/user/rst/quickstart.html 11 | [quick reference guide]: http://docutils.sourceforge.net/docs/user/rst/quickref.html 12 | 13 | ## Wiki links 14 | 15 | Links to other wiki pages are formed this way: `` `Page Name <>`_ ``. 16 | (Gitit converts markdown links with empty targets into wikilinks.) 17 | 18 | To link to a wiki page using something else as the link text: 19 | either `` `something else `_ `` or 20 | 21 | `something else`_ 22 | 23 | .. _`something else`: Page Name 24 | 25 | Note that page names may contain spaces and some special 26 | characters. They need not be CamelCase. CamelCase words are *not* 27 | automatically converted to wiki links. 28 | 29 | Wiki pages may be organized into directories. So, if you have 30 | several pages on wine, you may wish to organize them like so: 31 | 32 | Wine/Pinot Noir 33 | Wine/Burgundy 34 | Wine/Cabernet Sauvignon 35 | 36 | Note that a wiki link `` `Burgundy <>`_ `` that occurs inside the `Wine` 37 | directory will link to `Wine/Burgundy`, and not to `Burgundy`. To 38 | link to a top-level page called `Burgundy`, you'd have to use 39 | `` `Burgundy `_ ``. 40 | 41 | To link to a directory listing for a subdirectory, use a trailing 42 | slash: `` `Wine/ <>`_ `` will link to a listing of the `Wine` subdirectory. 43 | -------------------------------------------------------------------------------- /data/markup.Textile: -------------------------------------------------------------------------------- 1 | h1(#markdown). Markdown 2 | 3 | This wiki's pages are written in "pandoc":http://pandoc.org's extended form of "markdown":http://daringfireball.net/projects/markdown. If you're not familiar with markdown, you should start by looking at the "markdown "basics" page":http://daringfireball.net/projects/markdown/basics and the "markdown syntax description":http://daringfireball.net/projects/markdown/syntax. Consult the "pandoc User's Guide":http://pandoc.org/README.html for information about pandoc's syntax for footnotes, tables, description lists, and other elements not present in standard markdown. 4 | 5 | Markdown is pretty intuitive, since it is based on email conventions. Here are some examples to get you started: 6 | 7 | 8 | 9 | 12 | 15 | 16 | 17 | 20 | 23 | 24 | 25 | 28 | 31 | 32 | 33 | 36 | 39 | 40 | 41 | 44 | 47 | 48 | 49 | 52 | 55 | 56 | 57 | 60 | 63 | 64 | 65 | 68 | 71 | 72 | 73 | 76 | 79 | 80 | 81 | 84 | 87 | 88 | 89 | 92 | 95 | 96 | 97 | 100 | 103 | 104 | 105 | 111 | 118 | 119 | 126 | 134 | 135 | 136 | 149 | 173 | 174 | 175 | 186 | 213 | 214 |
10 | @*emphasized text*@ 11 | 13 | _emphasized text_ 14 |
18 | @**strong emphasis**@ 19 | 21 | *strong emphasis* 22 |
26 | @`literal text`@ 27 | 29 | @literal text@ 30 |
34 | @\*escaped special characters\*@ 35 | 37 | *escaped special characters* 38 |
42 | @[external link](http://google.com)@ 43 | 45 | "external link":http://google.com 46 |
50 | @![folder](/img/icons/folder.png)@ 51 | 53 | !/img/icons/folder.png(folder)! 54 |
58 | Wikilink: @[Front Page]()@ 59 | 61 | Wikilink: "Front Page": 62 |
66 | @H~2~O@ 67 | 69 | H[~2~]O 70 |
74 | @10^100^@ 75 | 77 | 10[^100^] 78 |
82 | @~~strikeout~~@ 83 | 85 | -strikeout- 86 |
90 | @$x = \frac{{ - b \pm \sqrt {b^2 - 4ac} }}{{2a}}$@ 91 | 93 | x = \frac{{ - b \pm \sqrt {b^2 - 4ac} }}{{2a}}[1] 94 |
98 | @A simple footnote.^[Or is it so simple?]@ 99 | 101 | A simple footnote.[2] 102 |
106 |
107 | > an indented paragraph,
108 | > usually used for quotations
109 | 
110 |
112 | 113 | bq. an indented paragraph, usually used for quotations 114 | 115 | 116 | 117 |
120 |
121 |     #!/bin/sh -e
122 |     # code, indented four spaces
123 |     echo "Hello world"
124 | 
125 |
127 | 128 | bc. #!/bin/sh -e 129 | # code, indented four spaces 130 | echo "Hello world" 131 | 132 | 133 |
137 |
138 | * a bulleted list
139 | * second item
140 |     - sublist
141 |     - and more
142 | * back to main list
143 |     1. this item has an ordered
144 |     2. sublist
145 |         a) you can also use letters
146 |         b) another item
147 | 
148 |
150 | 151 |
    152 |
  • a bulleted list
  • 153 |
  • second item 154 |
      155 |
    • sublist
    • 156 |
    • and more
    • 157 |
    158 |
  • 159 |
  • back to main list 160 |
      161 |
    1. this item has an ordered
    2. 162 |
    3. sublist 163 |
        164 |
      1. you can also use letters
      2. 165 |
      3. another item
      4. 166 |
      167 |
    4. 168 |
    169 |
  • 170 |
171 | 172 |
176 |
177 | Fruit        Quantity
178 | --------  -----------
179 | apples         30,200
180 | oranges         1,998
181 | pears              42
182 | 
183 | Table:  Our fruit inventory
184 | 
185 |
187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 |
Our fruit inventory
FruitQuantity
apples30,200
oranges1,998
pears42
211 | 212 |
215 | 216 | For headings, prefix a line with one or more @#@ signs: one for a major heading, two for a subheading, three for a subsubheading. Be sure to leave space before and after the heading. 217 | 218 |
219 | # Markdown
220 | 
221 | Text...
222 | 
223 | ## Some examples...
224 | 
225 | Text...
226 | 
227 | 228 | h2(#wiki-links). Wiki links 229 | 230 | Links to other wiki pages are formed this way: @[Page Name]()@. (Gitit converts markdown links with empty targets into wikilinks.) 231 | 232 | To link to a wiki page using something else as the link text: @[something else](Page Name)@. 233 | 234 | Note that page names may contain spaces and some special characters. They need not be CamelCase. CamelCase words are _not_ automatically converted to wiki links. 235 | 236 | Wiki pages may be organized into directories. So, if you have several pages on wine, you may wish to organize them like so: 237 | 238 | bc. Wine/Pinot Noir 239 | Wine/Burgundy 240 | Wine/Cabernet Sauvignon 241 | 242 | 243 | Note that a wiki link @[Burgundy]()@ that occurs inside the @Wine@ directory will link to @Wine/Burgundy@, and not to @Burgundy@. To link to a top-level page called @Burgundy@, you'd have to use @[Burgundy](/Burgundy)@. 244 | 245 | To link to a directory listing for a subdirectory, use a trailing slash: @[Wine/]()@ will link to a listing of the @Wine@ subdirectory. 246 | 247 | 248 | fn1. If this looks like code, it's because MathJax is not installed on your system. Contact your administrator to request it. 249 | 250 | 251 | fn2. Or is it so simple? 252 | 253 | 254 | 255 | -------------------------------------------------------------------------------- /data/markupHelp/HTML: -------------------------------------------------------------------------------- 1 | ~~~~~~~~ 2 |

Section heading

3 |

Subsection

4 |

Formatting: 5 | italics, 6 | bold, 7 | superscript, 8 | subscript, 9 | line
break. 10 |

11 |
12 |

Indented quotation

13 |
14 |

Links: 15 | 16 | external, 17 | Wiki Link, 18 | image, 20 |

21 |

Indented code block:

22 |

23 | #include <stdbool.h>
24 | 
25 |
    26 |
  • bulleted
  • 27 |
  • list
  • 28 |
29 |
30 |
    31 |
  1. ordered
  2. 32 |
  3. list 33 |
      34 |
    1. sublist
    2. 35 |
    3. another
    4. 36 |
    37 |
  4. 38 |
  5. item three
  6. 39 |
40 |
41 |
term
42 |
definition
43 |
orange
44 |
orange fruit
45 |
46 | ~~~~~~~~ 47 | 48 | For more: [HTML tutorial](https://developer.mozilla.org/en-US/docs/Learn/HTML), 49 | [pandoc](http://pandoc.org/README.html). 50 | 51 | -------------------------------------------------------------------------------- /data/markupHelp/LaTeX: -------------------------------------------------------------------------------- 1 | ~~~~~~~~ 2 | \section{Section heading} 3 | 4 | \subsection{Subsection} 5 | 6 | Formatting: \emph{italics}, 7 | \textbf{bold}, 8 | super\textsuperscript{script}, 9 | sub\textsubscr{script}, 10 | \sout{strikeout}. A line break\\ 11 | can be forced with \\ at 12 | the end of the line. 13 | 14 | \begin{quote} 15 | Indented quotation 16 | \end{quote} 17 | 18 | Links: 19 | \href{http://foo.bar}{external}, 20 | \href{}{Wiki Link}, 21 | \includegraphics{/img/banner.png}, 22 | \href{#subsection}{to heading}. 23 | 24 | \begin{verbatim} 25 | #include 26 | \end{verbatim} 27 | 28 | \begin{itemize} 29 | \item bulleted 30 | \item list 31 | \end{itemize} 32 | 33 | \begin{enumerate} 34 | \item ordered 35 | \item list 36 | \begin{enumerate}[a.] 37 | \item sublist 38 | \item another 39 | \end{enumerate} 40 | \item item three 41 | \end{enumerate} 42 | 43 | \begin{description} 44 | \item[term] definition 45 | \item[orange] orange fruit 46 | \end{description} 47 | 48 | ~~~~~~~~ 49 | 50 | For more: [LaTeX], [pandoc]. 51 | 52 | [LaTeX]: http://www.latex-project.org/ 53 | [pandoc]: http://pandoc.org/README.html 54 | 55 | -------------------------------------------------------------------------------- /data/markupHelp/LaTeX+LHS: -------------------------------------------------------------------------------- 1 | ~~~~~~~~ 2 | \section{Section heading} 3 | 4 | \subsection{Subsection} 5 | 6 | Formatting: \emph{italics}, 7 | \textbf{bold}, 8 | super\textsuperscript{script}, 9 | sub\textsubscr{script}, 10 | \sout{strikeout}. A line break\\ 11 | can be forced with \\ at 12 | the end of the line. 13 | 14 | \begin{quote} 15 | Indented quotation 16 | \end{quote} 17 | 18 | Links: 19 | \href{http://foo.bar}{external}, 20 | \href{}{Wiki Link}, 21 | \includegraphics{/img/banner.png}, 22 | \href{#subsection}{to heading}. 23 | 24 | \begin{verbatim} 25 | #include 26 | \end{verbatim} 27 | 28 | Haskell code: 29 | \begin{code} 30 | fibs = 1 : 1 : zipWith (+) 31 | fibs (tail fibs) 32 | \end{code} 33 | 34 | \begin{itemize} 35 | \item bulleted 36 | \item list 37 | \end{itemize} 38 | 39 | \begin{enumerate} 40 | \item ordered 41 | \item list 42 | \begin{enumerate}[a.] 43 | \item sublist 44 | \item another 45 | \end{enumerate} 46 | \item item three 47 | \end{enumerate} 48 | 49 | \begin{description} 50 | \item[term] definition 51 | \item[orange] orange fruit 52 | \end{description} 53 | 54 | ~~~~~~~~ 55 | 56 | For more: [LaTeX], [pandoc]. 57 | 58 | [LaTeX]: http://www.latex-project.org/ 59 | [pandoc]: http://pandoc.org/README.html 60 | 61 | -------------------------------------------------------------------------------- /data/markupHelp/Markdown: -------------------------------------------------------------------------------- 1 | ~~~~~~~~ 2 | # Section heading 3 | 4 | ## Subsection 5 | 6 | Formatting: *italics*, 7 | **bold**, super^script^, 8 | sub~script~, ~~strikeout~~. 9 | A line break 10 | can be forced with two spaces 11 | at the end of the line. 12 | 13 | > Indented quotation 14 | 15 | Links: 16 | [external](http://google.com), 17 | [Wiki Link](), 18 | ![image](/img/logo.png), 19 | [to heading](#section-heading). 20 | 21 | Indented code block: 22 | 23 | #include 24 | 25 | Or use a delimited code block: 26 | 27 | ~~~ { .haskell } 28 | let a = 1:a in head a 29 | ~~~ 30 | 31 | - bulleted 32 | - list 33 | 34 | * * * * * 35 | 36 | 1. ordered 37 | 2. list 38 | a. sublist (indent 4 spaces) 39 | b. another 40 | 3. item three 41 | 42 | term 43 | : definition 44 | 45 | orange 46 | : orange fruit 47 | 48 | ~~~~~~~~ 49 | 50 | For more: [markdown syntax](http://daringfireball.net/projects/markdown), 51 | [pandoc extensions](http://pandoc.org/README.html). 52 | 53 | -------------------------------------------------------------------------------- /data/markupHelp/Markdown+LHS: -------------------------------------------------------------------------------- 1 | ~~~~~~~~ 2 | # Section heading 3 | 4 | ## Subsection 5 | 6 | Formatting: *italics*, 7 | **bold**, super^script^, 8 | sub~script~, ~~strikeout~~. 9 | A line break 10 | can be forced with two spaces 11 | at the end of the line. 12 | 13 | > Indented quotation: 14 | > note: the '>' must not 15 | > be flush with the margin 16 | > or what follows will be 17 | > treated as Haskell code 18 | 19 | > -- bird-tracks Haskell: 20 | > fibs = 0 : 1 : 21 | > zipWith (+) fibs (tail fibs) 22 | 23 | Links: 24 | [external](http://google.com), 25 | [Wiki Link](), 26 | ![image](/img/logo.png), 27 | [to heading](#section-heading). 28 | 29 | Indented code block: 30 | 31 | #include 32 | 33 | Or use a delimited code block: 34 | 35 | ~~~ { .haskell } 36 | let a = 1:a in head a 37 | ~~~ 38 | 39 | - bulleted 40 | - list 41 | 42 | * * * * * 43 | 44 | 1. ordered 45 | 2. list 46 | a. sublist (indent 4 spaces) 47 | b. another 48 | 3. item three 49 | 50 | term 51 | : definition 52 | orange 53 | : orange fruit 54 | 55 | ~~~~~~~~ 56 | 57 | For more: [markdown syntax](http://daringfireball.net/projects/markdown), 58 | [pandoc extensions](http://pandoc.org/README.html). 59 | 60 | -------------------------------------------------------------------------------- /data/markupHelp/Org: -------------------------------------------------------------------------------- 1 | * Section heading 2 | 3 | ** Subsection 4 | 5 | Formatting: /italics/, *bold*, super^{script}, sub_{script}, 6 | +strikeout+. A line break\\ 7 | can be forced with two backslashes at the end of the line. 8 | 9 | #+BEGIN_QUOTE 10 | Indented quotation 11 | #+END_QUOTE 12 | 13 | Links: [[http://google.com][external]], [[][Wiki Link]], 14 | [[/img/logo.png]], [[#section-heading][to heading]]. 15 | 16 | Indented code block: 17 | 18 | #+BEGIN_EXAMPLE 19 | #include 20 | #+END_EXAMPLE 21 | 22 | Or 23 | 24 | #+BEGIN_SRC haskell 25 | let a = 1:a in head a 26 | #+END_SRC 27 | 28 | - bulleted 29 | - list 30 | 31 | -------------- 32 | 33 | 1. ordered 34 | 2. list 35 | 36 | 1. sublist (indent 4 spaces) 37 | 2. another 38 | 39 | 3. item three 40 | 41 | - term :: definition 42 | - orange :: orange fruit 43 | 44 | For more: [org-mode manual](http://orgmode.org/manual/) 45 | -------------------------------------------------------------------------------- /data/markupHelp/RST: -------------------------------------------------------------------------------- 1 | ~~~~~~~~ 2 | Section heading 3 | =============== 4 | 5 | Subsection 6 | ---------- 7 | 8 | Formatting: *italics*, 9 | **bold**. 10 | 11 | Indented quotation 12 | 13 | Links: 14 | `external `_, 15 | `Wiki Link <>`_, |image|, 16 | `heading <#subsection>`_. 17 | 18 | .. |image| image:: 19 | /img/logo.png 20 | 21 | :: 22 | 23 | let a = 1:a in head a 24 | 25 | - bulleted 26 | - list 27 | 28 | --------------- 29 | 30 | 1. ordered 31 | 2. list 32 | 33 | a. sublist (indent 4 spaces) 34 | b. another 35 | 36 | 3. item three 37 | 38 | term 39 | definition 40 | orange 41 | orange fruit 42 | 43 | ~~~~~~~~ 44 | 45 | For more: [reST primer], 46 | [quick reference guide]. 47 | 48 | [reST primer]: http://docutils.sourceforge.net/docs/user/rst/quickstart.html 49 | [quick reference guide]: http://docutils.sourceforge.net/docs/user/rst/quickref.html 50 | 51 | -------------------------------------------------------------------------------- /data/markupHelp/RST+LHS: -------------------------------------------------------------------------------- 1 | ~~~~~~~~ 2 | Section heading 3 | =============== 4 | 5 | Subsection 6 | ---------- 7 | 8 | Formatting: *italics*, 9 | **bold**. 10 | 11 | Indented quotation 12 | 13 | 14 | Links: 15 | `external `_, 16 | `Wiki Link <>`_, |image|, 17 | `heading <#subsection>`_. 18 | 19 | .. |image| image:: 20 | /img/logo.png 21 | 22 | :: 23 | 24 | let a = 1:a in head a 25 | 26 | > -- bird-style Haskell 27 | > fibs = 1 : 1 : zipWith (+) 28 | > fibs (tail fibs) 29 | 30 | - bulleted 31 | - list 32 | 33 | -------------- 34 | 35 | - ordered 36 | - list 37 | 38 | a. sublist (indent 4 spaces) 39 | b. another 40 | 41 | - item three 42 | 43 | term 44 | definition 45 | orange 46 | orange fruit 47 | 48 | ~~~~~~~~ 49 | 50 | For more: [reST primer], 51 | [quick reference guide]. 52 | 53 | [reST primer]: http://docutils.sourceforge.net/docs/user/rst/quickstart.html 54 | [quick reference guide]: http://docutils.sourceforge.net/docs/user/rst/quickref.html 55 | 56 | -------------------------------------------------------------------------------- /data/post-update: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This hook does two things: 4 | # 5 | # 1. update the "info" files that allow the list of references to be 6 | # queries over dumb transports such as http 7 | # 8 | # 2. if this repository looks like it is a non-bare repository, and 9 | # the checked-out branch is pushed to, then update the working copy. 10 | # This makes "push" function somewhat similarly to darcs and bzr. 11 | # 12 | # To enable this hook, make this file executable by "chmod +x post-update". 13 | 14 | git update-server-info 15 | 16 | is_bare=$(git config --get --bool core.bare) 17 | 18 | if [ -z "$is_bare" ] 19 | then 20 | # for compatibility's sake, guess 21 | git_dir_full=$(cd $GIT_DIR; pwd) 22 | case $git_dir_full in */.git) is_bare=false;; *) is_bare=true;; esac 23 | fi 24 | 25 | update_wc() { 26 | ref=$1 27 | echo "Push to checked out branch $ref" >&2 28 | if [ ! -f $GIT_DIR/logs/HEAD ] 29 | then 30 | echo "E:push to non-bare repository requires a HEAD reflog" >&2 31 | exit 1 32 | fi 33 | if (cd $GIT_WORK_TREE; git diff-files -q --exit-code >/dev/null) 34 | then 35 | wc_dirty=0 36 | else 37 | echo "W:unstaged changes found in working copy" >&2 38 | wc_dirty=1 39 | desc="working copy" 40 | fi 41 | if git diff-index --cached HEAD@{1} >/dev/null 42 | then 43 | index_dirty=0 44 | else 45 | echo "W:uncommitted, staged changes found" >&2 46 | index_dirty=1 47 | if [ -n "$desc" ] 48 | then 49 | desc="$desc and index" 50 | else 51 | desc="index" 52 | fi 53 | fi 54 | if [ "$wc_dirty" -ne 0 -o "$index_dirty" -ne 0 ] 55 | then 56 | new=$(git rev-parse HEAD) 57 | echo "W:stashing dirty $desc - see git-stash(1)" >&2 58 | ( trap 'echo trapped $$; git symbolic-ref HEAD "'"$ref"'"' 2 3 13 15 ERR EXIT 59 | git update-ref --no-deref HEAD HEAD@{1} 60 | cd $GIT_WORK_TREE 61 | git stash save "dirty $desc before update to $new"; 62 | git symbolic-ref HEAD "$ref" 63 | ) 64 | fi 65 | 66 | # eye candy - show the WC updates :) 67 | echo "Updating working copy" >&2 68 | (cd $GIT_WORK_TREE 69 | git diff-index -R --name-status HEAD >&2 70 | git reset --hard HEAD) 71 | } 72 | 73 | if [ "$is_bare" = "false" ] 74 | then 75 | active_branch=`git symbolic-ref HEAD` 76 | export GIT_DIR=$(cd $GIT_DIR; pwd) 77 | GIT_WORK_TREE=${GIT_WORK_TREE-..} 78 | for ref 79 | do 80 | if [ "$ref" = "$active_branch" ] 81 | then 82 | update_wc $ref 83 | fi 84 | done 85 | fi 86 | -------------------------------------------------------------------------------- /data/s5/default/blank.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgm/gitit/f8a847cfea55773beeaea4eb5051f6454ebba4ae/data/s5/default/blank.gif -------------------------------------------------------------------------------- /data/s5/default/bodybg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgm/gitit/f8a847cfea55773beeaea4eb5051f6454ebba4ae/data/s5/default/bodybg.gif -------------------------------------------------------------------------------- /data/s5/default/framing.css: -------------------------------------------------------------------------------- 1 | /* The following styles size, place, and layer the slide components. 2 | Edit these if you want to change the overall slide layout. 3 | The commented lines can be uncommented (and modified, if necessary) 4 | to help you with the rearrangement process. */ 5 | 6 | /* target = 1024x768 */ 7 | 8 | div#header, div#footer, .slide {width: 100%; top: 0; left: 0;} 9 | div#header {top: 0; height: 3em; z-index: 1;} 10 | div#footer {top: auto; bottom: 0; height: 2.5em; z-index: 5;} 11 | .slide {top: 0; width: 92%; padding: 3.5em 4% 4%; z-index: 2; list-style: none;} 12 | div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;} 13 | div#controls form {position: absolute; bottom: 0; right: 0; width: 100%; 14 | margin: 0;} 15 | #currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em; z-index: 10;} 16 | html>body #currentSlide {position: fixed;} 17 | 18 | /* 19 | div#header {background: #FCC;} 20 | div#footer {background: #CCF;} 21 | div#controls {background: #BBD;} 22 | div#currentSlide {background: #FFC;} 23 | */ 24 | -------------------------------------------------------------------------------- /data/s5/default/iepngfix.htc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 42 | -------------------------------------------------------------------------------- /data/s5/default/opera.css: -------------------------------------------------------------------------------- 1 | /* DO NOT CHANGE THESE unless you really want to break Opera Show */ 2 | .slide { 3 | visibility: visible !important; 4 | position: static !important; 5 | page-break-before: always; 6 | } 7 | #slide0 {page-break-before: avoid;} 8 | -------------------------------------------------------------------------------- /data/s5/default/outline.css: -------------------------------------------------------------------------------- 1 | /* don't change this unless you want the layout stuff to show up in the outline view! */ 2 | 3 | .layout div, #footer *, #controlForm * {display: none;} 4 | #footer, #controls, #controlForm, #navLinks, #toggle { 5 | display: block; visibility: visible; margin: 0; padding: 0;} 6 | #toggle {float: right; padding: 0.5em;} 7 | html>body #toggle {position: fixed; top: 0; right: 0;} 8 | 9 | /* making the outline look pretty-ish */ 10 | 11 | #slide0 h1, #slide0 h2, #slide0 h3, #slide0 h4 {border: none; margin: 0;} 12 | #slide0 h1 {padding-top: 1.5em;} 13 | .slide h1 {margin: 1.5em 0 0; padding-top: 0.25em; 14 | border-top: 1px solid #888; border-bottom: 1px solid #AAA;} 15 | #toggle {border: 1px solid; border-width: 0 0 1px 1px; background: #FFF;} 16 | -------------------------------------------------------------------------------- /data/s5/default/pretty.css: -------------------------------------------------------------------------------- 1 | /* Following are the presentation styles -- edit away! */ 2 | 3 | body {background: #FFF url(bodybg.gif) -16px 0 no-repeat; color: #000; font-size: 2em;} 4 | :link, :visited {text-decoration: none; color: #00C;} 5 | #controls :active {color: #88A !important;} 6 | #controls :focus {outline: 1px dotted #227;} 7 | h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;} 8 | ul, pre {margin: 0; line-height: 1em;} 9 | html, body {margin: 0; padding: 0;} 10 | 11 | blockquote, q {font-style: italic;} 12 | blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em; text-align: center; font-size: 1em;} 13 | blockquote p {margin: 0;} 14 | blockquote i {font-style: normal;} 15 | blockquote b {display: block; margin-top: 0.5em; font-weight: normal; font-size: smaller; font-style: normal;} 16 | blockquote b i {font-style: italic;} 17 | 18 | kbd {font-weight: bold; font-size: 1em;} 19 | sup {font-size: smaller; line-height: 1px;} 20 | 21 | .slide code {padding: 2px 0.25em; font-weight: bold; color: #533;} 22 | .slide code.bad, code del {color: red;} 23 | .slide code.old {color: silver;} 24 | .slide pre {padding: 0; margin: 0.25em 0 0.5em 0.5em; color: #533; font-size: 90%;} 25 | .slide pre code {display: block;} 26 | .slide ul {margin-left: 5%; margin-right: 7%; list-style: disc;} 27 | .slide li {margin-top: 0.75em; margin-right: 0;} 28 | .slide ul ul {line-height: 1;} 29 | .slide ul ul li {margin: .2em; font-size: 85%; list-style: square;} 30 | .slide img.leader {display: block; margin: 0 auto;} 31 | 32 | div#header, div#footer {background: #005; color: #AAB; 33 | font-family: Verdana, Helvetica, sans-serif;} 34 | div#header {background: #005 url(bodybg.gif) -16px 0 no-repeat; 35 | line-height: 1px;} 36 | div#footer {font-size: 0.5em; font-weight: bold; padding: 1em 0;} 37 | #footer h1, #footer h2 {display: block; padding: 0 1em;} 38 | #footer h2 {font-style: italic;} 39 | 40 | div.long {font-size: 0.75em;} 41 | .slide h1 {position: absolute; top: 0.7em; left: 87px; z-index: 1; 42 | margin: 0; padding: 0.3em 0 0 50px; white-space: nowrap; 43 | font: bold 150%/1em Helvetica, sans-serif; text-transform: capitalize; 44 | color: #DDE; background: #005;} 45 | .slide h3 {font-size: 130%;} 46 | h1 abbr {font-variant: small-caps;} 47 | 48 | div#controls {position: absolute; left: 50%; bottom: 0; 49 | width: 50%; 50 | text-align: right; font: bold 0.9em Verdana, Helvetica, sans-serif;} 51 | html>body div#controls {position: fixed; padding: 0 0 1em 0; 52 | top: auto;} 53 | div#controls form {position: absolute; bottom: 0; right: 0; width: 100%; 54 | margin: 0; padding: 0;} 55 | #controls #navLinks a {padding: 0; margin: 0 0.5em; 56 | background: #005; border: none; color: #779; 57 | cursor: pointer;} 58 | #controls #navList {height: 1em;} 59 | #controls #navList #jumplist {position: absolute; bottom: 0; right: 0; background: #DDD; color: #227;} 60 | 61 | #currentSlide {text-align: center; font-size: 0.5em; color: #449;} 62 | 63 | #slide0 {padding-top: 3.5em; font-size: 90%;} 64 | #slide0 h1 {position: static; margin: 1em 0 0; padding: 0; 65 | font: bold 2em Helvetica, sans-serif; white-space: normal; 66 | color: #000; background: transparent;} 67 | #slide0 h2 {font: bold italic 1em Helvetica, sans-serif; margin: 0.25em;} 68 | #slide0 h3 {margin-top: 1.5em; font-size: 1.5em;} 69 | #slide0 h4 {margin-top: 0; font-size: 1em;} 70 | 71 | ul.urls {list-style: none; display: inline; margin: 0;} 72 | .urls li {display: inline; margin: 0;} 73 | .note {display: none;} 74 | .external {border-bottom: 1px dotted gray;} 75 | html>body .external {border-bottom: none;} 76 | .external:after {content: " \274F"; font-size: smaller; color: #77B;} 77 | 78 | .incremental, .incremental *, .incremental *:after {color: #DDE; visibility: visible;} 79 | img.incremental {visibility: hidden;} 80 | .slide .current {color: #B02;} 81 | 82 | 83 | /* diagnostics 84 | 85 | li:after {content: " [" attr(class) "]"; color: #F88;} 86 | */ 87 | -------------------------------------------------------------------------------- /data/s5/default/print.css: -------------------------------------------------------------------------------- 1 | /* The following rule is necessary to have all slides appear in print! DO NOT REMOVE IT! */ 2 | .slide, ul {page-break-inside: avoid; visibility: visible !important;} 3 | h1 {page-break-after: avoid;} 4 | 5 | body {font-size: 12pt; background: white;} 6 | * {color: black;} 7 | 8 | #slide0 h1 {font-size: 200%; border: none; margin: 0.5em 0 0.25em;} 9 | #slide0 h3 {margin: 0; padding: 0;} 10 | #slide0 h4 {margin: 0 0 0.5em; padding: 0;} 11 | #slide0 {margin-bottom: 3em;} 12 | 13 | h1 {border-top: 2pt solid gray; border-bottom: 1px dotted silver;} 14 | .extra {background: transparent !important;} 15 | div.extra, pre.extra, .example {font-size: 10pt; color: #333;} 16 | ul.extra a {font-weight: bold;} 17 | p.example {display: none;} 18 | 19 | #header {display: none;} 20 | #footer h1 {margin: 0; border-bottom: 1px solid; color: gray; font-style: italic;} 21 | #footer h2, #controls {display: none;} 22 | 23 | /* The following rule keeps the layout stuff out of print. Remove at your own risk! */ 24 | .layout, .layout * {display: none !important;} 25 | -------------------------------------------------------------------------------- /data/s5/default/s5-core.css: -------------------------------------------------------------------------------- 1 | /* Do not edit or override these styles! The system will likely break if you do. */ 2 | 3 | div#header, div#footer, div#controls, .slide {position: absolute;} 4 | html>body div#header, html>body div#footer, 5 | html>body div#controls, html>body .slide {position: fixed;} 6 | .handout {display: none;} 7 | .layout {display: block;} 8 | .slide, .hideme, .incremental {visibility: hidden;} 9 | #slide0 {visibility: visible;} 10 | -------------------------------------------------------------------------------- /data/s5/default/slides.css: -------------------------------------------------------------------------------- 1 | @import url(s5-core.css); /* required to make the slide show run at all */ 2 | @import url(framing.css); /* sets basic placement and size of slide components */ 3 | @import url(pretty.css); /* stuff that makes the slides look better than blah */ -------------------------------------------------------------------------------- /data/s5/default/slides.min.js: -------------------------------------------------------------------------------- 1 | var undef;var slideCSS="";var snum=0;var smax=1;var incpos=0;var number=undef;var s5mode=true;var defaultView="slideshow";var controlVis="visible";var isIE=navigator.appName=="Microsoft Internet Explorer"&&navigator.userAgent.indexOf("Opera")<1?1:0;var isOp=navigator.userAgent.indexOf("Opera")>-1?1:0;var isGe=navigator.userAgent.indexOf("Gecko")>-1&&navigator.userAgent.indexOf("Safari")<1?1:0;function hasClass(a,b){if(!a.className){return false}return(a.className.search("(^|\\s)"+b+"(\\s|$)")!=-1)}function hasValue(a,b){if(!a){return false}return(a.search("(^|\\s)"+b+"(\\s|$)")!=-1)}function removeClass(a,b){if(!a){return}a.className=a.className.replace(new RegExp("(^|\\s)"+b+"(\\s|$)"),RegExp.$1+RegExp.$2)}function addClass(a,b){if(!a||hasClass(a,b)){return}if(a.className){a.className+=" "+b}else{a.className=b}}function GetElementsWithClassName(a,c){var d=document.getElementsByTagName(a);var e=new Array();for(var b=0;b'+snum+' / '+(smax-1)+"";if(snum==0){a.style.visibility="hidden"}else{a.style.visibility="visible"}}function go(c){if(document.getElementById("slideProj").disabled||c==0){return}var b=document.getElementById("jumplist");var g="slide"+snum;var e=document.getElementById(g);if(incrementals[snum].length>0){for(var a=0;almax){snum=lmax}if(snum<0){snum=0}}else{snum=parseInt(b.value)}var f="slide"+snum;var d=document.getElementById(f);if(!d){d=document.getElementById("slide0");snum=0}if(c<0){incpos=incrementals[snum].length}else{incpos=0}if(incrementals[snum].length>0&&incpos==0){for(var a=0;a0&&incpos>0){addClass(incrementals[snum][incpos-1],"current")}e.style.visibility="hidden";d.style.visibility="visible";b.selectedIndex=snum;currentSlide();number=0}function goTo(a){if(a>=smax||a==snum){return}go(a-snum)}function subgo(a){if(a>0){removeClass(incrementals[snum][incpos-1],"current");removeClass(incrementals[snum][incpos],"incremental");addClass(incrementals[snum][incpos],"current");incpos++}else{incpos--;removeClass(incrementals[snum][incpos],"current");addClass(incrementals[snum][incpos],"incremental");addClass(incrementals[snum][incpos-1],"current")}}function toggle(){var b=GetElementsWithClassName("*","slide");var d=document.getElementById("slideProj");var c=document.getElementById("outlineStyle");if(!d.disabled){d.disabled=true;c.disabled=false;s5mode=false;fontSize("1em");for(var e=0;e=incrementals[snum].length){go(1)}else{subgo(1)}}break;case 33:case 37:case 38:if(number!=undef){go(-1*number)}else{if(!incrementals[snum]||incpos<=0){go(-1)}else{subgo(-1)}}break;case 36:goTo(0);break;case 35:goTo(smax-1);break;case 67:showHide("k");break}if(a.which<48||a.which>57){number=undef}else{if(window.event&&isParentOrSelf(window.event.srcElement,"controls")){return}if(a.target&&isParentOrSelf(a.target,"controls")){return}number=(((number!=undef)?number:0)*10)+(a.which-48)}}return false}function clicker(b){number=undef;var a;if(window.event){a=window.event.srcElement;b=window.event}else{a=b.target}if(a.getAttribute("href")!=null||hasValue(a.rel,"external")||isParentOrSelf(a,"controls")||isParentOrSelf(a,"embed")||isParentOrSelf(a,"object")){return true}if(!b.which||b.which==1){if(!incrementals[snum]||incpos>=incrementals[snum].length){go(1)}else{subgo(1)}}}function findSlide(d){var c=null;var b=GetElementsWithClassName("*","slide");for(var a=0;a';if(controlVis=="hidden"){var b=document.getElementById("navLinks")}else{var b=document.getElementById("jumplist")}addClass(b,"hideme")}function fontScale(){if(!s5mode){return false}var f=22;var a=32;if(window.innerHeight){var c=window.innerHeight;var e=window.innerWidth}else{if(document.documentElement.clientHeight){var c=document.documentElement.clientHeight;var e=document.documentElement.clientWidth}else{if(document.body.clientHeight){var c=document.body.clientHeight;var e=document.body.clientWidth}else{var c=700;var e=1024}}}var b=Math.min(Math.round(c/f),Math.round(e/a));fontSize(b+"px");if(isGe){var d=document.getElementsByTagName("body")[0];d.style.display="none";d.style.display="block"}}function fontSize(a){if(!(s5ss=document.getElementById("s5ss"))){if(!isIE){document.getElementsByTagName("head")[0].appendChild(s5ss=document.createElement("style"));s5ss.setAttribute("media","screen, projection");s5ss.setAttribute("id","s5ss")}else{document.createStyleSheet();document.s5ss=document.styleSheets[document.styleSheets.length-1]}}if(!isIE){while(s5ss.lastChild){s5ss.removeChild(s5ss.lastChild)}s5ss.appendChild(document.createTextNode("body {font-size: "+a+" !important;}"))}else{document.s5ss.addRule("body","font-size: "+a+" !important;")}}function notOperaFix(){slideCSS=document.getElementById("slideProj").href;var b=document.getElementById("slideProj");var a=document.getElementById("outlineStyle");b.setAttribute("media","screen");a.disabled=true;if(isGe){b.setAttribute("href","null");b.setAttribute("href",slideCSS)}if(isIE&&document.styleSheets&&document.styleSheets[0]){document.styleSheets[0].addRule("img","behavior: url(ui/default/iepngfix.htc)");document.styleSheets[0].addRule("div","behavior: url(ui/default/iepngfix.htc)");document.styleSheets[0].addRule(".slide","behavior: url(ui/default/iepngfix.htc)")}}function getIncrementals(e){var d=new Array();if(!e){return d}var c=e.childNodes;for(var b=0;bbody p code {*white-space:normal;} 10 | hr {margin:-8px auto 11px;} 11 | .container ul { list-style: disc outside; margin-left: 2em; } /* IE can't handle :before and :after */ 12 | .container ul li { text-indent: 0; margin-left: 0; } 13 | .container legend { margin-bottom: 1.6em; } /* IE form margin bug */ 14 | sup, sub { font-size: 100%; } /* IE superscript & subscript bug */ 15 | .container blockquote p, #content blockquote ul, #content blockquote ol, #content blockquote dl, #content blockquote pre, #content blockquote address, 16 | .container blockquote table, #content blockquote form, #content blockquote h1, #content blockquote h2, #content blockquote h3, #content blockquote h4, #content blockquote h5, #content blockquote h6 { margin-top: .8em; margin-bottom: .8em; } /* IE can't handle :first-child */ 17 | * html .container textarea, * html .container input { padding: 0; } /* IE < 7 form fix */ 18 | .container input[type='submit'], .container input[type='button'] { padding: 0; } /* IE 7 button fix */ 19 | .container legend+* { margin-top: 0; } /* we already added legend margin */ 20 | a abbr, a acronym { text-decoration: underline; } /* IE 7 bug */ 21 | -------------------------------------------------------------------------------- /data/static/css/print.css: -------------------------------------------------------------------------------- 1 | body { 2 | width:100% !important; 3 | margin:0 !important; 4 | padding:0 !important; 5 | line-height: 1.4; 6 | font-family: "Times New Roman", serif; color: #000; background: none; font-size: 12pt; } 7 | 8 | /*Headings */ 9 | h1,h2,h3,h4,h5,h6 { font-family: Helvetica, Arial, sans-serif; } 10 | h1{font-size:19pt;} 11 | h2{font-size:17pt;} 12 | h3{font-size:15pt;} 13 | h4,h5,h6{font-size:12pt;} 14 | 15 | h2.revision { font-size: 10pt; font-weight: normal; font-style: italic; text-align: right; } 16 | 17 | pre, code { font: 10pt Courier, monospace; } 18 | blockquote { margin: 1.3em; padding: 1em; font-size: 10pt; } 19 | hr { background-color: #ccc; } 20 | 21 | /* Images */ 22 | img { float: left; margin: 1em 1.5em 1.5em 0; } 23 | a img { border: none; } 24 | 25 | /* Links */ 26 | a:link, a:visited { background: transparent; font-weight: normal; text-decoration: underline; color:#333; } 27 | a:link[href^="http://"]:after, a[href^="http://"]:visited:after { content: " (" attr(href) ")"; font-size: 90%; } 28 | a[href^="http://"] {color:#000; } 29 | 30 | /* Table */ 31 | table { margin: 1px; text-align:left; } 32 | th { font-weight: bold; } 33 | th,td { padding: 4px 10px 4px 0; } 34 | tfoot { font-style: italic; } 35 | caption { background: #fff; margin-bottom:2em; text-align:left; } 36 | thead {display: table-header-group;} 37 | tr {page-break-inside: avoid;} 38 | 39 | /*hide various parts from the site*/ 40 | 41 | #maincol { margin-left: 1em; margin-right: 1em; border: none; } 42 | #content { border: none; } 43 | #sidebar, #userbox, #footer {display:none;} 44 | #toc { display: none; } 45 | #categoryList { display: none; } 46 | h1 a:link, h2 a:link, h3 a:link, h4 a:link, h5 a:link, h6 a:link { text-decoration: none; } 47 | h1.pageTitle { font-size: 220%; } 48 | td.lineNumbers { display: none; } 49 | ul.tabs { display: none; } 50 | -------------------------------------------------------------------------------- /data/static/css/reset-fonts-grids.css: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009, Yahoo! Inc. All rights reserved. 3 | Code licensed under the BSD License: 4 | http://developer.yahoo.net/yui/license.txt 5 | version: 2.7.0 6 | MODIFIED by JM - don't reset list item styles, removed 'caption,th{text-align:left}' 7 | */ 8 | html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{*font-size:100%;}body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}select,input,button,textarea,button{font:99% arial,helvetica,clean,sans-serif;}table{font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;}body{text-align:center;}#doc,#doc2,#doc3,#doc4,.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6,.yui-t7{margin:auto;text-align:left;width:57.69em;*width:56.25em;}#doc2{width:73.076em;*width:71.25em;}#doc3{margin:auto 10px;width:auto;}#doc4{width:74.923em;*width:73.05em;}.yui-b{position:relative;}.yui-b{_position:static;}#yui-main .yui-b{position:static;}#yui-main,.yui-g .yui-u .yui-g{width:100%;}.yui-t1 #yui-main,.yui-t2 #yui-main,.yui-t3 #yui-main{float:right;margin-left:-25em;}.yui-t4 #yui-main,.yui-t5 #yui-main,.yui-t6 #yui-main{float:left;margin-right:-25em;}.yui-t1 .yui-b{float:left;width:12.30769em;*width:12.00em;}.yui-t1 #yui-main .yui-b{margin-left:13.30769em;*margin-left:13.05em;}.yui-t2 .yui-b{float:left;width:13.8461em;*width:13.50em;}.yui-t2 #yui-main .yui-b{margin-left:14.8461em;*margin-left:14.55em;}.yui-t3 .yui-b{float:left;width:23.0769em;*width:22.50em;}.yui-t3 #yui-main .yui-b{margin-left:24.0769em;*margin-left:23.62em;}.yui-t4 .yui-b{float:right;width:13.8456em;*width:13.50em;}.yui-t4 #yui-main .yui-b{margin-right:14.8456em;*margin-right:14.55em;}.yui-t5 .yui-b{float:right;width:18.4615em;*width:18.00em;}.yui-t5 #yui-main .yui-b{margin-right:19.4615em;*margin-right:19.125em;}.yui-t6 .yui-b{float:right;width:23.0769em;*width:22.50em;}.yui-t6 #yui-main .yui-b{margin-right:24.0769em;*margin-right:23.62em;}.yui-t7 #yui-main .yui-b{display:block;margin:0 0 1em 0;}#yui-main .yui-b{float:none;width:auto;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf,.yui-gc .yui-u,.yui-gd .yui-g,.yui-g .yui-gc .yui-u,.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf .yui-g,.yui-gf .yui-u{float:right;}.yui-g div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first,.yui-ge div.first,.yui-gf div.first,.yui-g .yui-gc div.first,.yui-g .yui-ge div.first,.yui-gc div.first div.first{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf{width:49.1%;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{width:32%;margin-left:1.99%;}.yui-gb .yui-u{*margin-left:1.9%;*width:31.9%;}.yui-gc div.first,.yui-gd .yui-u{width:66%;}.yui-gd div.first{width:32%;}.yui-ge div.first,.yui-gf .yui-u{width:74.2%;}.yui-ge .yui-u,.yui-gf div.first{width:24%;}.yui-g .yui-gb div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first{margin-left:0;}.yui-g .yui-g .yui-u,.yui-gb .yui-g .yui-u,.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u,.yui-ge .yui-g .yui-u,.yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0;}.yui-g .yui-g .yui-u{width:48.1%;}.yui-g .yui-gb div.first,.yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%;}.yui-g .yui-gc div.first,.yui-gd .yui-g{width:66%;}.yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%;}.yui-gb .yui-gc div.first,.yui-gb .yui-gd div.first{*margin-right:0;}.yui-gb .yui-gb .yui-u,.yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%;}.yui-g .yui-gb .yui-u{_margin-left:1.0%;}.yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%;}.yui-gb .yui-gd div.first{*width:31%;_width:29.5%;}.yui-g .yui-gc .yui-u,.yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0;}.yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf .yui-u{margin:0;}.yui-gb .yui-gb .yui-u{_margin-left:.7%;}.yui-gb .yui-g div.first,.yui-gb .yui-gb div.first{*margin-left:0;}.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0;}.yui-gb .yui-gd div.first{width:32%;}.yui-g .yui-gd div.first{_width:29.9%;}.yui-ge .yui-g{width:24%;}.yui-gf .yui-g{width:74.2%;}.yui-gb .yui-ge div.yui-u,.yui-gb .yui-gf div.yui-u{float:right;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf div.first{float:left;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf div.first{*width:24%;_width:20%;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%;}.yui-ge div.first .yui-gd .yui-u{width:65%;}.yui-ge div.first .yui-gd div.first{width:32%;}#hd:after,#bd:after,#ft:after,.yui-g:after,.yui-gb:after,.yui-gc:after,.yui-gd:after,.yui-ge:after,.yui-gf:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#hd,#bd,#ft,.yui-g,.yui-gb,.yui-gc,.yui-gd,.yui-ge,.yui-gf{zoom:1;} 9 | -------------------------------------------------------------------------------- /data/static/css/screen.css: -------------------------------------------------------------------------------- 1 | @import url("reset-fonts-grids.css"); 2 | 3 | html { background: #f9f9f9; color: black; } 4 | body { margin: 10px; } 5 | 6 | fieldset { border: 1px solid #ccc; padding: 1em; } 7 | legend { font-weight: bold; margin-left: 1em; padding: 4px; } 8 | textarea, input[type='text'], input[type='password'], select { border: 1px solid #ccc; background: #fff; } 9 | textarea:hover, input[type='text']:hover, input[type='password']:hover, select:hover { border-color: #aaa; } 10 | textarea:focus, input[type='text']:focus, input[type='password']:focus, select:focus { border-color: #888; outline: 2px solid #ffffaa; } 11 | input, select { cursor: pointer; } 12 | input[type='text'] { cursor: text; } 13 | textarea, input { padding: .3em .4em .15em .4em; } 14 | select { padding: .1em .2em 0 .2em; } 15 | option { padding: 0 .4em; } 16 | table, tr, td, th { border: none; } 17 | hr { height: 1px; color: #aaa; background-color: #aaa; border: 0; margin: .2em 0 .2em 0; } 18 | 19 | h1, h2, h3, h4, h5, h6 { font-weight: normal; border-bottom: 1px solid #aaa; } 20 | 21 | h1.pageTitle { font-size: 197%; margin: 0.2em 0 .5em; } 22 | 23 | h1 { font-size: 153.9%; margin: 1.07em 0 .535em; } 24 | h2 { font-size: 138.5%; margin: 1.14em 0 .57em; } 25 | h3 { font-size: 123.1%; margin: 1.23em 0 .615em; } 26 | h4 { font-size: 116%; margin: 1.33em 0 .67em; } 27 | h5 { font-size: 108%; margin: 1.6em 0 .8em; } 28 | h6 { font-size: 100%; margin: 1.6em 0 .8em; } 29 | 30 | strong { font-weight: bold; } 31 | ul { list-style-type: square; } 32 | dt { font-weight: bold; margin-bottom: .1em; } 33 | 34 | optgroup{ font-weight: normal; } 35 | abbr, acronym { border-bottom:1px dotted #000; cursor:help; } 36 | em { font-style: italic; } 37 | del { text-decoration: line-through; } 38 | 39 | blockquote, ul, ol, dl { margin: 1em; } 40 | ol, ul, dl { margin-left: 2em; } 41 | dl dd { margin-left: 1em; } 42 | th, td { padding: .5em; } 43 | th { font-weight: bold; } 44 | caption { margin-bottom: .5em; text-align: center; } 45 | sup { vertical-align: super; } 46 | sub { vertical-align: sub; } 47 | sub, sup { line-height: 0.3em; } 48 | p, fieldset, table, pre { margin-bottom: 1em; } 49 | button, input[type="checkbox"], input[type="radio"], input[type="reset"], input[type="submit"], input[type="button"] { padding: 1px; } 50 | 51 | blockquote { padding: 0 1.6em; color: #666; } 52 | 53 | a:link { text-decoration: underline; color: #36c; } 54 | a:visited { text-decoration: underline; color: #99c; } 55 | a:hover { text-decoration: underline; color: #c33; } 56 | a:active, a:focus { text-decoration: underline; color: #000; } 57 | 58 | input.search_term { width: 95% } 59 | 60 | button:hover, a.button:hover { background-color:#dff4ff; border:1px solid #c2e1ef; color:#336699; } 61 | a.button:active, button:active { background-color:#6299c5; border:1px solid #6299c5; color:#fff; } 62 | 63 | h1 > a:link, h1 > a:active, h1 > a:hover, h1 > a:focus, h1 > a:visited, 64 | h2 > a:link, h2 > a:active, h2 > a:hover, h2 > a:focus, h2 > a:visited, 65 | h3 > a:link, h3 > a:active, h3 > a:hover, h3 > a:focus, h3 > a:visited, 66 | h4 > a:link, h4 > a:active, h4 > a:hover, h4 > a:focus, h4 > a:visited, 67 | h5 > a:link, h5 > a:active, h5 > a:hover, h5 > a:focus, h5 > a:visited, 68 | h6 > a:link, h6 > a:active, h6 > a:hover, h6 > a:focus, h6 > a:visited { 69 | color: black; text-decoration: none; } 70 | 71 | #content { border: 1px solid #ccc; background-color: #fff; padding: 1em; font-size: 108%; } 72 | #content p, #content pre, #content li { line-height: 140%; } 73 | 74 | #userbox { text-align: right; font-weight: bold; margin: 1em; } 75 | 76 | #logo { min-height: 50px; } 77 | 78 | #sidebar fieldset { background-color: white; margin-bottom: 1em; padding: 0; font-size: 93%; } 79 | #sidebar fieldset, #sidebar fieldset legend { font-weight: normal; } 80 | #sidebar ul { padding: 0; margin: 0; margin-left: 1.6em; line-height: 1.5em; } 81 | #sidebar ul li { color: #888; list-style: square; } 82 | 83 | div#TOC { background-color: #f9f9f9; border: 10px solid white; margin: 0.8em; margin-right: 0; padding: 0.4em; } 84 | #TOC ul { padding: 0 0 0 1em; margin: 0; list-style: none; } 85 | 86 | #sidebar input, #sidebar select { font-size: 93%; padding: 0.1em; } 87 | #sidebar input[type='submit'] { border: none; background-color: #ccc; color: white; } 88 | 89 | #exportbox select { width: 8.5em; border: 1px solid #ccc; padding: 0; } 90 | #exportbox { margin: 0.3em 0 0.5em 0.4em; padding: 0; } 91 | 92 | #footer { padding: 1em; color: #888; text-align: center; font-size: 93%; } 93 | 94 | #searchform { padding: 0; margin: 0.3em 0 0.5em 0.4em; } 95 | #searchform input[type='text'] { width: 8.5em; border: 1px solid #ccc; } 96 | 97 | div#categoryList { padding: 0em; margin: 1em 0 0 0; border: 1px dashed #ccc; } 98 | #categoryList ul > li { display: inline; padding-right: 1em; } 99 | 100 | #editform textarea { height: 25em; width: 98%; font-family: monospace; font-size: 93%; } 101 | #editform #logMsg { width: 98%; margin-right: 1em; margin-bottom: 0.3em; } 102 | 103 | #goform { padding: 0; margin: 0.3em 0 0.5em 0.4em; } 104 | #goform input[type='text'] { width: 8.5em; border: 1px solid #ccc; } 105 | 106 | .search_result { margin-bottom: 15px; } 107 | .search_result .match { margin-bottom: 15px; } 108 | 109 | pre>code { display: block; } 110 | pre.matches { margin: 0; padding: 0; } 111 | #pattern { background-color: yellow; font-weight: bold; } 112 | pre.matches span.highlighted { background-color: yellow; } 113 | 114 | .added { background-color: yellow; } 115 | .deleted { text-decoration: line-through; color: gray; } 116 | 117 | /* .req is used to hide a honeypot in a form */ 118 | .req { display: none; } 119 | 120 | ul.messages > li { color: red; list-style: square; font-weight: bold; } 121 | 122 | ul.tabs { padding: 0; margin: 0 0 1px 0; } 123 | ul.tabs li { display: inline; border: 1px solid #ccc; border-bottom: none; padding: 0 0.6em 0 0.6em; 124 | margin: 0 0 0 1.2em; background: white; } 125 | ul.tabs li.selected { border-bottom: 3px solid white; } 126 | ul.tabs li a { text-decoration: none; font-size: 93%; font-weight: bold; margin: 0; color: #36c; } 127 | 128 | .index ul { list-style: none; margin: 0; padding: 0; } 129 | .index li { list-style: none; background-position: 0 1px; background-repeat: no-repeat; padding-left: 20px; } 130 | .index li.page { background-image: url(../img/icons/page.png); } 131 | .index li.folder { background-image: url(../img/icons/folder.png); } 132 | .index a { color: #000000; cursor: pointer; text-decoration: none; } 133 | .index a + a { margin-left: 0.5em; } 134 | .index a:hover { text-decoration: underline; } 135 | 136 | a.updir { font-weight: bold; } 137 | 138 | h2.revision { font-size: 100%; color: #888; font-style: italic; border: none; margin: 0 0 0.5em 0; padding: 0; } 139 | 140 | div.markupHelp pre { font-size: 77%; overflow: auto; } 141 | 142 | .login { display: none; } 143 | 144 | /* Style the footnotes; from gwern.net */ 145 | #footnotediv div { 146 | background-color: white; 147 | padding: 3px; 148 | padding: 12px; 149 | max-width: 800px; 150 | border: 1px solid #CDBBB5; 151 | box-shadow: #555 0 0 10px; 152 | -webkit-box-shadow: #555 0 0 10px; 153 | -moz-box-shadow: 0 0 10px #555; 154 | } 155 | /* Deal with multiple footnotes one after another; Charuru */ 156 | sup + sup { margin-left: 2px; } 157 | 158 | /* Make theme responsive */ 159 | @media (max-width: 768px) { 160 | #yui-main { 161 | float:none!important; 162 | margin-left: 0!important; 163 | } 164 | #maincol { 165 | margin-left: 0!important; 166 | } 167 | #sidebar { 168 | width: 100%; 169 | float: none; 170 | } 171 | #logo { 172 | float: left; 173 | margin-right:5%; 174 | margin-top: 12px; 175 | width: 30%; 176 | } 177 | .sitenav { 178 | float: left; 179 | margin-right: 5%; 180 | width: 30%; 181 | } 182 | .pageTools { 183 | float: right; 184 | width: 30% 185 | } 186 | } 187 | @media (max-device-width: 568px) { 188 | #logo, .sitenav, .pageTools { 189 | float: none; 190 | width: 100%; 191 | } 192 | } 193 | 194 | -------------------------------------------------------------------------------- /data/static/img/icons/feed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgm/gitit/f8a847cfea55773beeaea4eb5051f6454ebba4ae/data/static/img/icons/feed.png -------------------------------------------------------------------------------- /data/static/img/icons/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgm/gitit/f8a847cfea55773beeaea4eb5051f6454ebba4ae/data/static/img/icons/folder.png -------------------------------------------------------------------------------- /data/static/img/icons/page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgm/gitit/f8a847cfea55773beeaea4eb5051f6454ebba4ae/data/static/img/icons/page.png -------------------------------------------------------------------------------- /data/static/img/lambda-bann.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgm/gitit/f8a847cfea55773beeaea4eb5051f6454ebba4ae/data/static/img/lambda-bann.png -------------------------------------------------------------------------------- /data/static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgm/gitit/f8a847cfea55773beeaea4eb5051f6454ebba4ae/data/static/img/logo.png -------------------------------------------------------------------------------- /data/static/js/MathMLinHTML.js: -------------------------------------------------------------------------------- 1 | /* 2 | March 19, 2004 MathHTML (c) Peter Jipsen http://www.chapman.edu/~jipsen 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2 of the License, or (at 7 | your option) any later version. 8 | This program is distributed in the hope that it will be useful, but 9 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 10 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 | (at http://www.gnu.org/copyleft/gpl.html) for more details. 12 | */ 13 | 14 | function convertMath(node) {// for Gecko 15 | if (node.nodeType==1) { 16 | var newnode = 17 | document.createElementNS("http://www.w3.org/1998/Math/MathML", 18 | node.nodeName.toLowerCase()); 19 | for(var i=0; i < node.attributes.length; i++) 20 | newnode.setAttribute(node.attributes[i].nodeName, 21 | node.attributes[i].nodeValue); 22 | for (var i=0; i"); 69 | document.write(""); 70 | } 71 | if(typeof window.addEventListener != 'undefined'){ 72 | window.addEventListener('load', convert, false); 73 | } 74 | if(typeof window.attachEvent != 'undefined') { 75 | window.attachEvent('onload', convert); 76 | } 77 | -------------------------------------------------------------------------------- /data/static/js/dragdiff.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | $("#content").prepend("

Drag one revision onto another to see differences.

"); 3 | $(".difflink").draggable({helper: "clone"}); 4 | $(".difflink").droppable({ 5 | accept: ".difflink", 6 | drop: function(ev, ui) { 7 | var targetOrder = parseInt($(this).attr("order")); 8 | var sourceOrder = parseInt($(ui.draggable).attr("order")); 9 | var diffurl = $(this).attr("diffurl"); 10 | if (targetOrder < sourceOrder) { 11 | var fromRev = $(this).attr("revision"); 12 | var toRev = $(ui.draggable).attr("revision"); 13 | } else { 14 | var toRev = $(this).attr("revision"); 15 | var fromRev = $(ui.draggable).attr("revision"); 16 | }; 17 | location.href = diffurl + '?from=' + fromRev + '&to=' + toRev; 18 | } 19 | }); 20 | }); 21 | 22 | -------------------------------------------------------------------------------- /data/static/js/footnotes.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | Footnotes.setup(); 3 | }); 4 | 5 | var Footnotes = { 6 | footnotetimeout: false, 7 | setup: function() { 8 | var footnotelinks = $('.footnoteRef') 9 | 10 | footnotelinks.unbind('mouseover',Footnotes.footnoteover); 11 | footnotelinks.unbind('mouseout',Footnotes.footnoteoout); 12 | 13 | footnotelinks.bind('mouseover',Footnotes.footnoteover); 14 | footnotelinks.bind('mouseout',Footnotes.footnoteoout); 15 | }, 16 | footnoteover: function() { 17 | clearTimeout(Footnotes.footnotetimeout); 18 | $('#footnotediv').stop(); 19 | $('#footnotediv').remove(); 20 | 21 | var id = $(this).attr('href').substr(1); 22 | var position = $(this).offset(); 23 | 24 | var div = $(document.createElement('div')); 25 | div.attr('id','footnotediv'); 26 | div.bind('mouseover',Footnotes.divover); 27 | div.bind('mouseout',Footnotes.footnoteoout); 28 | 29 | var el = document.getElementById(id); 30 | div.html('
'+$(el).html()+'
'); 31 | 32 | $(document.body).append(div); 33 | 34 | var left = position.left; 35 | if(left + 420 > $(window).width() + $(window).scrollLeft()) 36 | left = $(window).width() - 420 + $(window).scrollLeft(); 37 | var top = position.top+20; 38 | if(top + div.height() > $(window).height() + $(window).scrollTop()) 39 | top = position.top - div.height() - 15; 40 | div.css({ 41 | left:left, 42 | top:top, 43 | opacity:0.95, 44 | position: "absolute" 45 | }); 46 | }, 47 | footnoteoout: function() { 48 | Footnotes.footnotetimeout = setTimeout(function() { 49 | $('#footnotediv').animate({ 50 | opacity: 0 51 | }, 600, function() { 52 | $('#footnotediv').remove(); 53 | }); 54 | },100); 55 | }, 56 | divover: function() { 57 | clearTimeout(Footnotes.footnotetimeout); 58 | $('#footnotediv').stop(); 59 | $('#footnotediv').css({ 60 | opacity: 0.9 61 | }); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /data/static/js/jquery.hotkeys-0.7.9.min.js: -------------------------------------------------------------------------------- 1 | (function(jQuery){jQuery.fn.__bind__=jQuery.fn.bind;jQuery.fn.__unbind__=jQuery.fn.unbind;jQuery.fn.__find__=jQuery.fn.find;var hotkeys={version:'0.7.9',override:/keypress|keydown|keyup/g,triggersMap:{},specialKeys:{27:'esc',9:'tab',32:'space',13:'return',8:'backspace',145:'scroll',20:'capslock',144:'numlock',19:'pause',45:'insert',36:'home',46:'del',35:'end',33:'pageup',34:'pagedown',37:'left',38:'up',39:'right',40:'down',109:'-',112:'f1',113:'f2',114:'f3',115:'f4',116:'f5',117:'f6',118:'f7',119:'f8',120:'f9',121:'f10',122:'f11',123:'f12',191:'/'},shiftNums:{"`":"~","1":"!","2":"@","3":"#","4":"$","5":"%","6":"^","7":"&","8":"*","9":"(","0":")","-":"_","=":"+",";":":","'":"\"",",":"<",".":">","/":"?","\\":"|"},newTrigger:function(type,combi,callback){var result={};result[type]={};result[type][combi]={cb:callback,disableInInput:false};return result;}};hotkeys.specialKeys=jQuery.extend(hotkeys.specialKeys,{96:'0',97:'1',98:'2',99:'3',100:'4',101:'5',102:'6',103:'7',104:'8',105:'9',106:'*',107:'+',109:'-',110:'.',111:'/'});jQuery.fn.find=function(selector){this.query=selector;return jQuery.fn.__find__.apply(this,arguments);};jQuery.fn.unbind=function(type,combi,fn){if(jQuery.isFunction(combi)){fn=combi;combi=null;} 2 | if(combi&&typeof combi==='string'){var selectorId=((this.prevObject&&this.prevObject.query)||(this[0].id&&this[0].id)||this[0]).toString();var hkTypes=type.split(' ');for(var x=0;x' + '$1' + ''); 24 | }); 25 | }; 26 | function toggleMatches(obj) { 27 | var pattern = $('#pattern').text(); 28 | var matches = obj.next('.matches') 29 | matches.slideToggle(300); 30 | matches.highlightPattern(pattern, 'highlighted'); 31 | if (obj.html() == '[show matches]') { 32 | obj.html('[hide matches]'); 33 | } else { 34 | obj.html('[show matches]'); 35 | }; 36 | } 37 | $(function() { 38 | $('a.showmatch').attr('onClick', 'toggleMatches($(this));'); 39 | $('pre.matches').hide(); 40 | $('a.showmatch').show(); 41 | }); 42 | -------------------------------------------------------------------------------- /data/static/js/uploadForm.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | $("#file").change(function () { 3 | var fn = $(this).val().replace(/.*\\/,""); 4 | $("#wikiname").val(fn); 5 | }); 6 | }); 7 | -------------------------------------------------------------------------------- /data/static/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: /_ 3 | -------------------------------------------------------------------------------- /data/templates/content.st: -------------------------------------------------------------------------------- 1 |
2 | $if(revision)$ 3 |

Revision $revision$ (click the page title to view the current version)

4 | $endif$ 5 |

$pagetitle$

6 | $if(messages)$ 7 | $messages()$ 8 | $endif$ 9 | $content$ 10 |
11 | -------------------------------------------------------------------------------- /data/templates/expire.st: -------------------------------------------------------------------------------- 1 | $if(usecache)$ 2 | 3 | 11 | $endif$ 12 | -------------------------------------------------------------------------------- /data/templates/footer.st: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /data/templates/getuser.st: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /data/templates/listitem.st: -------------------------------------------------------------------------------- 1 |
  • $it$
  • 2 | -------------------------------------------------------------------------------- /data/templates/logo.st: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /data/templates/markuphelp.st: -------------------------------------------------------------------------------- 1 |
    2 | $markuphelp$ 3 |
    4 | -------------------------------------------------------------------------------- /data/templates/messages.st: -------------------------------------------------------------------------------- 1 |
      2 | $messages:listitem()$ 3 |
    4 | -------------------------------------------------------------------------------- /data/templates/page.st: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | $if(feed)$ 7 | 8 | 9 | $endif$ 10 | $wikititle$ - $pagetitle$ 11 | $if(printable)$ 12 | 13 | $else$ 14 | 15 | 16 | $endif$ 17 | 18 | 19 | 20 |
    21 |
    22 |
    23 | $userbox()$ 24 | $tabs$ 25 | $content()$ 26 | $footer()$ 27 |
    28 |
    29 | 41 |
    42 | $javascripts$ 43 | $expire()$ 44 | $getuser()$ 45 | 46 | 47 | -------------------------------------------------------------------------------- /data/templates/pagetools.st: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | This page 4 | 12 |
    13 |
    14 | -------------------------------------------------------------------------------- /data/templates/sitenav.st: -------------------------------------------------------------------------------- 1 | 28 | -------------------------------------------------------------------------------- /data/templates/userbox.st: -------------------------------------------------------------------------------- 1 |
    2 | 6 |   7 | 8 | 9 |
    10 | -------------------------------------------------------------------------------- /expireGititCache.hs: -------------------------------------------------------------------------------- 1 | {- 2 | expireGititCache - (C) 2009 John MacFarlane, licensed under the GPL 3 | 4 | This program is designed to be used in post-update hooks and other scripts. 5 | 6 | Usage: expireGititCache base-url [file..] 7 | 8 | Example: 9 | 10 | expireGititCache http://localhost:5001 page1.page foo/bar.hs "Front Page.page" 11 | 12 | will produce POST requests to http://localhost:5001/_expire/page1, 13 | http://localhost:5001/_expire/foo/bar.hs, and 14 | http://localhost:5001/_expire/Front Page. 15 | 16 | Return statuses: 17 | 18 | 0 -> the cached page was successfully expired (or was not cached in the first place) 19 | 1 -> fewer than two arguments were supplied 20 | 3 -> did not receive a 200 OK response from the request 21 | 5 -> could not parse the uri 22 | 23 | -} 24 | 25 | module Main 26 | where 27 | import Network.HTTP 28 | import System.Environment 29 | import Network.URI 30 | import System.FilePath 31 | import Control.Monad 32 | import System.IO 33 | import System.Exit 34 | 35 | main :: IO () 36 | main = do 37 | args <- getArgs 38 | (uriString : files) <- if length args < 2 39 | then usageMessage >> return [""] 40 | else return args 41 | uri <- case parseURI uriString of 42 | Just u -> return u 43 | Nothing -> do 44 | hPutStrLn stderr ("Could not parse URI " ++ uriString) 45 | exitWith (ExitFailure 5) 46 | forM_ files (expireFile uri) 47 | 48 | usageMessage :: IO () 49 | usageMessage = do 50 | hPutStrLn stderr $ "Usage: expireGititCache base-url [file..]\n" ++ 51 | "Example: expireGititCache http://localhost:5001 page1.page foo/bar.hs" 52 | exitWith (ExitFailure 1) 53 | 54 | expireFile :: URI -> FilePath -> IO () 55 | expireFile uri file = do 56 | let path' = if takeExtension file == ".page" 57 | then dropExtension file 58 | else file 59 | let uri' = uri{uriPath = "/_expire/" ++ urlEncode path'} 60 | resResp <- simpleHTTP Request{rqURI = uri', rqMethod = POST, rqHeaders = [], rqBody = ""} 61 | case resResp of 62 | Left connErr -> error $ show connErr 63 | Right (Response (2,0,0) _ _ _) -> return () 64 | _ -> do 65 | hPutStrLn stderr ("Request for " ++ show uri' ++ " did not return success status") 66 | exitWith (ExitFailure 3) 67 | -------------------------------------------------------------------------------- /gitit.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 2.0 2 | name: gitit 3 | version: 0.15.1.2 4 | build-type: Simple 5 | synopsis: Wiki using happstack, git or darcs, and pandoc. 6 | description: Gitit is a wiki backed by a git, darcs, or mercurial 7 | filestore. Pages and uploaded files can be modified either 8 | directly via the VCS's command-line tools or through 9 | the wiki's web interface. Pandoc is used for markup 10 | processing, so pages may be written in 11 | (extended) markdown, reStructuredText, LaTeX, HTML, 12 | or literate Haskell. 13 | . 14 | Notable features include 15 | . 16 | * plugins: dynamically loaded page 17 | transformations written in Haskell (see 18 | "Network.Gitit.Interface") 19 | . 20 | * conversion of TeX math to MathML for display in 21 | web browsers 22 | . 23 | * syntax highlighting of source code 24 | files and code snippets 25 | . 26 | * Atom feeds (site-wide and per-page) 27 | . 28 | * a library, "Network.Gitit", that makes it simple 29 | to include a gitit wiki in any happstack application 30 | . 31 | For usage information: @gitit --help@ 32 | 33 | category: Network 34 | license: GPL 35 | license-file: LICENSE 36 | author: John MacFarlane 37 | maintainer: jgm@berkeley.edu 38 | bug-reports: http://github.com/jgm/gitit/issues 39 | stability: experimental 40 | extra-source-files: data/static/js/jquery-1.2.6.js 41 | data/static/js/jquery.hotkeys-0.7.9.js 42 | data/static/js/jquery-ui.core-1.6rc2.js 43 | data/static/js/jquery-ui.droppable-1.6rc2.js 44 | data/static/js/jquery-ui.draggable-1.6rc2.js 45 | data/static/js/jquery-ui.tabs-1.6rc2.js 46 | extra-doc-files: CHANGES, YUI-LICENSE, BLUETRIP-LICENSE, TANGOICONS 47 | data-files: data/static/css/screen.css, data/static/css/print.css, 48 | data/static/css/ie.css, data/static/css/highlighting.css, 49 | data/static/css/reset-fonts-grids.css, 50 | data/static/css/custom.css, 51 | data/static/img/logo.png, data/static/img/icons/feed.png, 52 | data/static/img/icons/folder.png, data/static/img/icons/page.png, 53 | data/static/js/dragdiff.js, data/static/js/jquery-1.2.6.min.js, 54 | data/static/js/uploadForm.js, data/static/js/jquery-ui-combined-1.6rc2.min.js, 55 | data/static/js/jquery.hotkeys-0.7.9.min.js, 56 | data/static/js/preview.js, data/static/js/search.js, 57 | data/static/js/MathMLinHTML.js, data/static/js/footnotes.js, 58 | data/static/robots.txt, 59 | data/s5/default/blank.gif, 60 | data/s5/default/bodybg.gif, 61 | data/s5/default/framing.css, 62 | data/s5/default/iepngfix.htc, 63 | data/s5/default/opera.css, 64 | data/s5/default/outline.css, 65 | data/s5/default/pretty.css, 66 | data/s5/default/print.css, 67 | data/s5/default/s5-core.css, 68 | data/s5/default/slides.css, 69 | data/s5/default/slides.js, 70 | data/s5/default/slides.min.js, 71 | data/post-update, data/FrontPage.page, data/Help.page, 72 | data/markup.Markdown, data/markup.RST, 73 | data/markup.Textile, data/markup.Org, data/markup.DocBook, 74 | data/markup.HTML, data/markup.LaTeX, 75 | data/default.conf, 76 | data/templates/page.st, data/templates/content.st, 77 | data/templates/userbox.st, data/templates/footer.st, 78 | data/templates/logo.st, data/templates/markuphelp.st, 79 | data/templates/pagetools.st, data/templates/sitenav.st, 80 | data/templates/messages.st, data/templates/listitem.st, 81 | data/templates/expire.st, data/templates/getuser.st, 82 | data/markupHelp/Markdown, data/markupHelp/Markdown+LHS, 83 | data/markupHelp/RST, data/markupHelp/RST+LHS, 84 | data/markupHelp/LaTeX, data/markupHelp/LaTeX+LHS, 85 | data/markupHelp/HTML, data/markupHelp/Org, 86 | plugins/CapitalizeEmphasis.hs, 87 | plugins/PigLatin.hs, 88 | plugins/Dot.hs, 89 | plugins/ImgTex.hs, 90 | plugins/Interwiki.hs, 91 | plugins/Deprofanizer.hs, 92 | plugins/WebArchiver.hs, 93 | plugins/ShowUser.hs, 94 | plugins/Signature.hs, 95 | plugins/Subst.hs, 96 | README.markdown 97 | 98 | Source-repository head 99 | type: git 100 | location: git://github.com/jgm/gitit.git 101 | 102 | Flag plugins 103 | description: Compile in support for plugins. This will increase the size of 104 | the executable and the memory it uses, so those who will not need 105 | plugins should disable this flag. 106 | default: True 107 | 108 | Library 109 | hs-source-dirs: src 110 | exposed-modules: Network.Gitit, Network.Gitit.ContentTransformer, 111 | Network.Gitit.Types, Network.Gitit.Framework, 112 | Network.Gitit.Initialize, Network.Gitit.Config, 113 | Network.Gitit.Layout, Network.Gitit.Authentication, 114 | Network.Gitit.Authentication.Github, 115 | Network.Gitit.Util, Network.Gitit.Server 116 | Network.Gitit.Cache, Network.Gitit.State, 117 | Network.Gitit.Handlers, 118 | Network.Gitit.Plugins, 119 | Network.Gitit.Page, Network.Gitit.Feed, 120 | Network.Gitit.Compat.Except, 121 | Paths_gitit 122 | autogen-modules: Paths_gitit 123 | build-depends: base >= 4.9 && < 5, 124 | syb, 125 | filepath, 126 | safe, 127 | parsec, 128 | pretty, 129 | xhtml, 130 | containers, 131 | process, 132 | filepath, 133 | directory, 134 | mtl, 135 | old-time, 136 | temporary, 137 | pandoc >= 2.9 && < 2.20 || >= 3.0 && < 3.7, 138 | pandoc-types >= 1.20 && < 1.24, 139 | skylighting >= 0.8.2.3 && < 0.15, 140 | bytestring, 141 | text, 142 | random, 143 | utf8-string >= 0.3 && < 1.1, 144 | SHA > 1, 145 | HTTP >= 4000.0, 146 | HStringTemplate >= 0.8.8 && < 0.9, 147 | old-locale, 148 | time, 149 | recaptcha >= 0.1, 150 | filestore >= 0.6.5 && < 0.7, 151 | zlib >= 0.5 && < 0.8, 152 | url >= 2.1, 153 | happstack-server >= 7.5 && < 7.10, 154 | base64-bytestring >= 0.1, 155 | xml >= 1.3.5, 156 | hslogger >= 1, 157 | feed >= 1.0 && < 1.4, 158 | xml-types >= 0.3, 159 | xss-sanitize >= 0.3 && < 0.4, 160 | tagsoup >= 0.13 && < 0.15, 161 | blaze-html >= 0.5 && < 0.10, 162 | json >= 0.4 && < 0.12, 163 | uri-bytestring >= 0.2.3.3, 164 | split, 165 | hoauth2 >= 2.3.0 && < 2.15, 166 | xml-conduit >= 1.5 && < 1.10, 167 | http-conduit >= 2.1.6 && < 2.4, 168 | http-client-tls >= 0.2.2 && < 0.4, 169 | aeson >= 0.7 && < 2.3, 170 | uuid >= 1.3 && < 1.4, 171 | network-uri >= 2.6, 172 | network >= 2.6 && < 3.3, 173 | network-bsd >= 2.8.1 && < 2.9, 174 | doctemplates >= 0.7.1 175 | if flag(plugins) 176 | exposed-modules: Network.Gitit.Interface 177 | build-depends: ghc, ghc-paths 178 | cpp-options: -D_PLUGINS 179 | default-extensions: CPP 180 | default-language: Haskell2010 181 | ghc-options: -Wall -fno-warn-unused-do-bind 182 | ghc-prof-options: -fprof-auto-exported 183 | 184 | Executable gitit 185 | hs-source-dirs: . 186 | main-is: gitit.hs 187 | build-depends: base >= 4.15 && < 5, 188 | gitit, 189 | mtl, 190 | hslogger, 191 | bytestring, 192 | text, 193 | utf8-string, 194 | directory, 195 | network-uri >= 2.6, 196 | network >= 2.6 197 | other-modules: Paths_gitit 198 | default-extensions: CPP 199 | default-language: Haskell2010 200 | ghc-options: -Wall -threaded -fno-warn-unused-do-bind 201 | ghc-prof-options: -fprof-auto-exported -rtsopts 202 | 203 | Executable expireGititCache 204 | hs-source-dirs: . 205 | main-is: expireGititCache.hs 206 | build-depends: base >= 4.9 && < 5, HTTP, url, filepath, syb, 207 | network-uri >= 2.6, 208 | network >= 2.6 209 | ghc-options: -Wall 210 | default-language: Haskell2010 211 | -------------------------------------------------------------------------------- /gitit.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | {- 3 | Copyright (C) 2008 John MacFarlane 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | -} 19 | 20 | module Main where 21 | 22 | import Network.Gitit 23 | import Network.Gitit.Server 24 | import Network.Gitit.Util (readFileUTF8) 25 | import System.Directory 26 | import Data.Maybe (isNothing) 27 | import Data.Text.Encoding (encodeUtf8) 28 | import Network.Gitit.Compat.Except() 29 | import Control.Monad 30 | import System.Log.Logger (Priority(..), setLevel, setHandlers, 31 | getLogger, saveGlobalLogger) 32 | import System.Log.Handler.Simple (fileHandler) 33 | import System.Environment 34 | import System.Exit 35 | import System.IO (stderr) 36 | import System.Console.GetOpt 37 | import Network.Socket hiding (Debug) 38 | import Data.Version (showVersion) 39 | import qualified Data.ByteString.Char8 as B 40 | import Data.ByteString.UTF8 (fromString) 41 | 42 | import Paths_gitit (version, getDataFileName) 43 | 44 | main :: IO () 45 | main = do 46 | 47 | -- parse options to get config file 48 | args <- getArgs >>= parseArgs 49 | 50 | -- sequence in Either monad gets first Left or all Rights 51 | opts <- case sequence args of 52 | Left Help -> putErr ExitSuccess =<< usageMessage 53 | Left Version -> do 54 | progname <- getProgName 55 | putErr ExitSuccess (progname ++ " version " ++ 56 | showVersion version ++ compileInfo ++ copyrightMessage) 57 | Left PrintDefaultConfig -> getDataFileName "data/default.conf" >>= 58 | readFileUTF8 >>= B.putStrLn . encodeUtf8 >> exitSuccess 59 | Right xs -> return xs 60 | 61 | conf' <- case [f | ConfigFile f <- opts] of 62 | fs -> getConfigFromFiles fs 63 | 64 | let conf = foldl handleFlag conf' opts 65 | 66 | -- check for external programs that are needed 67 | let repoProg = case repositoryType conf of 68 | Mercurial -> "hg" 69 | Darcs -> "darcs" 70 | Git -> "git" 71 | let prereqs = ["grep", repoProg] 72 | forM_ prereqs $ \prog -> 73 | findExecutable prog >>= \mbFind -> 74 | when (isNothing mbFind) $ error $ 75 | "Required program '" ++ prog ++ "' not found in system path." 76 | 77 | -- set up logging 78 | let level = if debugMode conf then DEBUG else logLevel conf 79 | logFileHandler <- fileHandler (logFile conf) level 80 | serverLogger <- getLogger "Happstack.Server.AccessLog.Combined" 81 | gititLogger <- getLogger "gitit" 82 | saveGlobalLogger $ setLevel level $ setHandlers [logFileHandler] serverLogger 83 | saveGlobalLogger $ setLevel level $ setHandlers [logFileHandler] gititLogger 84 | 85 | -- setup the page repository, template, and static files, if they don't exist 86 | createRepoIfMissing conf 87 | createStaticIfMissing conf 88 | createTemplateIfMissing conf 89 | 90 | -- initialize state 91 | initializeGititState conf 92 | 93 | let serverConf = nullConf { validator = Nothing, port = portNumber conf, 94 | timeout = 20, logAccess = Nothing } 95 | 96 | -- open the requested interface 97 | sock <- socket AF_INET Stream defaultProtocol 98 | setSocketOption sock ReuseAddr 1 99 | let portNum = show (portNumber conf) 100 | addrs <- getAddrInfo Nothing (Just $ address conf) (Just portNum) 101 | case addrs of 102 | addr:_ -> bind sock $ addrAddress addr 103 | [] -> error $ "Could not resolve " ++ address conf ++ ":" ++ portNum 104 | listen sock 10 105 | 106 | -- start the server 107 | simpleHTTPWithSocket sock serverConf $ msum [ wiki conf 108 | , dir "_reloadTemplates" (reloadTemplates conf) 109 | ] 110 | 111 | data ExitOpt 112 | = Help 113 | | Version 114 | | PrintDefaultConfig 115 | 116 | data ConfigOpt 117 | = ConfigFile FilePath 118 | | Port Int 119 | | Listen String 120 | | Debug 121 | deriving (Eq) 122 | 123 | type Opt = Either ExitOpt ConfigOpt 124 | 125 | flags :: [OptDescr Opt] 126 | flags = 127 | [ Option ['h'] ["help"] (NoArg (Left Help)) 128 | "Print this help message" 129 | , Option ['v'] ["version"] (NoArg (Left Version)) 130 | "Print version information" 131 | , Option ['p'] ["port"] (ReqArg (Right . Port . read) "PORT") 132 | "Specify port" 133 | , Option ['l'] ["listen"] (ReqArg (Right . Listen) "INTERFACE") 134 | "Specify IP address to listen on" 135 | , Option [] ["print-default-config"] (NoArg (Left PrintDefaultConfig)) 136 | "Print default configuration" 137 | , Option [] ["debug"] (NoArg (Right Debug)) 138 | "Print debugging information on each request" 139 | , Option ['f'] ["config-file"] (ReqArg (Right . ConfigFile) "FILE") 140 | "Specify configuration file" 141 | ] 142 | 143 | parseArgs :: [String] -> IO [Opt] 144 | parseArgs argv = 145 | case getOpt Permute flags argv of 146 | (opts,_,[]) -> return opts 147 | (_,_,errs) -> putErr (ExitFailure 1) . (concat errs ++) =<< usageMessage 148 | 149 | usageMessage :: IO String 150 | usageMessage = do 151 | progname <- getProgName 152 | return $ usageInfo ("Usage: " ++ progname ++ " [opts...]") flags 153 | 154 | copyrightMessage :: String 155 | copyrightMessage = "\nCopyright (C) 2008 John MacFarlane\n" ++ 156 | "This is free software; see the source for copying conditions. There is no\n" ++ 157 | "warranty, not even for merchantability or fitness for a particular purpose." 158 | 159 | compileInfo :: String 160 | compileInfo = 161 | #ifdef _PLUGINS 162 | " +plugins" 163 | #else 164 | " -plugins" 165 | #endif 166 | 167 | handleFlag :: Config -> ConfigOpt -> Config 168 | handleFlag conf Debug = conf{ debugMode = True, logLevel = DEBUG } 169 | handleFlag conf (Port p) = conf { portNumber = p } 170 | handleFlag conf (Listen l) = conf { address = l } 171 | handleFlag conf _ = conf 172 | 173 | putErr :: ExitCode -> String -> IO a 174 | putErr c s = B.hPutStrLn stderr (fromString s) >> exitWith c 175 | -------------------------------------------------------------------------------- /plugins/CapitalizeEmphasis.hs: -------------------------------------------------------------------------------- 1 | module CapitalizeEmphasis (plugin) where 2 | 3 | -- This plugin converts emphasized text to ALL CAPS. 4 | -- Not a very useful feature, but useful as an example 5 | -- of how to write a plugin. 6 | 7 | import Network.Gitit.Interface 8 | import Data.Char (toUpper) 9 | 10 | plugin :: Plugin 11 | plugin = mkPageTransform capsTransform 12 | 13 | capsTransform :: [Inline] -> [Inline] 14 | capsTransform (Emph x : xs) = processWith capStr x ++ capsTransform xs 15 | capsTransform (x:xs) = x : capsTransform xs 16 | capsTransform [] = [] 17 | 18 | capStr :: Inline -> Inline 19 | capStr (Str x) = Str (map toUpper x) 20 | capStr x = x 21 | -------------------------------------------------------------------------------- /plugins/Deprofanizer.hs: -------------------------------------------------------------------------------- 1 | module Deprofanizer (plugin) where 2 | 3 | -- This plugin replaces profane words with "XXXXX". 4 | 5 | import Network.Gitit.Interface 6 | import Data.Char (toLower) 7 | 8 | plugin :: Plugin 9 | plugin = mkPageTransform deprofanize 10 | 11 | deprofanize :: Inline -> Inline 12 | deprofanize (Str x) | isBadWord x = Str "XXXXX" 13 | deprofanize x = x 14 | 15 | isBadWord :: String -> Bool 16 | isBadWord x = map toLower x `elem` ["darn", "blasted", "stinker"] 17 | -- there are more, but this is a family program 18 | 19 | -------------------------------------------------------------------------------- /plugins/Dot.hs: -------------------------------------------------------------------------------- 1 | module Dot (plugin) where 2 | 3 | -- This plugin allows you to include a graphviz dot diagram 4 | -- in a page like this: 5 | -- 6 | -- ~~~ {.dot name="diagram1"} 7 | -- digraph G {Hello->World} 8 | -- ~~~ 9 | -- 10 | -- The "dot" executable must be in the path. 11 | -- The generated png file will be saved in the static img directory. 12 | -- If no name is specified, a unique name will be generated from a hash 13 | -- of the file contents. 14 | 15 | import Network.Gitit.Interface 16 | import System.Process (readProcessWithExitCode) 17 | import System.Exit (ExitCode(ExitSuccess)) 18 | -- from the utf8-string package on HackageDB: 19 | import Data.ByteString.Lazy.UTF8 (fromString) 20 | -- from the SHA package on HackageDB: 21 | import Data.Digest.Pure.SHA (sha1, showDigest) 22 | import System.FilePath (()) 23 | 24 | plugin :: Plugin 25 | plugin = mkPageTransformM transformBlock 26 | 27 | transformBlock :: Block -> PluginM Block 28 | transformBlock (CodeBlock (_, classes, namevals) contents) | "dot" `elem` classes = do 29 | cfg <- askConfig 30 | let (name, outfile) = case lookup "name" namevals of 31 | Just fn -> ([Str fn], fn ++ ".png") 32 | Nothing -> ([], uniqueName contents ++ ".png") 33 | liftIO $ do 34 | (ec, _out, err) <- readProcessWithExitCode "dot" ["-Tpng", "-o", 35 | staticDir cfg "img" outfile] contents 36 | let attr = ("image", [], []) 37 | if ec == ExitSuccess 38 | then return $ Para [Image attr name ("/img" outfile, "")] 39 | else error $ "dot returned an error status: " ++ err 40 | transformBlock x = return x 41 | 42 | -- | Generate a unique filename given the file's contents. 43 | uniqueName :: String -> String 44 | uniqueName = showDigest . sha1 . fromString 45 | 46 | -------------------------------------------------------------------------------- /plugins/ImgTex.hs: -------------------------------------------------------------------------------- 1 | module ImgTex (plugin) where 2 | {- 3 | 4 | This plugin provides a clear math LaTeX output. 5 | (* latex and dvipng executable must be in the path.) 6 | 7 | like this: 8 | 9 | ~~~ {.dvipng} 10 | \nabla \times \bm{V} 11 | = 12 | \frac{1}{h_1 h_2 h_3} 13 | \begin{vmatrix} 14 | h_1 e_1 & h_2 e_2 & h_3 e_3 \\ 15 | \frac{\partial}{\partial q_{1}} & 16 | \frac{\partial}{\partial q_{2}} & 17 | \frac{\partial}{\partial q_{3}} \\ 18 | h_1 V_1 & h_2 V_2 & h_3 V_3 19 | \end{vmatrix} 20 | ~~~ 21 | 22 | License: GPL 23 | written by Kohei OZAKI 24 | modified by John MacFarlane to use withTempDir 25 | 26 | -} 27 | 28 | import Network.Gitit.Interface 29 | import System.Process (system) 30 | import System.Directory 31 | import Data.ByteString.Lazy.UTF8 (fromString) 32 | import Data.Digest.Pure.SHA 33 | import System.FilePath 34 | import Control.Monad.Trans (liftIO) 35 | 36 | plugin :: Plugin 37 | plugin = mkPageTransformM transformBlock 38 | 39 | templateHeader, templateFooter :: String 40 | templateHeader = concat 41 | [ "\\documentclass[12pt]{article}\n" 42 | , "\\usepackage{amsmath,amssymb,bm}\n" 43 | , "\\begin{document}\n" 44 | , "\\thispagestyle{empty}\n" 45 | , "\\[\n"] 46 | 47 | templateFooter = 48 | "\n" 49 | ++ "\\]\n" 50 | ++ "\\end{document}\n" 51 | 52 | transformBlock :: Block -> PluginM Block 53 | transformBlock (CodeBlock (_, classes, namevals) contents) 54 | | "dvipng" `elem` classes = do 55 | cfg <- askConfig 56 | let (name, outfile) = case lookup "name" namevals of 57 | Just fn -> ([Str fn], fn ++ ".png") 58 | Nothing -> ([], uniqueName contents ++ ".png") 59 | curr <- liftIO getCurrentDirectory 60 | liftIO $ withTempDir "gitit-imgtex" $ \tmpdir -> do 61 | setCurrentDirectory tmpdir 62 | writeFile (outfile ++ ".tex") (templateHeader ++ contents ++ templateFooter) 63 | system $ "latex " ++ outfile ++ ".tex > /dev/null" 64 | setCurrentDirectory curr 65 | system $ "dvipng -T tight -bd 1000 -freetype0 -Q 5 --gamma 1.3 " ++ 66 | (tmpdir outfile <.> "dvi") ++ " -o " ++ (staticDir cfg "img" outfile) 67 | return $ Para [Image name ("/img" outfile, "")] 68 | transformBlock x = return x 69 | 70 | uniqueName :: String -> String 71 | uniqueName = showDigest . sha1 . fromString 72 | -------------------------------------------------------------------------------- /plugins/MTable.hs: -------------------------------------------------------------------------------- 1 | module MTable (plugin) where 2 | 3 | -- This plugin ideally parses a less irritating table syntax 4 | -- for gitit. 5 | -- 6 | -- ~~~ {.mtable} 7 | -- | foo | bar | bop | 8 | -- | and | so | on | 9 | -- ~~~ 10 | -- 11 | -- Unfortuantely it still can't do colspan 12 | -- 13 | -- Simon Heath 2013 14 | 15 | import Data.Default 16 | import Data.List.Split 17 | import Text.Pandoc (readMarkdown) 18 | import Network.Gitit.Interface 19 | import System.IO.Unsafe 20 | 21 | plugin :: Plugin 22 | plugin = mkPageTransformM parseTableBlock 23 | 24 | parseTableBlock :: Block -> PluginM Block 25 | parseTableBlock (CodeBlock (_, classes, namevals) contents) | "mtable" `elem` classes = do 26 | let lineses = lines contents 27 | splittedLines = map (splitOn "|") lineses 28 | splittedLinesWithEmptiesRemoved = map (filter ((/=) "")) splittedLines 29 | parseCell x = 30 | let res = readMarkdown def x in 31 | case res of 32 | Left _ -> [Para $ [Str "Error parsing markdown in cell?"]] 33 | Right (Pandoc _ blk) -> blk 34 | cellify line = map (\cell -> parseCell cell) line 35 | cells = map cellify splittedLinesWithEmptiesRemoved 36 | alignments = replicate (length (head cells)) AlignDefault 37 | return $ Table [] alignments [] [] cells --(head cells) (tail cells) 38 | 39 | parseTableBlock x = return x 40 | -------------------------------------------------------------------------------- /plugins/PigLatin.hs: -------------------------------------------------------------------------------- 1 | module PigLatin (plugin) where 2 | 3 | -- This plugin converts a page to pig latin if the 'language' metadata 4 | -- field is set to 'pig latin'. This demonstrates how to get access to 5 | -- metadata in a plugin. 6 | 7 | import Network.Gitit.Interface 8 | import Data.Char (toLower, toUpper, isLower, isUpper, isLetter) 9 | 10 | plugin :: Plugin 11 | plugin = PageTransform $ \doc -> do 12 | meta <- askMeta 13 | case lookup "language" meta of 14 | Just s | map toLower s == "pig latin" -> 15 | return $ processWith pigLatinStr doc 16 | _ -> return doc 17 | 18 | pigLatinStr :: Inline -> Inline 19 | pigLatinStr (Str "") = Str "" 20 | pigLatinStr (Str (c:cs)) | isLower c && isConsonant c = 21 | Str (cs ++ (c : "ay")) 22 | pigLatinStr (Str (c:cs)) | isUpper c && isConsonant c = 23 | Str (capitalize cs ++ (toLower c : "ay")) 24 | pigLatinStr (Str x@(c:_)) | isLetter c = Str (x ++ "yay") 25 | pigLatinStr x = x 26 | 27 | isConsonant :: Char -> Bool 28 | isConsonant c = c `notElem` "aeiouAEIOU" 29 | 30 | capitalize :: String -> String 31 | capitalize "" = "" 32 | capitalize (c:cs) = toUpper c : cs 33 | -------------------------------------------------------------------------------- /plugins/ShowUser.hs: -------------------------------------------------------------------------------- 1 | module ShowUser (plugin) where 2 | 3 | -- This plugin replaces $USER$ with the name of the currently logged in 4 | -- user, or the empty string if no one is logged in. 5 | 6 | import Network.Gitit.Interface 7 | 8 | plugin :: Plugin 9 | plugin = mkPageTransformM showuser 10 | 11 | showuser :: Inline -> PluginM Inline 12 | showuser (Math InlineMath x) | x == "USER" = do 13 | doNotCache -- tell gitit not to cache this page, as it has dynamic content 14 | mbUser <- askUser 15 | case mbUser of 16 | Nothing -> return $ Str "" 17 | Just u -> return $ Str $ uUsername u 18 | showuser x = return x 19 | 20 | -------------------------------------------------------------------------------- /plugins/Signature.hs: -------------------------------------------------------------------------------- 1 | module Signature (plugin) where 2 | 3 | -- This plugin replaces $SIG$ with the username and timestamp 4 | -- of the last edit, prior to saving the page in the repository. 5 | 6 | import Network.Gitit.Interface 7 | import Data.DateTime (getCurrentTime, formatDateTime) 8 | 9 | plugin :: Plugin 10 | plugin = PreCommitTransform replacedate 11 | 12 | replacedate :: String -> PluginM String 13 | replacedate [] = return "" 14 | replacedate ('$':'S':'I':'G':'$':xs) = do 15 | datetime <- liftIO getCurrentTime 16 | mbuser <- askUser 17 | let username = case mbuser of 18 | Nothing -> "???" 19 | Just u -> uUsername u 20 | let sig = concat ["-- ", username, " (", formatDateTime "%c" datetime, ")"] 21 | fmap (sig ++ ) $ replacedate xs 22 | replacedate (x:xs) = fmap (x : ) $ replacedate xs 23 | 24 | -------------------------------------------------------------------------------- /plugins/Subst.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE PackageImports #-} 2 | 3 | -- Usage: a paragraph containing just [My page](!subst) 4 | -- will be replaced by the contents of My page. 5 | -- 6 | -- Limitations: it is assumed that My page is 7 | -- formatted with markdown, and contains no metadata. 8 | 9 | module Subst (plugin) where 10 | 11 | --import "MonadCatchIO-mtl" Control.Monad.CatchIO (try) 12 | import Control.Monad.Catch (try) 13 | import Data.FileStore (FileStoreError, retrieve) 14 | import Text.Pandoc (def, readMarkdown) 15 | import Network.Gitit.ContentTransformer (inlinesToString) 16 | import Network.Gitit.Interface 17 | import Network.Gitit.Framework (filestoreFromConfig) 18 | 19 | plugin :: Plugin 20 | plugin = mkPageTransformM substituteIntoBlock 21 | 22 | substituteIntoBlock :: [Block] -> PluginM [Block] 23 | substituteIntoBlock ((Para [Link attr ref ("!subst", _)]):xs) = 24 | do let target = inlinesToString ref 25 | cfg <- askConfig 26 | let fs = filestoreFromConfig cfg 27 | article <- try $ liftIO (retrieve fs (target ++ ".page") Nothing) 28 | case article :: Either FileStoreError String of 29 | Left _ -> let txt = Str ("[" ++ target ++ "](!subst)") 30 | alt = "'" ++ target ++ "' doesn't exist. Click here to create it." 31 | lnk = Para [Link attr [txt] (target,alt)] 32 | in (lnk :) `fmap` substituteIntoBlock xs 33 | -- Right a -> let (Pandoc _ content) = readMarkdown def a 34 | -- in (content ++) `fmap` substituteIntoBlock xs 35 | 36 | Right a -> case readMarkdown def a of 37 | Left err -> 38 | let content = [Para $ [Str "Error parsing markdown in subst?"]] in 39 | (content ++) `fmap` substituteIntoBlock xs 40 | Right (Pandoc _ content) -> (content ++) `fmap` substituteIntoBlock xs 41 | 42 | substituteIntoBlock (x:xs) = (x:) `fmap` substituteIntoBlock xs 43 | substituteIntoBlock [] = return [] 44 | -------------------------------------------------------------------------------- /plugins/WebArchiver.hs: -------------------------------------------------------------------------------- 1 | {-| Scans page of Markdown looking for http links. When it finds them, it submits them 2 | to webcitation.org / https://secure.wikimedia.org/wikipedia/en/wiki/WebCite 3 | (It will also submit them to Alexa (the source for the Internet Archive), but Alexa says that 4 | its bots take weeks to visit and may not ever.) 5 | 6 | This module employs the archiver daemon as a library; `cabal install archiver` will install it. 7 | 8 | Limitations: 9 | * Only parses Markdown, not ReST or any other format; this is because 'readMarkdown' 10 | is hardwired into it. 11 | * No rate limitation or choking; will fire off all requests as fast as possible. 12 | If pages have more than 20 external links or so, this may result in your IP being temporarily 13 | banned by WebCite. To avoid this, you can use WebArchiverBot.hs instead, which will parse & dump 14 | URLs into a file processed by the archiver daemon (which *is* rate-limited). 15 | 16 | By: Gwern Branwen; placed in the public domain -} 17 | 18 | module WebArchiver (plugin) where 19 | 20 | import Control.Concurrent (forkIO) 21 | import Network.URL.Archiver as A (checkArchive) 22 | import Network.Gitit.Interface (askUser, bottomUpM, liftIO, uEmail, Plugin(PreCommitTransform), Inline(Link)) 23 | import Text.Pandoc (defaultParserState, readMarkdown) 24 | 25 | plugin :: Plugin 26 | plugin = PreCommitTransform archivePage 27 | 28 | -- archivePage :: String -> ReaderT PluginData (StateT Context IO) String 29 | archivePage x = do mbUser <- askUser 30 | let email = case mbUser of 31 | Nothing -> "nobody@mailinator.com" 32 | Just u -> uEmail u 33 | let p = readMarkdown defaultParserState x 34 | -- force evaluation and archiving side-effects 35 | _p' <- liftIO $ bottomUpM (archiveLinks email) p 36 | return x -- note: this is read-only - don't actually change page! 37 | 38 | archiveLinks :: String -> Inline -> IO Inline 39 | archiveLinks e x@(Link _ (uln, _)) = forkIO (A.checkArchive e uln) >> return x 40 | archiveLinks _ x = return x 41 | -------------------------------------------------------------------------------- /plugins/WebArchiverBot.hs: -------------------------------------------------------------------------------- 1 | {-| Scans page of Markdown looking for http links; when found it prints them out to a default file. 2 | This plugin is meant to be run in conjunction with archiver . 3 | If you do not wish to run it (for example, you have no more than a dozen external http links on any page), 4 | then you should use the original WebArchiver.hs plugin. 5 | 6 | Limitations: 7 | * Only parses Markdown, not ReST or any other format; this is because 'readMarkdown' 8 | is hardwired into it. 9 | 10 | By: Gwern Branwen; placed in the public domain -} 11 | 12 | module WebArchiverBot (plugin) where 13 | 14 | import System.Directory (getHomeDirectory) 15 | import Network.Gitit.Interface (liftIO, bottomUpM, Plugin(PreCommitTransform), Inline(Link)) 16 | import Text.Pandoc (defaultParserState, readMarkdown) 17 | 18 | plugin :: Plugin 19 | plugin = PreCommitTransform archivePage 20 | 21 | -- archivePage :: (MonadIO m) => String -> m String 22 | archivePage x = do let p = readMarkdown defaultParserState x 23 | -- force evaluation and archiving side-effects 24 | _p' <- liftIO $ bottomUpM archiveLinks p 25 | return x -- note: this is read-only - don't actually change page! 26 | 27 | archiveLinks :: Inline -> IO Inline 28 | archiveLinks x@(Link _ ('!':_, _)) = return x -- skip interwiki links 29 | archiveLinks x@(Link _ ('#':_, _)) = return x -- skip section links 30 | archiveLinks x@(Link _ (uln, _)) = do homedir <- getHomeDirectory 31 | appendFile (homedir++"/.urls.txt") (uln++"\n") 32 | return x 33 | archiveLinks x = return x 34 | -------------------------------------------------------------------------------- /src/Network/Gitit.hs: -------------------------------------------------------------------------------- 1 | {- 2 | Copyright (C) 2009 John MacFarlane 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | -} 18 | 19 | {- | Functions for embedding a gitit wiki into a Happstack application. 20 | 21 | The following is a minimal standalone wiki program: 22 | 23 | > import Network.Gitit 24 | > import Happstack.Server.SimpleHTTP 25 | > 26 | > main = do 27 | > conf <- getDefaultConfig 28 | > createStaticIfMissing conf 29 | > createTemplateIfMissing conf 30 | > createRepoIfMissing conf 31 | > initializeGititState conf 32 | > simpleHTTP nullConf{port = 5001} $ wiki conf 33 | 34 | Here is a more complex example, which serves different wikis 35 | under different paths, and uses a custom authentication scheme: 36 | 37 | > import Network.Gitit 38 | > import Control.Monad 39 | > import Text.XHtml hiding (dir) 40 | > import Happstack.Server.SimpleHTTP 41 | > 42 | > type WikiSpec = (String, FileStoreType, PageType) 43 | > 44 | > wikis = [ ("markdownWiki", Git, Markdown) 45 | > , ("latexWiki", Darcs, LaTeX) ] 46 | > 47 | > -- custom authentication 48 | > myWithUser :: Handler -> Handler 49 | > myWithUser handler = do 50 | > -- replace the following with a function that retrieves 51 | > -- the logged in user for your happstack app: 52 | > user <- return "testuser" 53 | > localRq (setHeader "REMOTE_USER" user) handler 54 | > 55 | > myAuthHandler = msum 56 | > [ dir "_login" $ seeOther "/your/login/url" $ toResponse () 57 | > , dir "_logout" $ seeOther "/your/logout/url" $ toResponse () ] 58 | > 59 | > handlerFor :: Config -> WikiSpec -> ServerPart Response 60 | > handlerFor conf (path', fstype, pagetype) = dir path' $ 61 | > wiki conf{ repositoryPath = path' 62 | > , repositoryType = fstype 63 | > , defaultPageType = pagetype} 64 | > 65 | > indexPage :: ServerPart Response 66 | > indexPage = ok $ toResponse $ 67 | > (p << "Wiki index") +++ 68 | > ulist << map (\(path', _, _) -> li << hotlink (path' ++ "/") << path') wikis 69 | > 70 | > main = do 71 | > conf <- getDefaultConfig 72 | > let conf' = conf{authHandler = myAuthHandler, withUser = myWithUser} 73 | > forM wikis $ \(path', fstype, pagetype) -> do 74 | > let conf'' = conf'{ repositoryPath = path' 75 | > , repositoryType = fstype 76 | > , defaultPageType = pagetype 77 | > } 78 | > createStaticIfMissing conf'' 79 | > createRepoIfMissing conf'' 80 | > createTemplateIfMissing conf' 81 | > initializeGititState conf' 82 | > simpleHTTP nullConf{port = 5001} $ 83 | > (nullDir >> indexPage) `mplus` msum (map (handlerFor conf') wikis) 84 | 85 | -} 86 | 87 | module Network.Gitit ( 88 | -- * Wiki handlers 89 | wiki 90 | , reloadTemplates 91 | , runHandler 92 | -- * Initialization 93 | , module Network.Gitit.Initialize 94 | -- * Configuration 95 | , module Network.Gitit.Config 96 | , loginUserForm 97 | -- * Types 98 | , module Network.Gitit.Types 99 | -- * Tools for building handlers 100 | , module Network.Gitit.Framework 101 | , module Network.Gitit.Layout 102 | , module Network.Gitit.ContentTransformer 103 | , module Network.Gitit.Page 104 | , getFileStore 105 | , getUser 106 | , getConfig 107 | , queryGititState 108 | , updateGititState 109 | ) 110 | where 111 | import Network.Gitit.Types 112 | import Network.Gitit.Server 113 | import Network.Gitit.Framework 114 | import Network.Gitit.Handlers 115 | import Network.Gitit.Initialize 116 | import Network.Gitit.Config 117 | import Network.Gitit.Layout 118 | import Network.Gitit.State 119 | (getFileStore, getUser, getConfig, queryGititState, updateGititState) 120 | import Network.Gitit.ContentTransformer 121 | import Network.Gitit.Page 122 | import Network.Gitit.Authentication (loginUserForm) 123 | import Paths_gitit (getDataFileName) 124 | import Control.Monad 125 | import Control.Monad.Reader 126 | import Prelude hiding (readFile) 127 | import qualified Data.ByteString.Char8 as B 128 | import System.FilePath (()) 129 | import System.Directory (getTemporaryDirectory) 130 | import Safe 131 | 132 | -- | Happstack handler for a gitit wiki. 133 | wiki :: Config -> ServerPart Response 134 | wiki conf = do 135 | tempDir <- liftIO getTemporaryDirectory 136 | let maxSize = fromIntegral $ maxUploadSize conf 137 | decodeBody $ defaultBodyPolicy tempDir maxSize maxSize maxSize 138 | let static = staticDir conf 139 | defaultStatic <- liftIO $ getDataFileName $ "data" "static" 140 | -- if file not found in staticDir, we check also in the data/static 141 | -- directory, which contains defaults 142 | let staticHandler = withExpiresHeaders $ 143 | serveDirectory' static `mplus` serveDirectory' defaultStatic 144 | let debugHandler' = msum [debugHandler | debugMode conf] 145 | let handlers = debugHandler' `mplus` authHandler conf `mplus` 146 | authenticate ForRead (msum wikiHandlers) 147 | let fs = filestoreFromConfig conf 148 | let ws = WikiState { wikiConfig = conf, wikiFileStore = fs } 149 | if compressResponses conf 150 | then compressedResponseFilter 151 | else return "" 152 | staticHandler `mplus` runHandler ws (withUser conf handlers) 153 | 154 | -- | Like 'serveDirectory', but if file is not found, fail instead of 155 | -- returning a 404 error. 156 | serveDirectory' :: FilePath -> ServerPart Response 157 | serveDirectory' p = do 158 | rq <- askRq 159 | resp' <- serveDirectory EnableBrowsing [] p 160 | if rsCode resp' == 404 || lastNote "fileServeStrict'" (rqUri rq) == '/' 161 | then mzero -- pass through if not found or directory index 162 | else 163 | -- turn off compresion filter unless it's text 164 | case getHeader "Content-Type" resp' of 165 | Just ct | B.pack "text/" `B.isPrefixOf` ct -> return resp' 166 | _ -> ignoreFilters >> return resp' 167 | 168 | wikiHandlers :: [Handler] 169 | wikiHandlers = 170 | [ -- redirect /wiki -> /wiki/ when gitit is being served at /wiki 171 | -- so that relative wikilinks on the page will work properly: 172 | guardBareBase >> getWikiBase >>= \b -> movedPermanently (b ++ "/") (toResponse ()) 173 | , dir "_activity" showActivity 174 | , dir "_go" goToPage 175 | , method GET >> dir "_search" searchResults 176 | , dir "_upload" $ do guard =<< return . uploadsAllowed =<< getConfig 177 | msum [ method GET >> authenticate ForModify uploadForm 178 | , method POST >> authenticate ForModify uploadFile ] 179 | , dir "_random" $ method GET >> randomPage 180 | , dir "_index" indexPage 181 | , dir "_feed" feedHandler 182 | , dir "_category" categoryPage 183 | , dir "_categories" categoryListPage 184 | , dir "_expire" expireCache 185 | , dir "_showraw" $ msum 186 | [ showRawPage 187 | , guardPath isSourceCode >> showFileAsText ] 188 | , dir "_history" $ msum 189 | [ showPageHistory 190 | , guardPath isSourceCode >> showFileHistory ] 191 | , dir "_edit" $ authenticate ForModify (unlessNoEdit editPage showPage) 192 | , dir "_diff" $ msum 193 | [ showPageDiff 194 | , guardPath isSourceCode >> showFileDiff ] 195 | , dir "_discuss" discussPage 196 | , dir "_delete" $ msum 197 | [ method GET >> 198 | authenticate ForModify (unlessNoDelete confirmDelete showPage) 199 | , method POST >> 200 | authenticate ForModify (unlessNoDelete deletePage showPage) ] 201 | , dir "_preview" preview 202 | , guardIndex >> indexPage 203 | , method POST >> guardCommand "cancel" >> showPage 204 | , method POST >> guardCommand "update" >> 205 | authenticate ForModify (unlessNoEdit updatePage showPage) 206 | , showPage 207 | , guardPath isSourceCode >> method GET >> showHighlightedSource 208 | , handleAny 209 | , notFound =<< (guardPath isPage >> createPage) 210 | ] 211 | 212 | -- | Recompiles the gitit templates. 213 | reloadTemplates :: Config -> ServerPart Response 214 | reloadTemplates cfg = do 215 | liftIO $ recompilePageTemplate cfg 216 | ok $ toResponse "Page templates have been recompiled." 217 | 218 | -- | Converts a gitit Handler into a standard happstack ServerPart. 219 | runHandler :: WikiState -> Handler -> ServerPart Response 220 | runHandler = mapServerPartT . unpackReaderT 221 | 222 | unpackReaderT :: s -> UnWebT (ReaderT s IO) a -> UnWebT IO a 223 | unpackReaderT st uw = runReaderT uw st 224 | 225 | -------------------------------------------------------------------------------- /src/Network/Gitit/Authentication/Github.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP, OverloadedStrings, ScopedTypeVariables #-} 2 | 3 | module Network.Gitit.Authentication.Github ( loginGithubUser 4 | , getGithubUser 5 | , GithubCallbackPars 6 | , GithubLoginError 7 | , ghUserMessage 8 | , ghDetails) where 9 | 10 | import Network.Gitit.Types 11 | import Network.Gitit.Server 12 | import Network.Gitit.State 13 | import Network.Gitit.Util 14 | import Network.Gitit.Framework 15 | import qualified Data.ByteString.Char8 as BS 16 | import qualified Data.ByteString.Lazy as BSL 17 | import qualified URI.ByteString as URI 18 | import Network.HTTP.Conduit 19 | import Network.OAuth.OAuth2 20 | import Control.Monad (liftM, mplus, mzero) 21 | import Data.Maybe 22 | import Data.Aeson 23 | import Data.Text (Text, pack, unpack) 24 | import Data.Text.Encoding (encodeUtf8) 25 | import Control.Applicative 26 | import Control.Monad ((>=>)) 27 | import Control.Monad.Trans (liftIO) 28 | import Data.UUID (toString) 29 | import Data.UUID.V4 (nextRandom) 30 | import qualified Control.Exception as E 31 | import Control.Monad.Except 32 | import Prelude 33 | 34 | loginGithubUser :: OAuth2 -> Params -> Handler 35 | loginGithubUser githubKey params = do 36 | state <- liftIO $ fmap toString nextRandom 37 | base' <- getWikiBase 38 | let destination = pDestination params `orIfNull` (base' ++ "/") 39 | key <- newSession $ sessionDataGithubStateUrl state destination 40 | cfg <- getConfig 41 | addCookie (MaxAge $ sessionTimeout cfg) (mkSessionCookie key) 42 | let usingOrg = isJust $ org $ githubAuth cfg 43 | let scopes = "user:email" ++ if usingOrg then ",read:org" else "" 44 | let url = appendQueryParams [("state", BS.pack state), ("scope", BS.pack scopes)] $ authorizationUrl githubKey 45 | seeOther (BS.unpack (URI.serializeURIRef' url)) $ toResponse ("redirecting to github" :: String) 46 | 47 | data GithubLoginError = GithubLoginError { ghUserMessage :: String 48 | , ghDetails :: Maybe String 49 | } 50 | 51 | getGithubUser :: GithubConfig -- ^ Oauth2 configuration (client secret) 52 | -> GithubCallbackPars -- ^ Authentication code gained after authorization 53 | -> String -- ^ Github state, we expect the state we sent in loginGithubUser 54 | -> GititServerPart (Either GithubLoginError User) -- ^ user email and name (password 'none') 55 | getGithubUser ghConfig githubCallbackPars githubState = liftIO $ 56 | newManager tlsManagerSettings >>= getUserInternal 57 | where 58 | getUserInternal mgr = 59 | liftIO $ runExceptT $ do 60 | let (Just state) = rState githubCallbackPars 61 | if state == githubState 62 | then do 63 | let (Just code) = rCode githubCallbackPars 64 | at <- withExceptT (oauthToGithubError "No access token found yet") 65 | $ fetchAccessToken mgr (oAuth2 ghConfig) (ExchangeToken $ pack code) 66 | liftIO >=> liftEither $ ifSuccess "User Authentication failed" 67 | (userInfo mgr (accessToken at)) 68 | (\githubUser -> ifSuccess 69 | ("No email for user " ++ unpack (gLogin githubUser) ++ " returned by Github") 70 | (mailInfo mgr (accessToken at)) 71 | (\githubUserMail -> do 72 | let gitLogin = gLogin githubUser 73 | user <- mkUser (unpack gitLogin) 74 | (unpack $ email $ head (filter primary githubUserMail)) 75 | "none" 76 | let mbOrg = org ghConfig 77 | case mbOrg of 78 | Nothing -> return $ Right user 79 | Just githuborg -> ifSuccess 80 | ("Membership check failed: the user " ++ unpack gitLogin ++ " is required to be a member of the organization " ++ unpack githuborg ++ ".") 81 | (orgInfo gitLogin githuborg mgr (accessToken at)) 82 | (\_ -> return $ Right user))) 83 | else 84 | throwError $ 85 | GithubLoginError ("The state sent to github is not the same as the state received: " ++ state ++ ", but expected sent state: " ++ githubState) 86 | Nothing 87 | ifSuccess errMsg failableAction successAction = E.catch 88 | (do Right outcome <- failableAction 89 | successAction outcome) 90 | (\exception -> liftIO $ return $ Left $ 91 | GithubLoginError errMsg 92 | (Just $ show (exception :: E.SomeException))) 93 | oauthToGithubError errMsg e = GithubLoginError errMsg (Just $ show e) 94 | 95 | data GithubCallbackPars = GithubCallbackPars { rCode :: Maybe String 96 | , rState :: Maybe String } 97 | deriving Show 98 | 99 | instance FromData GithubCallbackPars where 100 | fromData = do 101 | vCode <- liftM Just (look "code") `mplus` return Nothing 102 | vState <- liftM Just (look "state") `mplus` return Nothing 103 | return GithubCallbackPars {rCode = vCode, rState = vState} 104 | 105 | #if MIN_VERSION_hoauth2(1, 9, 0) 106 | userInfo :: Manager -> AccessToken -> IO (Either BSL.ByteString GithubUser) 107 | #else 108 | userInfo :: Manager -> AccessToken -> IO (OAuth2Result OA.Errors GithubUser) 109 | #endif 110 | userInfo mgr token = runExceptT $ authGetJSON mgr token $ githubUri "/user" 111 | 112 | #if MIN_VERSION_hoauth2(1, 9, 0) 113 | mailInfo :: Manager -> AccessToken -> IO (Either BSL.ByteString [GithubUserMail]) 114 | #else 115 | mailInfo :: Manager -> AccessToken -> IO (OAuth2Result OA.Errors [GithubUserMail]) 116 | #endif 117 | mailInfo mgr token = runExceptT $ authGetJSON mgr token $ githubUri "/user/emails" 118 | 119 | #if MIN_VERSION_hoauth2(1, 9, 0) 120 | orgInfo :: Text -> Text -> Manager -> AccessToken -> IO (Either BSL.ByteString BSL.ByteString) 121 | #else 122 | orgInfo :: Text -> Text -> Manager -> AccessToken -> IO (OAuth2Result OA.Errors BSL.ByteString) 123 | #endif 124 | orgInfo gitLogin githubOrg mgr token = do 125 | let url = githubUri $ "/orgs/" `BS.append` encodeUtf8 githubOrg `BS.append` "/members/" `BS.append` encodeUtf8 gitLogin 126 | runExceptT $ authGetBS mgr token url 127 | 128 | type UriPath = BS.ByteString 129 | 130 | githubUri :: UriPath -> URI.URI 131 | githubUri p = URI.URI { URI.uriScheme = URI.Scheme "https" 132 | , URI.uriAuthority = Just $ URI.Authority Nothing (URI.Host "api.github.com") Nothing 133 | , URI.uriPath = p 134 | , URI.uriQuery = URI.Query [] 135 | , URI.uriFragment = Nothing } 136 | 137 | data GithubUser = GithubUser { gLogin :: Text 138 | } deriving (Show, Eq) 139 | 140 | instance FromJSON GithubUser where 141 | parseJSON (Object o) = GithubUser 142 | <$> o .: "login" 143 | parseJSON _ = mzero 144 | 145 | data GithubUserMail = GithubUserMail { email :: Text 146 | , primary :: Bool 147 | } deriving (Show, Eq) 148 | 149 | instance FromJSON GithubUserMail where 150 | parseJSON (Object o) = GithubUserMail 151 | <$> o .: "email" 152 | <*> o .: "primary" 153 | parseJSON _ = mzero 154 | -------------------------------------------------------------------------------- /src/Network/Gitit/Cache.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | {- 3 | Copyright (C) 2008 John MacFarlane 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | -} 19 | 20 | {- Functions for maintaining user list and session state. 21 | -} 22 | 23 | module Network.Gitit.Cache ( expireCachedFile 24 | , lookupCache 25 | , cacheContents ) 26 | where 27 | 28 | import qualified Data.ByteString as B (ByteString, readFile, writeFile) 29 | import System.FilePath 30 | import System.Directory (doesFileExist, removeFile, createDirectoryIfMissing, getModificationTime) 31 | import Data.Time.Clock (UTCTime) 32 | #if MIN_VERSION_directory(1,2,0) 33 | #else 34 | import System.Time (ClockTime(..)) 35 | import Data.Time.Clock.POSIX (posixSecondsToUTCTime) 36 | #endif 37 | import Network.Gitit.State 38 | import Network.Gitit.Types 39 | import Control.Monad 40 | import Control.Monad.Trans (liftIO) 41 | import Text.Pandoc.UTF8 (encodePath) 42 | 43 | -- | Expire a cached file, identified by its filename in the filestore. 44 | -- Returns () after deleting a file from the cache, fails if no cached file. 45 | expireCachedFile :: String -> GititServerPart () 46 | expireCachedFile file = do 47 | cfg <- getConfig 48 | let target = encodePath $ cacheDir cfg file 49 | exists <- liftIO $ doesFileExist target 50 | when exists $ liftIO $ liftIO $ removeFile target 51 | 52 | lookupCache :: String -> GititServerPart (Maybe (UTCTime, B.ByteString)) 53 | lookupCache file = do 54 | cfg <- getConfig 55 | let target = encodePath $ cacheDir cfg file 56 | exists <- liftIO $ doesFileExist target 57 | if exists 58 | then liftIO $ do 59 | #if MIN_VERSION_directory(1,2,0) 60 | modtime <- getModificationTime target 61 | #else 62 | TOD secs _ <- getModificationTime target 63 | let modtime = posixSecondsToUTCTime $ fromIntegral secs 64 | #endif 65 | contents <- B.readFile target 66 | return $ Just (modtime, contents) 67 | else return Nothing 68 | 69 | cacheContents :: String -> B.ByteString -> GititServerPart () 70 | cacheContents file contents = do 71 | cfg <- getConfig 72 | let target = encodePath $ cacheDir cfg file 73 | let targetDir = takeDirectory target 74 | liftIO $ do 75 | createDirectoryIfMissing True targetDir 76 | B.writeFile target contents 77 | -------------------------------------------------------------------------------- /src/Network/Gitit/Compat/Except.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | module Network.Gitit.Compat.Except ( 3 | ExceptT 4 | , Except 5 | , Error(..) 6 | , runExceptT 7 | , runExcept 8 | , MonadError 9 | , throwError 10 | , catchError ) 11 | where 12 | 13 | #if MIN_VERSION_mtl(2,2,1) 14 | import Control.Monad.Except 15 | 16 | class Error a where 17 | noMsg :: a 18 | strMsg :: String -> a 19 | 20 | noMsg = strMsg "" 21 | strMsg _ = noMsg 22 | 23 | #else 24 | import Control.Monad.Error 25 | import Control.Monad.Identity (Identity, runIdentity) 26 | 27 | type ExceptT = ErrorT 28 | 29 | type Except s a = ErrorT s Identity a 30 | 31 | runExceptT :: ExceptT e m a -> m (Either e a) 32 | runExceptT = runErrorT 33 | 34 | runExcept :: ExceptT e Identity a -> Either e a 35 | runExcept = runIdentity . runExceptT 36 | #endif 37 | -------------------------------------------------------------------------------- /src/Network/Gitit/Interface.hs: -------------------------------------------------------------------------------- 1 | {- 2 | Copyright (C) 2009 John MacFarlane 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | -} 18 | 19 | {- | Interface for plugins. 20 | 21 | A plugin is a Haskell module that is dynamically loaded by gitit. 22 | 23 | There are three kinds of plugins: 'PageTransform's, 24 | 'PreParseTransform's, and 'PreCommitTransform's. These plugins differ 25 | chiefly in where they are applied. 'PreCommitTransform' plugins are 26 | applied just before changes to a page are saved and may transform 27 | the raw source that is saved. 'PreParseTransform' plugins are applied 28 | when a page is viewed and may alter the raw page source before it 29 | is parsed as a 'Pandoc' document. Finally, 'PageTransform' plugins 30 | modify the 'Pandoc' document that results after a page's source is 31 | parsed, but before it is converted to HTML: 32 | 33 | > +--------------------------+ 34 | > | edited text from browser | 35 | > +--------------------------+ 36 | > || <---- PreCommitTransform plugins 37 | > \/ 38 | > || <---- saved to repository 39 | > \/ 40 | > +---------------------------------+ 41 | > | raw page source from repository | 42 | > +---------------------------------+ 43 | > || <---- PreParseTransform plugins 44 | > \/ 45 | > || <---- markdown or RST reader 46 | > \/ 47 | > +-----------------+ 48 | > | Pandoc document | 49 | > +-----------------+ 50 | > || <---- PageTransform plugins 51 | > \/ 52 | > +---------------------+ 53 | > | new Pandoc document | 54 | > +---------------------+ 55 | > || <---- HTML writer 56 | > \/ 57 | > +----------------------+ 58 | > | HTML version of page | 59 | > +----------------------+ 60 | 61 | Note that 'PreParseTransform' and 'PageTransform' plugins do not alter 62 | the page source stored in the repository. They only affect what is 63 | visible on the website. Only 'PreCommitTransform' plugins can 64 | alter what is stored in the repository. 65 | 66 | Note also that 'PreParseTransform' and 'PageTransform' plugins will 67 | not be run when the cached version of a page is used. Plugins can 68 | use the 'doNotCache' command to prevent a page from being cached, 69 | if their behavior is sensitive to things that might change from 70 | one time to another (such as the time or currently logged-in user). 71 | 72 | You can use the helper functions 'mkPageTransform' and 'mkPageTransformM' 73 | to create 'PageTransform' plugins from a transformation of any 74 | of the basic types used by Pandoc (for example, @Inline@, @Block@, 75 | @[Inline]@, even @String@). Here is a simple (if silly) example: 76 | 77 | > -- Deprofanizer.hs 78 | > module Deprofanizer (plugin) where 79 | > 80 | > -- This plugin replaces profane words with "XXXXX". 81 | > 82 | > import Network.Gitit.Interface 83 | > import Data.Char (toLower) 84 | > 85 | > plugin :: Plugin 86 | > plugin = mkPageTransform deprofanize 87 | > 88 | > deprofanize :: Inline -> Inline 89 | > deprofanize (Str x) | isBadWord x = Str "XXXXX" 90 | > deprofanize x = x 91 | > 92 | > isBadWord :: String -> Bool 93 | > isBadWord x = (map toLower x) `elem` ["darn", "blasted", "stinker"] 94 | > -- there are more, but this is a family program 95 | 96 | Further examples can be found in the @plugins@ directory in 97 | the source distribution. If you have installed gitit using Cabal, 98 | you can also find them in the directory 99 | @CABALDIR\/share\/gitit-X.Y.Z\/plugins@, where @CABALDIR@ is the cabal 100 | install directory and @X.Y.Z@ is the version number of gitit. 101 | 102 | -} 103 | 104 | module Network.Gitit.Interface ( Plugin(..) 105 | , PluginM 106 | , mkPageTransform 107 | , mkPageTransformM 108 | , Config(..) 109 | , Request(..) 110 | , User(..) 111 | , Context(..) 112 | , PageType(..) 113 | , PageLayout(..) 114 | , askConfig 115 | , askUser 116 | , askRequest 117 | , askFileStore 118 | , askMeta 119 | , doNotCache 120 | , getContext 121 | , modifyContext 122 | , inlinesToURL 123 | , inlinesToString 124 | , liftIO 125 | , withTempDir 126 | , module Text.Pandoc.Definition 127 | , module Text.Pandoc.Generic 128 | ) 129 | where 130 | import Text.Pandoc.Definition 131 | import Text.Pandoc.Generic 132 | import Data.Data 133 | import Network.Gitit.Types 134 | import Network.Gitit.ContentTransformer 135 | import Network.Gitit.Util (withTempDir) 136 | import Network.Gitit.Server (Request(..)) 137 | import Control.Monad.Reader (ask) 138 | import Control.Monad.Trans (liftIO) 139 | import Control.Monad (liftM) 140 | import Data.FileStore (FileStore) 141 | 142 | -- | Returns the current wiki configuration. 143 | askConfig :: PluginM Config 144 | askConfig = liftM pluginConfig ask 145 | 146 | -- | Returns @Just@ the logged in user, or @Nothing@ if nobody is logged in. 147 | askUser :: PluginM (Maybe User) 148 | askUser = liftM pluginUser ask 149 | 150 | -- | Returns the complete HTTP request. 151 | askRequest :: PluginM Request 152 | askRequest = liftM pluginRequest ask 153 | 154 | -- | Returns the wiki filestore. 155 | askFileStore :: PluginM FileStore 156 | askFileStore = liftM pluginFileStore ask 157 | 158 | -- | Returns the page meta data 159 | askMeta :: PluginM [(String, String)] 160 | askMeta = liftM ctxMeta getContext 161 | 162 | -- | Indicates that the current page or file is not to be cached. 163 | doNotCache :: PluginM () 164 | doNotCache = modifyContext (\ctx -> ctx{ ctxCacheable = False }) 165 | 166 | -- | Lifts a function from @a -> a@ (for example, @Inline -> Inline@, 167 | -- @Block -> Block@, @[Inline] -> [Inline]@, or @String -> String@) 168 | -- to a 'PageTransform' plugin. 169 | mkPageTransform :: Data a => (a -> a) -> Plugin 170 | mkPageTransform fn = PageTransform $ return . bottomUp fn 171 | 172 | -- | Monadic version of 'mkPageTransform'. 173 | -- Lifts a function from @a -> m a@ to a 'PageTransform' plugin. 174 | mkPageTransformM :: Data a => (a -> PluginM a) -> Plugin 175 | mkPageTransformM = PageTransform . bottomUpM 176 | 177 | -------------------------------------------------------------------------------- /src/Network/Gitit/Layout.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE FlexibleContexts #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | {-# LANGUAGE TypeApplications #-} 4 | {- 5 | Copyright (C) 2009 John MacFarlane 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation; either version 2 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | -} 21 | 22 | {- Functions and data structures for wiki page layout. 23 | -} 24 | 25 | module Network.Gitit.Layout ( defaultPageLayout 26 | , defaultRenderPage 27 | , formattedPage 28 | , filledPageTemplate 29 | , uploadsAllowed 30 | ) 31 | where 32 | import Network.Gitit.Server 33 | import Network.Gitit.Framework 34 | import Network.Gitit.State 35 | import Network.Gitit.Types 36 | import Network.HTTP (urlEncodeVars) 37 | import qualified Text.StringTemplate as T 38 | import Data.Maybe (isNothing) 39 | import Text.Blaze.Html5 hiding (s, article, map) 40 | import Text.Blaze.Html5.Attributes hiding (id) 41 | import Data.String (IsString(fromString)) 42 | import Text.Blaze.Html.Renderer.String (renderHtml) 43 | 44 | defaultPageLayout :: PageLayout 45 | defaultPageLayout = PageLayout 46 | { pgPageName = "" 47 | , pgRevision = Nothing 48 | , pgPrintable = False 49 | , pgMessages = [] 50 | , pgTitle = "" 51 | , pgScripts = [] 52 | , pgShowPageTools = True 53 | , pgShowSiteNav = True 54 | , pgMarkupHelp = Nothing 55 | , pgTabs = [ViewTab, EditTab, HistoryTab, DiscussTab] 56 | , pgSelectedTab = ViewTab 57 | , pgLinkToFeed = False 58 | } 59 | 60 | -- | Returns formatted page 61 | formattedPage :: PageLayout -> Html -> Handler 62 | formattedPage layout htmlContents = do 63 | renderer <- queryGititState renderPage 64 | renderer layout htmlContents 65 | 66 | -- | Given a compiled string template, returns a page renderer. 67 | defaultRenderPage :: T.StringTemplate String -> PageLayout -> Html -> Handler 68 | defaultRenderPage templ layout htmlContents = do 69 | cfg <- getConfig 70 | base' <- getWikiBase 71 | ok . setContentType "text/html; charset=utf-8" . toResponse . T.render . 72 | filledPageTemplate base' cfg layout htmlContents $ templ 73 | 74 | -- | Returns a page template with gitit variables filled in. 75 | filledPageTemplate :: String -> Config -> PageLayout -> Html -> 76 | T.StringTemplate String -> T.StringTemplate String 77 | filledPageTemplate base' cfg layout htmlContents templ = 78 | let rev = pgRevision layout 79 | page = pgPageName layout 80 | prefixedScript x = case x of 81 | 'h':'t':'t':'p':_ -> x 82 | _ -> base' ++ "/js/" ++ x 83 | 84 | scripts = ["jquery-1.2.6.min.js", "jquery-ui-combined-1.6rc2.min.js", "footnotes.js"] ++ pgScripts layout 85 | scriptLink x = script ! src (fromString $ prefixedScript x) ! 86 | type_ "text/javascript" $ mempty 87 | javascriptlinks = renderHtml $ mconcat $ map scriptLink scripts 88 | article = if isDiscussPage page then drop 1 page else page 89 | discussion = '@':article 90 | tabli tab = if tab == pgSelectedTab layout 91 | then li ! class_ "selected" 92 | else li 93 | tabs' = [x | x <- pgTabs layout, 94 | not (x == EditTab && page `elem` noEdit cfg)] 95 | tabs = (ul ! class_ "tabs") $ foldMap (linkForTab tabli base' page rev) tabs' 96 | setStrAttr attr = T.setAttribute attr . renderHtml . fromString @Html 97 | setBoolAttr attr test = if test then T.setAttribute attr ("true"::[Char]) else id 98 | in T.setAttribute "base" base' . 99 | T.setAttribute "feed" (pgLinkToFeed layout) . 100 | setStrAttr "wikititle" (wikiTitle cfg) . 101 | setStrAttr "pagetitle" (pgTitle layout) . 102 | T.setAttribute "javascripts" javascriptlinks . 103 | setStrAttr "pagename" page . 104 | setStrAttr "articlename" article . 105 | setStrAttr "discussionname" discussion . 106 | setStrAttr "pageUrl" (urlForPage page) . 107 | setStrAttr "articleUrl" (urlForPage article) . 108 | setStrAttr "discussionUrl" (urlForPage discussion) . 109 | setBoolAttr "ispage" (isPage page) . 110 | setBoolAttr "isarticlepage" (isPage page && not (isDiscussPage page)) . 111 | setBoolAttr "isdiscusspage" (isDiscussPage page) . 112 | setBoolAttr "pagetools" (pgShowPageTools layout) . 113 | setBoolAttr "sitenav" (pgShowSiteNav layout) . 114 | maybe id (T.setAttribute "markuphelp") (pgMarkupHelp layout) . 115 | setBoolAttr "printable" (pgPrintable layout) . 116 | maybe id (T.setAttribute "revision") rev . 117 | (if null (pgTabs layout) then id else T.setAttribute "tabs" 118 | (renderHtml tabs)) . 119 | (\f x xs -> if null xs then x else f xs) (T.setAttribute "messages") id (pgMessages layout) . 120 | T.setAttribute "usecache" (useCache cfg) . 121 | T.setAttribute "content" (renderHtml htmlContents) . 122 | setBoolAttr "wikiupload" ( uploadsAllowed cfg) $ 123 | templ 124 | 125 | 126 | -- auxiliary functions: 127 | 128 | linkForTab :: (Tab -> Html -> Html) -> String -> String -> Maybe String -> Tab -> Html 129 | linkForTab tabli base' page _ HistoryTab = 130 | tabli HistoryTab $ a ! href (fromString $ base' ++ "/_history" ++ urlForPage page) $ "history" 131 | linkForTab tabli _ _ _ DiffTab = 132 | tabli DiffTab $ a ! href "" $ "diff" 133 | linkForTab tabli base' page rev ViewTab = 134 | let origPage s = if isDiscussPage s 135 | then drop 1 s 136 | else s 137 | in if isDiscussPage page 138 | then tabli DiscussTab $ a ! 139 | href (fromString $ base' ++ urlForPage (origPage page)) $ "page" 140 | else tabli ViewTab $ a ! 141 | href (fromString $ base' ++ urlForPage page ++ 142 | case rev of 143 | Just r -> "?revision=" ++ r 144 | Nothing -> "") $ "view" 145 | linkForTab tabli base' page _ DiscussTab = 146 | tabli (if isDiscussPage page then ViewTab else DiscussTab) $ 147 | a ! href (fromString $ base' ++ if isDiscussPage page then "" else "/_discuss" ++ 148 | urlForPage page) $ "discuss" 149 | linkForTab tabli base' page rev EditTab = 150 | tabli EditTab $ a ! 151 | href (fromString $ base' ++ "/_edit" ++ urlForPage page ++ 152 | case rev of 153 | Just r -> "?revision=" ++ r ++ "&" ++ 154 | urlEncodeVars [("logMsg", "Revert to " ++ r)] 155 | Nothing -> "") $ if isNothing rev 156 | then "edit" 157 | else "revert" 158 | 159 | uploadsAllowed :: Config -> Bool 160 | uploadsAllowed = (0 <) . maxUploadSize 161 | -------------------------------------------------------------------------------- /src/Network/Gitit/Page.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | {- 3 | Copyright (C) 2009 John MacFarlane 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | -} 19 | 20 | {- Functions for translating between Page structures and raw 21 | - text strings. The strings may begin with a metadata block, 22 | - which looks like this (it is valid YAML): 23 | - 24 | - > --- 25 | - > title: Custom Title 26 | - > format: markdown+lhs 27 | - > toc: yes 28 | - > categories: foo bar baz 29 | - > ... 30 | - 31 | - This would tell gitit to use "Custom Title" as the displayed 32 | - page title (instead of the page name), to interpret the page 33 | - text as markdown with literate haskell, to include a table of 34 | - contents, and to include the page in the categories foo, bar, 35 | - and baz. 36 | - 37 | - The metadata block may be omitted entirely, and any particular line 38 | - may be omitted. The categories in the @categories@ field should be 39 | - separated by spaces. Commas will be treated as spaces. 40 | - 41 | - Metadata value fields may be continued on the next line, as long as 42 | - it is nonblank and starts with a space character. 43 | - 44 | - Unrecognized metadata fields are simply ignored. 45 | -} 46 | 47 | module Network.Gitit.Page ( stringToPage 48 | , pageToString 49 | , readCategories 50 | ) 51 | where 52 | import Network.Gitit.Types 53 | import Network.Gitit.Util (trim, splitCategories, parsePageType) 54 | import Text.ParserCombinators.Parsec 55 | import Data.Char (toLower) 56 | import Data.List (intercalate) 57 | import Data.Maybe (fromMaybe) 58 | import Data.ByteString.UTF8 (toString) 59 | import qualified Data.ByteString as B 60 | import qualified Data.ByteString.Char8 as BC 61 | import System.IO (withFile, Handle, IOMode(..)) 62 | import qualified Control.Exception as E 63 | import System.IO.Error (isEOFError) 64 | 65 | 66 | parseMetadata :: String -> ([(String, String)], String) 67 | parseMetadata raw = 68 | case parse pMetadataBlock "" raw of 69 | Left _ -> ([], raw) 70 | Right (ls, rest) -> (ls, rest) 71 | 72 | pMetadataBlock :: GenParser Char st ([(String, String)], String) 73 | pMetadataBlock = try $ do 74 | _ <- string "---" 75 | _ <- pBlankline 76 | ls <- manyTill pMetadataLine pMetaEnd 77 | skipMany pBlankline 78 | rest <- getInput 79 | return (ls, rest) 80 | 81 | pMetaEnd :: GenParser Char st Char 82 | pMetaEnd = try $ do 83 | string "..." <|> string "---" 84 | pBlankline 85 | 86 | pBlankline :: GenParser Char st Char 87 | pBlankline = try $ many (oneOf " \t") >> newline 88 | 89 | pMetadataLine :: GenParser Char st (String, String) 90 | pMetadataLine = try $ do 91 | first <- letter 92 | rest <- many (letter <|> digit <|> oneOf "-_") 93 | let ident = first:rest 94 | skipMany (oneOf " \t") 95 | _ <- char ':' 96 | rawval <- many $ noneOf "\n\r" 97 | <|> (try $ newline >> notFollowedBy pBlankline >> 98 | skipMany1 (oneOf " \t") >> return ' ') 99 | _ <- newline 100 | return (ident, trim rawval) 101 | 102 | -- | Read a string (the contents of a page file) and produce a Page 103 | -- object, using defaults except when overridden by metadata. 104 | stringToPage :: Config -> String -> String -> Page 105 | stringToPage conf pagename raw = 106 | let (ls, rest) = parseMetadata raw 107 | page' = Page { pageName = pagename 108 | , pageFormat = defaultPageType conf 109 | , pageLHS = defaultLHS conf 110 | , pageTOC = tableOfContents conf 111 | , pageTitle = pagename 112 | , pageCategories = [] 113 | , pageText = filter (/= '\r') rest 114 | , pageMeta = ls } 115 | in foldr adjustPage page' ls 116 | 117 | adjustPage :: (String, String) -> Page -> Page 118 | adjustPage ("title", val) page' = page' { pageTitle = val } 119 | adjustPage ("format", val) page' = page' { pageFormat = pt, pageLHS = lhs } 120 | where (pt, lhs) = parsePageType val 121 | adjustPage ("toc", val) page' = page' { 122 | pageTOC = map toLower val `elem` ["yes","true"] } 123 | adjustPage ("categories", val) page' = 124 | page' { pageCategories = splitCategories val ++ pageCategories page' } 125 | adjustPage (_, _) page' = page' 126 | 127 | -- | Write a string (the contents of a page file) corresponding to 128 | -- a Page object, using explicit metadata only when needed. 129 | pageToString :: Config -> Page -> String 130 | pageToString conf page' = 131 | let pagename = pageName page' 132 | pagetitle = pageTitle page' 133 | pageformat = pageFormat page' 134 | pagelhs = pageLHS page' 135 | pagetoc = pageTOC page' 136 | pagecats = pageCategories page' 137 | metadata = filter 138 | (\(k, _) -> not (k `elem` 139 | ["title", "format", "toc", "categories"])) 140 | (pageMeta page') 141 | metadata' = (if pagename /= pagetitle 142 | then "title: " ++ pagetitle ++ "\n" 143 | else "") ++ 144 | (if pageformat /= defaultPageType conf || 145 | pagelhs /= defaultLHS conf 146 | then "format: " ++ 147 | map toLower (show pageformat) ++ 148 | if pagelhs then "+lhs\n" else "\n" 149 | else "") ++ 150 | (if pagetoc /= tableOfContents conf 151 | then "toc: " ++ 152 | (if pagetoc then "yes" else "no") ++ "\n" 153 | else "") ++ 154 | (if not (null pagecats) 155 | then "categories: " ++ intercalate ", " pagecats ++ "\n" 156 | else "") ++ 157 | (unlines (map (\(k, v) -> k ++ ": " ++ v) metadata)) 158 | in (if null metadata' then "" else "---\n" ++ metadata' ++ "...\n\n") 159 | ++ pageText page' 160 | 161 | -- | Read categories from metadata strictly. 162 | readCategories :: FilePath -> IO [String] 163 | readCategories f = 164 | withFile f ReadMode $ \h -> 165 | E.catch (do fl <- B.hGetLine h 166 | if dashline fl 167 | then do -- get rest of metadata 168 | rest <- hGetLinesTill h dotOrDashline 169 | let (md,_) = parseMetadata $ unlines $ "---":rest 170 | return $ splitCategories $ fromMaybe "" 171 | $ lookup "categories" md 172 | else return []) 173 | (\e -> if isEOFError e then return [] else E.throwIO e) 174 | 175 | dashline :: B.ByteString -> Bool 176 | dashline x = 177 | case BC.unpack x of 178 | ('-':'-':'-':xs) | all (==' ') xs -> True 179 | _ -> False 180 | 181 | dotOrDashline :: B.ByteString -> Bool 182 | dotOrDashline x = 183 | case BC.unpack x of 184 | ('-':'-':'-':xs) | all (==' ') xs -> True 185 | ('.':'.':'.':xs) | all (==' ') xs -> True 186 | _ -> False 187 | 188 | hGetLinesTill :: Handle -> (B.ByteString -> Bool) -> IO [String] 189 | hGetLinesTill h end = do 190 | next <- B.hGetLine h 191 | if end next 192 | then return [toString next] 193 | else do 194 | rest <- hGetLinesTill h end 195 | return (toString next:rest) 196 | -------------------------------------------------------------------------------- /src/Network/Gitit/Plugins.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | {- 3 | Copyright (C) 2009 John MacFarlane 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | -} 19 | 20 | {- Functions for loading plugins. 21 | -} 22 | 23 | module Network.Gitit.Plugins ( loadPlugin, loadPlugins ) 24 | where 25 | import Network.Gitit.Types 26 | import System.FilePath (takeBaseName) 27 | import Control.Monad (unless) 28 | import System.Log.Logger (logM, Priority(..)) 29 | #ifdef _PLUGINS 30 | import Data.List (isInfixOf, isPrefixOf) 31 | import GHC 32 | import GHC.Paths 33 | import Unsafe.Coerce 34 | 35 | loadPlugin :: FilePath -> IO Plugin 36 | loadPlugin pluginName = do 37 | logM "gitit" WARNING ("Loading plugin '" ++ pluginName ++ "'...") 38 | runGhc (Just libdir) $ do 39 | dflags <- getSessionDynFlags 40 | setSessionDynFlags dflags 41 | -- initDynFlags 42 | unless ("Network.Gitit.Plugin." `isPrefixOf` pluginName) 43 | $ do 44 | #if __GLASGOW_HASKELL__ >= 904 45 | addTarget =<< guessTarget pluginName Nothing Nothing 46 | #else 47 | addTarget =<< guessTarget pluginName Nothing 48 | #endif 49 | r <- load LoadAllTargets 50 | case r of 51 | Failed -> error $ "Error loading plugin: " ++ pluginName 52 | Succeeded -> return () 53 | let modName = 54 | if "Network.Gitit.Plugin" `isPrefixOf` pluginName 55 | then pluginName 56 | else if "Network/Gitit/Plugin/" `isInfixOf` pluginName 57 | then "Network.Gitit.Plugin." ++ takeBaseName pluginName 58 | else takeBaseName pluginName 59 | pr <- parseImportDecl "import Prelude" 60 | i <- parseImportDecl "import Network.Gitit.Interface" 61 | m <- parseImportDecl ("import " ++ modName) 62 | setContext [IIDecl m, IIDecl i, IIDecl pr] 63 | value <- compileExpr (modName ++ ".plugin :: Plugin") 64 | let value' = (unsafeCoerce value) :: Plugin 65 | return value' 66 | 67 | #else 68 | 69 | loadPlugin :: FilePath -> IO Plugin 70 | loadPlugin pluginName = do 71 | error $ "Cannot load plugin '" ++ pluginName ++ 72 | "'. gitit was not compiled with plugin support." 73 | return undefined 74 | 75 | #endif 76 | 77 | loadPlugins :: [FilePath] -> IO [Plugin] 78 | loadPlugins pluginNames = do 79 | plugins' <- mapM loadPlugin pluginNames 80 | unless (null pluginNames) $ logM "gitit" WARNING "Finished loading plugins." 81 | return plugins' 82 | 83 | -------------------------------------------------------------------------------- /src/Network/Gitit/Server.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | {-# OPTIONS_GHC -fno-warn-orphans #-} 3 | {- 4 | Copyright (C) 2008 John MacFarlane 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | -} 20 | 21 | {- Re-exports Happstack functions needed by gitit, including 22 | replacements for Happstack functions that don't handle UTF-8 properly, and 23 | new functions for setting headers and zipping contents and for looking up IP 24 | addresses. 25 | -} 26 | 27 | module Network.Gitit.Server 28 | ( module Happstack.Server 29 | , withExpiresHeaders 30 | , setContentType 31 | , setFilename 32 | , lookupIPAddr 33 | , getHost 34 | , compressedResponseFilter 35 | ) 36 | where 37 | import Happstack.Server 38 | import Happstack.Server.Compression (compressedResponseFilter) 39 | import Network.Socket (getAddrInfo, defaultHints, addrAddress) 40 | import Control.Monad (liftM) 41 | import Data.ByteString.UTF8 as U hiding (lines) 42 | 43 | withExpiresHeaders :: ServerMonad m => m Response -> m Response 44 | withExpiresHeaders = liftM (setHeader "Cache-Control" "max-age=21600") 45 | 46 | setContentType :: String -> Response -> Response 47 | setContentType = setHeader "Content-Type" 48 | 49 | setFilename :: String -> Response -> Response 50 | setFilename = setHeader "Content-Disposition" . \fname -> "attachment; filename=\"" ++ fname ++ "\"" 51 | 52 | -- IP lookup 53 | 54 | lookupIPAddr :: String -> IO (Maybe String) 55 | lookupIPAddr hostname = do 56 | addrs <- getAddrInfo (Just defaultHints) (Just hostname) Nothing 57 | if null addrs 58 | then return Nothing 59 | else return $ Just $ takeWhile (/=':') $ show $ addrAddress $ case addrs of -- head addrs 60 | [] -> error "lookupIPAddr, no addrs" 61 | (x:_) -> x 62 | getHost :: ServerMonad m => m (Maybe String) 63 | getHost = liftM (maybe Nothing (Just . U.toString)) $ getHeaderM "Host" 64 | -------------------------------------------------------------------------------- /src/Network/Gitit/State.hs: -------------------------------------------------------------------------------- 1 | {- 2 | Copyright (C) 2008 John MacFarlane 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | -} 18 | 19 | {- Functions for maintaining user list and session state. 20 | -} 21 | 22 | module Network.Gitit.State where 23 | 24 | import qualified Control.Exception as E 25 | import qualified Data.Map as M 26 | import System.Random (randomRIO) 27 | import Data.Digest.Pure.SHA (sha512, showDigest) 28 | import qualified Data.ByteString.Lazy.UTF8 as L (fromString) 29 | import Data.IORef 30 | import System.IO.Unsafe (unsafePerformIO) 31 | import Control.Monad (liftM, replicateM) 32 | import Control.Monad.IO.Class 33 | import Control.Monad.Reader 34 | import Data.FileStore 35 | import Data.List (intercalate) 36 | import System.Log.Logger (Priority(..), logM) 37 | import Network.Gitit.Types 38 | 39 | gititstate :: IORef GititState 40 | gititstate = unsafePerformIO $ newIORef GititState { sessions = undefined 41 | , users = undefined 42 | , renderPage = undefined 43 | , plugins = undefined } 44 | 45 | updateGititState :: MonadIO m => (GititState -> GititState) -> m () 46 | updateGititState fn = liftIO $! atomicModifyIORef gititstate $ \st -> (fn st, ()) 47 | 48 | queryGititState :: MonadIO m => (GititState -> a) -> m a 49 | queryGititState fn = liftM fn $ liftIO $! readIORef gititstate 50 | 51 | debugMessage :: String -> GititServerPart () 52 | debugMessage msg = liftIO $ logM "gitit" DEBUG msg 53 | 54 | mkUser :: String -- username 55 | -> String -- email 56 | -> String -- unhashed password 57 | -> IO User 58 | mkUser uname email pass = do 59 | salt <- genSalt 60 | return User { uUsername = uname, 61 | uPassword = Password { pSalt = salt, 62 | pHashed = hashPassword salt pass }, 63 | uEmail = email } 64 | 65 | genSalt :: IO String 66 | genSalt = replicateM 32 $ randomRIO ('0','z') 67 | 68 | hashPassword :: String -> String -> String 69 | hashPassword salt pass = showDigest $ sha512 $ L.fromString $ salt ++ pass 70 | 71 | authUser :: String -> String -> GititServerPart Bool 72 | authUser name pass = do 73 | users' <- queryGititState users 74 | case M.lookup name users' of 75 | Just u -> do 76 | let salt = pSalt $ uPassword u 77 | let hashed = pHashed $ uPassword u 78 | return $ hashed == hashPassword salt pass 79 | Nothing -> return False 80 | 81 | isUser :: String -> GititServerPart Bool 82 | isUser name = liftM (M.member name) $ queryGititState users 83 | 84 | addUser :: String -> User -> GititServerPart () 85 | addUser uname user = 86 | updateGititState (\s -> s { users = M.insert uname user (users s) }) >> 87 | getConfig >>= 88 | liftIO . writeUserFile 89 | 90 | adjustUser :: String -> User -> GititServerPart () 91 | adjustUser uname user = updateGititState 92 | (\s -> s { users = M.adjust (const user) uname (users s) }) >> 93 | getConfig >>= 94 | liftIO . writeUserFile 95 | 96 | delUser :: String -> GititServerPart () 97 | delUser uname = 98 | updateGititState (\s -> s { users = M.delete uname (users s) }) >> 99 | getConfig >>= 100 | liftIO . writeUserFile 101 | 102 | writeUserFile :: Config -> IO () 103 | writeUserFile conf = do 104 | usrs <- queryGititState users 105 | E.handle handleWriteError $ writeFile (userFile conf) $ 106 | "[" ++ intercalate "\n," (map show $ M.toList usrs) ++ "\n]" 107 | where handleWriteError :: E.SomeException -> IO () 108 | handleWriteError e = logM "gitit" ERROR $ 109 | "Error writing user file " ++ show (userFile conf) ++ 110 | "\n" ++ show e 111 | 112 | getUser :: String -> GititServerPart (Maybe User) 113 | getUser uname = liftM (M.lookup uname) $ queryGititState users 114 | 115 | isSession :: MonadIO m => SessionKey -> m Bool 116 | isSession key = liftM (M.member key . unsession) $ queryGititState sessions 117 | 118 | setSession :: MonadIO m => SessionKey -> SessionData -> m () 119 | setSession key u = updateGititState $ \s -> 120 | s { sessions = Sessions . M.insert key u . unsession $ sessions s } 121 | 122 | newSession :: MonadIO m => SessionData -> m SessionKey 123 | newSession u = do 124 | key <- liftIO $ SessionKey <$> randomRIO (0, 1000000000) 125 | setSession key u 126 | return key 127 | 128 | delSession :: MonadIO m => SessionKey -> m () 129 | delSession key = updateGititState $ \s -> 130 | s { sessions = Sessions . M.delete key . unsession $ sessions s } 131 | 132 | getSession :: MonadIO m => SessionKey -> m (Maybe SessionData) 133 | getSession key = queryGititState $ M.lookup key . unsession . sessions 134 | 135 | getConfig :: GititServerPart Config 136 | getConfig = liftM wikiConfig ask 137 | 138 | getFileStore :: GititServerPart FileStore 139 | getFileStore = liftM wikiFileStore ask 140 | 141 | getDefaultPageType :: GititServerPart PageType 142 | getDefaultPageType = liftM defaultPageType getConfig 143 | 144 | getDefaultLHS :: GititServerPart Bool 145 | getDefaultLHS = liftM defaultLHS getConfig 146 | -------------------------------------------------------------------------------- /src/Network/Gitit/Util.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP, ScopedTypeVariables, OverloadedStrings #-} 2 | {- 3 | Copyright (C) 2009 John MacFarlane 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program; if not, write to the Free Software 14 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | -} 16 | 17 | {- Utility functions for Gitit. 18 | -} 19 | 20 | module Network.Gitit.Util ( readFileUTF8 21 | , inDir 22 | , withTempDir 23 | , orIfNull 24 | , splitCategories 25 | , trim 26 | , yesOrNo 27 | , parsePageType 28 | , encUrl 29 | , getPageTypeDefaultExtensions 30 | ) 31 | where 32 | import System.Directory 33 | import Control.Exception (bracket) 34 | import System.FilePath ((), (<.>)) 35 | import System.IO.Error (isAlreadyExistsError) 36 | import Control.Monad.Trans (liftIO) 37 | import Data.Char (toLower, isAscii) 38 | import Data.Text (Text) 39 | import Network.Gitit.Types 40 | import qualified Control.Exception as E 41 | import qualified Text.Pandoc.UTF8 as UTF8 42 | import Text.Pandoc (Extension(..), Extensions, getDefaultExtensions, enableExtension) 43 | import Network.URL (encString) 44 | 45 | #if !MIN_VERSION_pandoc(2,12,0) 46 | import qualified Data.Text as T 47 | #endif 48 | 49 | -- | Read file as UTF-8 string. Encode filename as UTF-8. 50 | readFileUTF8 :: FilePath -> IO Text 51 | #if MIN_VERSION_pandoc(2,12,0) 52 | readFileUTF8 = UTF8.readFile 53 | #else 54 | readFileUTF8 = fmap T.pack . UTF8.readFile 55 | #endif 56 | 57 | -- | Perform a function a directory and return to working directory. 58 | inDir :: FilePath -> IO a -> IO a 59 | inDir d action = do 60 | w <- getCurrentDirectory 61 | setCurrentDirectory d 62 | result <- action 63 | setCurrentDirectory w 64 | return result 65 | 66 | -- | Perform a function in a temporary directory and clean up. 67 | withTempDir :: FilePath -> (FilePath -> IO a) -> IO a 68 | withTempDir baseName f = do 69 | oldDir <- getCurrentDirectory 70 | bracket (createTempDir 0 baseName) 71 | (\tmp -> setCurrentDirectory oldDir >> removeDirectoryRecursive tmp) 72 | f 73 | 74 | -- | Create a temporary directory with a unique name. 75 | createTempDir :: Integer -> FilePath -> IO FilePath 76 | createTempDir num baseName = do 77 | sysTempDir <- getTemporaryDirectory 78 | let dirName = sysTempDir baseName <.> show num 79 | liftIO $ E.catch (createDirectory dirName >> return dirName) $ 80 | \e -> if isAlreadyExistsError e 81 | then createTempDir (num + 1) baseName 82 | else ioError e 83 | 84 | -- | Returns a list, if it is not null, or a backup, if it is. 85 | orIfNull :: [a] -> [a] -> [a] 86 | orIfNull lst backup = if null lst then backup else lst 87 | 88 | -- | Split a string containing a list of categories. 89 | splitCategories :: String -> [String] 90 | splitCategories = words . map puncToSpace . trim 91 | where puncToSpace x | x `elem` ['.',',',';',':'] = ' ' 92 | puncToSpace x = x 93 | 94 | -- | Trim leading and trailing spaces. 95 | trim :: String -> String 96 | trim = reverse . trimLeft . reverse . trimLeft 97 | where trimLeft = dropWhile (`elem` [' ','\t']) 98 | 99 | -- | Show Bool as "yes" or "no". 100 | yesOrNo :: Bool -> String 101 | yesOrNo True = "yes" 102 | yesOrNo False = "no" 103 | 104 | parsePageType :: String -> (PageType, Bool) 105 | parsePageType s = 106 | case map toLower s of 107 | "markdown" -> (Markdown,False) 108 | "markdown+lhs" -> (Markdown,True) 109 | "commonmark" -> (CommonMark,False) 110 | "docbook" -> (DocBook,False) 111 | "rst" -> (RST,False) 112 | "rst+lhs" -> (RST,True) 113 | "html" -> (HTML,False) 114 | "textile" -> (Textile,False) 115 | "latex" -> (LaTeX,False) 116 | "latex+lhs" -> (LaTeX,True) 117 | "org" -> (Org,False) 118 | "mediawiki" -> (MediaWiki,False) 119 | x -> error $ "Unknown page type: " ++ x 120 | 121 | getPageTypeDefaultExtensions :: PageType -> Bool -> Extensions 122 | getPageTypeDefaultExtensions pt lhs = 123 | if lhs 124 | then enableExtension Ext_literate_haskell defaults 125 | else defaults 126 | where defaults = getDefaultExtensions $ 127 | case pt of 128 | CommonMark -> "commonmark" 129 | DocBook -> "docbook" 130 | HTML -> "html" 131 | LaTeX -> "latex" 132 | Markdown -> "markdown" 133 | MediaWiki -> "mediawiki" 134 | Org -> "org" 135 | RST -> "rst" 136 | Textile -> "textile" 137 | 138 | encUrl :: String -> String 139 | encUrl = encString True isAscii 140 | -------------------------------------------------------------------------------- /stack.yaml: -------------------------------------------------------------------------------- 1 | nix: 2 | enable: false 3 | packages: [zlib zlib.dev pkg-config] 4 | 5 | flags: 6 | pandoc: 7 | embed_data_files: true 8 | gitit: 9 | plugins: true 10 | mintty: 11 | Win32-2-13-1: false 12 | sendfile: 13 | portable: true 14 | 15 | packages: 16 | - '.' 17 | extra-deps: 18 | - filestore-0.6.5 19 | - recaptcha-0.1.0.4 20 | 21 | resolver: lts-21.1 22 | --------------------------------------------------------------------------------