Git Product home page Git Product logo

yst's Introduction

yst - static websites from YAML and string templates

yst is a tool for generating a static website by filling string templates with data taken from YAML or CSV text files or SQLite3 file based databases. This approach combines the speed, security, and ease of deployment of a static website with the flexibility and maintainability of a dynamic site that separates presentation and data.

Installing yst

yst is written in Haskell. The easiest way to install yst is by using Haskell's cabal install tool. The best way to get this tool is to install the Haskell platform, which includes a complete installation of the GHC compiler and the cabal executable.

Once you have cabal, you can install yst with two commands:

cabal update
cabal install yst

(Note that by default, cabal installs the yst executable into a special directory: ~/.cabal/bin on unix systems. You will need to make sure that directory is in your system path.)

If you get the error "yst-0.2.3 depends on template-haskell-2.4.0.0 which failed to install," then try the following:

cabal install syb-with-class-0.6
cabal install yst

Getting started

To get started with yst, use the command:

yst create mysite

This will create a directory mysite and populate it with the files needed for a sample site. Change to this directory and run yst with no arguments to create the site:

cd mysite
yst

The site will be created in the site directory. Open up site/index.html to take a look.

The configuration file index.yaml tells yst which pages to build, and from which templates and data files. Let's take a look, so we can see what went into index.html. The file is a YAML list of YAML hashes (name/value pairs). The first item is

- url      : index.html
  title    : Home
  template : index.st
  requires : event.st
  data     :
    recentevents : FROM events.yaml ORDER BY date DESC LIMIT 2

This says: build the page index.html from the string template index.st (and subtemplate event.st) and data from events.yaml. Sort this data (a list of events) by date in descending order, and discard all but the first two items. Put the resulting data in the string template attribute recentevents. Give the page the title "Home."

Now take a look at events.yaml, the data source. Again it is a YAML list of YAML hashes, each item in the list representing one event. The first is:

- date: 2009-06-28
  speaker:  Sam Smith
  title: Building a static website

Pretty self-explanatory! Try adding a new event, then rebuild the site by typing yst and see how it looks.

If you have problems, make sure events.yaml is a valid YAML file. Structure is shown through indentation, so make sure things line up right. And occasionally you may need to use quotation marks around string values---for example, when a title contains a colon.

There's one more ingredient in our recipe---the string templates. Take a look at index.st, the template from which index.html is built:

# Welcome

Here's our website. Have a look around.

Our last two events:

$recentevents:event()$

For a complete list of events, see the [events](events.html) page.

The first thing to notice is that this is in markdown format (or, to be precise, markdown with pandoc extensions). So, for example, the first line is a level-one header, and there is a hyperlink to the events page on the last line.

The second thing to notice is the bit between dollar signs. This is a placeholder for some formatted data. The rendered template will include the list recentevents (remember, this was populated from events.yaml after some transformations---see above). And each element of this list will be formatted by a subtemplate called event.st:

- $if(it.speaker)$$it.speaker; separator=" and "$, $endif$ *$it.title$*.

Let's break this down. The whole line will print a bulleted list item. it here refers to the event that is being processed by the template. So the first part says: if this event has a speaker field, print the speaker, or, if the speaker field is a list, print all the speakers separated by the word "and", followed by a comma. And the second part says, print the contents of the title field, surrounding it with asterisks (which is the markdown way of making it emphasized).

(See the string template documentation for details of template syntax, and examples.)

If you look at index.html, you'll see this rough structure, but in an HTML file, not a markdown file. yst converts the rendered markdown template to HTML (using pandoc), and inserts it into a "layout" file called layout.html.st. If you look at this file, you'll see that it's an HTML file with blanks for $contents$ and $nav$. The $contents$ blank gets filled by the rendered template, converted to HTML, and the $nav$ blank gets filled by an HTML navigation menu (an unordered list with links).

To summarize our example, then: yst sorts and filters the data in events.yaml according to our instructions; inserts this data into the events.st template, formatting each item using the event.st template; uses pandoc to convert the rendered template to HTML; constructs a navigation menu; and puts the contents and navigation menu in the layout template layout.html.st. The result is our page, index.html.

Reference

The yst command

Synopsis:

yst                    # rebuilds site, using default config.yaml
yst -f myconf.yaml     # rebuilds site, using myconf.yaml as config
yst create newsite     # creates a starter (demo) site in newsite directory

When run without arguments, yst looks at index.yaml to determine the dependencies of each page, and rebuilds only the pages whose dependencies have changed since the last build.

In order for this to work properly, you must be sure to list all subtemplates included recursively in the main page template using the requires field. This field takes a single filename or a YAML list, which may be in either of two formats:

requires: [event.st, date.st]

or

requires:
  - event.st
  - date.st

If you don't list all the subtemplates needed to render a page under requires, yst will still work, but it might sometimes fail to rebuild a page when one of these subtemplates has been changed.

config.yaml

The configuration file specifies the following:

  • indexfile: the filename of the index file (default: index.yaml)
  • title: the title of the whole site
  • sourcedir: list of directories containing templates and page sources (default: .)
  • datadir: list of directories containing yaml data files (default: .)
  • filesdir: list of directories containing static files (default: files)
  • layout: the default layout template for the site, relative to sourcedir (default: layout.html.st)
  • navstyle: either top for a top menu or side for a side menu

The directories specified by sourcedir and datadir are searched in order to find source/template or data files, respectively. This allows for a ../templates directory to be shared among multiple sites, for example. Static files are merged from the contents of all directories in filesdir. All of these accept a string as a singleton list.

index.yaml and submenus

The index file is a YAML list of pages. Each page may have the following fields:

  • url: the relative URL of the page to be built
  • title: the title of the page
  • template: the main string template from which the page will be built
  • source: the markdown source from which the page will be built
  • requires: other files changes to which should trigger a page rebuild (primarily subtemplates of the main page template)
  • data: string template attributes, data sources, and transformations (see below)
  • layout: a layout template to use, if other than the site default
  • inmenu: if 'no', the page will not be included in the site navigation menu

Each page must have at least url, title, and either template or source. Values for template, source, and layout are relative to sourcedir specified in config.yaml.

The pages may be organized into a tree-like hierarchy, which will be reflected in the site navigation menu. It is easiest to see how this works by example:

- Rooms:
  - url      : room101.html
    title    : Room 101
    source   : room101.txt

  - url      : room203.html
    title    : Room 203
    source   : room203.txt

Here we have a subtree called "Rooms" with two pages under it. Subtrees can contain other subtrees. Just be consistent about indentation.

The data field

The data field in index.yaml can populate any number of stringtemplate attributes with data from YAML or CSV files or SQLite3 databases. The syntax is easiest to explain by example (note that the keywords do not have to be in ALL CAPS, although they may, and the query doesn't have to end with a semicolon, though it may):

data:
    events:  from events.yaml order by date desc group by title then location
    people:  from people.csv order by birthday then lastname where
              birthstate = 'CA' limit 5
    beststudents: from students.sqlite 
              query "select * from students where grade > 5"
              order by name

First we have the name of the stringtemplate attribute to be populated (say, events). Then, after the colon, we have the data source (events.yaml). If the data source is an SQLite3 database, it should be followed by a query that is a quoted string.

The data source is followed by one or more transformations, which will be applied in order. Here are the possible transformations. In what follows, brackets denote an optional component, | denotes alternatives, and * indicates that the component may be repeated several times:

ORDER BY field [ASC|DESC] [THEN field [ASC|DESC]]*

Sorts a list by comparing the value of field. ASC (the default) means "ascending", and DESC means "descending". The keyword THEN is used to separate fields that will be compared in order. So, if we are ordering by birthday then lastname, we will compare birthdays, and if these are equal, we will break the tie by comparing last names.

GROUP BY field [THEN field]*

Converts a list into a list of lists, where each sublist contains only items with the same value for field. So, for example, group by date takes a list of events and produces a list of lists of items, where each sublist contains events occuring at a single date. GROUP BY date THEN venue would produce a list of lists of lists, and so on.

LIMIT n

Removes all but the n top items from a list. n must be a number.

WHERE condition

Selects only items that meet a condition.

A condition in a WHERE statement is a Boolean combination (using NOT, AND, OR, and parentheses for disambiguation) of basic conditions. A basic condition is either of the form value op value, where value may be either a fieldname or a constant, or of the form HAS fieldname' where fieldname' is a string constant. Note that all constants must be enclosed in quotes. op may be one of the following: =, >=, <=, >, < and 'contains'.

The basic condition arg1 contains arg2 succeeds if and only if arg1 is a fieldname whose value is a list containing the value of arg2.

The basic condition HAS fieldname' succeeds if and only if the item has the fieldname as a field. For example, HAS "data"'.

Note that the order of transformations is significant. You can get different results if you use LIMIT before or after ORDER BY, for example.

If you want to specify an attribute's value directly, rather than reading it from a file, just omit the "FROM":

data:
  deadline: 11/20/2009

Any YAML value can be given to an attribute in this way.

Static files

Any file or subdirectory in the files directory (or whatever is the value of filesdir in config.yaml) will be copied verbatim to the site. So this is the place to put javascripts, css files, images, PDFs, and the like.

Date fields

yst will recognize date fields in data files automatically, if the dates are in one of the following formats:

  • the locale's standard date format
  • MM/DD/YYYY (e.g. 04/28/1953)
  • MM/DD/YY (e.g. 04/28/53)
  • YYYY-MM-DD (e.g. 1953-04-28)
  • DD MON YYYY (e.g. 28 Apr 1953)

Dates may be formatted in templates using a stringtemplate "format" directive. There's an example in the demo file date.st:

$it; format="%B %d, %Y"$

The following codes may be used in format strings (taken from Haskell's Date.Time.Format documentation):

  • %D : same as %m/%d/%y
  • %F : same as %Y-%m-%d
  • %x : as dateFmt locale (e.g. %m/%d/%y)
  • %Y : year
  • %y : last two digits of year, 00 - 99
  • %C : century (being the first two digits of the year), 00 - 99
  • %B : month name, long form (fst from months locale), January - December
  • %b, %h : month name, short form (snd from months locale), Jan - Dec
  • %m : month of year, leading 0 as needed, 01 - 12
  • %d : day of month, leading 0 as needed, 01 - 31
  • %e : day of month, leading space as needed, 1 - 31
  • %j : day of year for Ordinal Date format, 001 - 366
  • %G : year for Week Date format
  • %g : last two digits of year for Week Date format, 00 - 99
  • %f : century (first two digits of year) for Week Date format, 00 - 99
  • %V : week for Week Date format, 01 - 53
  • %u : day for Week Date format, 1 - 7
  • %a : day of week, short form (snd from wDays locale), Sun - Sat
  • %A : day of week, long form (fst from wDays locale), Sunday - Saturday
  • %U : week number of year, where weeks start on Sunday (as sundayStartWeek), 00 - 53
  • %w : day of week number, 0 (= Sunday) - 6 (= Saturday)
  • %W : week number of year, where weeks start on Monday (as mondayStartWeek), 00 - 53

Lists as values

In some cases, a field may have one or several values. For example, an event might occur at a date or a date range, and an article may have one author or a list of authors.

An elegant way to handle these cases is to let the field take either a scalar or a list value, and use stringtemplate's "separator" directive to format the result appropriately. So, for example, in our events.yaml we have:

- date: 2009-06-28
  speaker:  Sam Smith
  title: Building a static website

- date:  2009-04-15
  speaker:
    - Sam Smith
    - '[Jim Jones](http://foo.bar/baz)'
  title: Advantages of static websites

- date:
    - 2009-04-20
    - 2009-04-22
  title: Seminar on web security

- date: 2009-04-15
  speaker: Jim Jones
  title:  XSS attacks for dummies

Note that the date field is sometimes a single date, sometimes a list (with start and end date of a range), and the speaker field is sometimes a single speaker, and sometimes a range.

Here is how we handle the date in eventgroup.st:

**$first(it).date:date(); separator=" - "$**

Here first(it).date is the raw data, which may be a single date or a list. first(it).date:date() is the result of formatting each date using the date.st template (discussed above). And first(it).date:date; separator=" - " is the result of taking this list of formatted dates and concatenating them, separated by a hyphen. When there is just one date, we just get a date. When there are two, we get a date range.

We can use the same trick in the case of speaker. If it is an event record, then it.speaker; separator=" and " will be either a single speaker (if the value is not a list) or a list of speakers separated by "and" (if it is a list).

In sorting lists with order by, yst compares two lists by comparing the first members, then (in case of a tie) the second members, and so on. If one item is a list and the other a scalar, the scalar is compared to the first item of the list. So, in the example above, Seminar on web security will be sorted an earlier than an event with date 2009-04-21, and later than an event with date range 2009-04-20 - 2009-04-21.

YAML gotchas

If you have a colon in a YAML value, be sure to enclose it in quotes, or you'll get an error. So,

title:  "Cheever: A Life"

not

title:  Cheever: A Life

Or (especially if the string is long), use > or | for a wrapped or unwrapped multiline string literal:

title: |
  A very long string that
  goes on and on.

  You can even have blank lines,
  but be sure to maintain indentation.

Using CSV files instead of YAML

If you like, you can use a CSV file instead of YAML for your data source. Just give it the extension .csv. In index.yaml, you'd have:

data:
  events: from events.csv order by date desc

This can be handy if you're using existing data, because spreadsheets and databases can easily be dumped to CSV. In the case of a SQL database, you can use a query like this to get the CSV:

SELECT * INTO OUTFILE 'result.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM my_table;

(Thanks to http://www.terminally-incoherent.com/blog/2006/07/20/dump-mysql-table-into-csv-file/.)

Using a SQLite database as data source

You can also get the data directly from a database. Just give the file name from the database followed by a query quoted in "'s

In this way you can do joins and other advanced operations on your data before handing them over to yst:

data:
  meetings : FROM data.sqlite 
             QUERY "select * from meetings 
               left outer join persons
               on meetings.speaker = persons.name"

Using HTML in the templates

Markdown allows raw HTML to be used, so you can embed HTML in templates. Pandoc's extended markdown is different from standard markdown in that it parses text within HTML block elements as markdown. So, for example, you can include a section in <div> tags, or use raw <ul> and <li> tags instead of markdown formatting.

Layout templates

Layout files are also string templates, but they are not treated as markdown by default. They should use a double extension to indicate the format. So, for example, an HTML layout could be standard.html.st, and a LaTeX layout could be printed.tex.st. yst will convert the page contents appropriately for the format of the layout template. Here are the supported formats and extensions:

  • HTML: .html.st, .xhtml.st
  • LaTeX: .tex.st, .latex.st
  • ConTeXt: .context.st
  • Groff man: .1.st
  • Rich text format: .rtf.st
  • Texinfo: .texi.st
  • DocBook: .db.st
  • OpenDocument XML: .fodt.st
  • Plain text (markdown): .txt.st, .markdown.st

The demo site shows how you can use yst to produce a LaTeX document from the same data sources you use to produce HTML pages.

The following stringtemplate attributes are defined when layouts are rendered:

  • $contents$: the result of rendering the page and converting to the layout's format
  • $nav$: an HTML navigation menu created from index.yaml
  • $gendate$: the date the page was generated
  • $sitetitle$: the site title from config.yaml
  • $pagetitle$: the page title as defined in index.yaml
  • $root$: the path to the website's root, relative to the page being rendered. So, for example, if we are rendering rooms/room503.html, $root$ will have the value ../. Put $root$ in front of relative URLs in your layout file, so that the links aren't broken on pages in subdirectories.

Previewing a site

If you use only relative URLs in your site, you can preview it by opening any of the HTML files in site in your web browser. If you use absolute links, this won't work, but you can use Jinjing Wang's simple static web server maid:

cabal update
cabal install maid

To use maid to preview your site, just change to the site directory and start maid:

cd site
maid

The site will appear at http://localhost:3000. If you want to serve it at another port, just pass the port number as an argument to maid:

maid 5999

Development

Source code

yst's source code lives on github at http://github.com/jgm/yst/tree/master. You can clone the repository with

git://github.com/jgm/yst.git

To install the development code once you've checked it out, just do

cabal install

(But please stick to the released version if you don't like things to break unexpectedly!)

Reporting bugs

If you find a bug, please report it using the issue tracker on yst's github page.

yst's People

Contributors

codyreichert avatar jgm avatar jmitchell avatar league avatar ohad avatar sigurdmeldgaard avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

yst's Issues

datadir config variable does not work unless it is set to `.`

I am using yst to power a site, and when I tried to change the default value of the datadir config variable in config.yaml, I got an error which went along the lines of Error parsing books.yaml: books.yaml: openFile: does not exist (No such file or directory).

After poking around the source code, I realised that the getData method in Data.hs gets called with only the DataSpec instance, which contains only the name of the file and not the full path. In order to construct the full path, we need access to the Site instance which contains the dataDir field.

I have created a small patch which addresses the issue. Let me know if I am missing something.

Last div not properly closed

I have found an issue where the last div is not properly closed in a markdown template defined using several headings.

I added this to the demo website index.yaml:

- url      : bug.html
  title    : Bug
  template : bug.html.st
  requires : bug.st

bug.html.st contains:

<!-- Begin -->
$bug()$
<!-- End -->

bug.st contains:

# Heading 1

Lorem ipsur

# Heading 2

Lorem ipsur

The resulting page contains the following html:

      <div id="maincol" class="yui-b">
<!-- Begin --><div id="heading-1"
><h1
  >Heading 1</h1
  ><p
  >Lorem ipsur</p
  ></div
><div id="heading-2"
><h1
  >Heading 2</h1
  >Lorem ipsur<!-- End -->
</div
>
      </div>

I would have expect the div with id heading-2 to be closed prior to the end comment. It seems in this case it is closed later but in other circumstances it causes a big problem with the end comment is replaced with actual markup .

Literate Haskell input

This is a feature request, no bug report.

I'd like to be able to use .lhs files as source and .lhs.st files as template such that the input is interpreted as literate Haskell and the output is produced with syntax highlighting.

How difficult would it be to implement this?

Link to outside site in $nav$?

It would be nice to be able to have a link in the navigation list that links to an outside site, for example, an externally hosted blog (or even just a different part of the site that isn't managed and generated by yst).

Support custom `$nav$` rendering using templates

$nav$ currently generates hard-coded HTML (see

renderNav targeturl nodes = unpack $ renderText $
). It would be great if users could specify a template for it instead.

If you're interested I can work on this and file a PR.

Possible solution

Custom nav templates could be specified by setting an optional setting in the config.

config.yaml

navigation: navmenu.st

If it isn't set $nav$ in a layout template could fallback to a default template which renders the same HTML yst does now. The default would be something like this:

navmenu.st

<ul class="nav tree" $if(!it.toplevel)$style="display: none;"$endif$>
  $if(it.page)$
    <li $if(it.current)$class="current"$endif$>
      <a href="$it.url$">$it.title$</a>
    </li>
  $else$   <!-- a submenu -->
    <a class="tree-toggle nav-header">$it.title$</a>
    $it.entries:navmenu()$
  $endif$
</ul>

Failed to build yst - Ambiguous occurrence ‘defaultTimeLocale’

I'm using Arch 5.13.4-arch1-1 and did pacman -S ghc cabal-install stack && cabal update and configured Cabal for dynamic linking (https://wiki.archlinux.org/title/haskell#Installation).

Then I did cabal install yst and get the following error:

esolving dependencies...
Build profile: -w ghc-8.10.5 -O1
In order, the following will be built (use -v for more details):
 - yst-0.2.4.1 (exe:yst) (requires build)
Starting     yst-0.2.4.1 (all, legacy fallback)
Building     yst-0.2.4.1 (all, legacy fallback)

Failed to build yst-0.2.4.1.
Build log (
/home/me/.cabal/logs/ghc-8.10.5/yst-0.2.4.1-000c099766b225f780ac90ad904a516be4784fe25fff1c450497f8b2fcba7a42.log
):
Configuring yst-0.2.4.1...
Preprocessing executable 'yst' for yst-0.2.4.1..
Building executable 'yst' for yst-0.2.4.1..

<no location info>: warning: [-Wmissing-home-modules]
    These modules are needed for compilation but not listed in your .cabal file's other-modules:
        Paths_yst
[ 1 of 10] Compiling Paths_yst        ( dist/build/yst/autogen/Paths_yst.hs, dist/build/yst/yst-tmp/Paths_yst.dyn_o )
[ 2 of 10] Compiling Yst.Types        ( Yst/Types.hs, dist/build/yst/yst-tmp/Yst/Types.dyn_o )
[ 3 of 10] Compiling Yst.Util         ( Yst/Util.hs, dist/build/yst/yst-tmp/Yst/Util.dyn_o )

Yst/Util.hs:46:36: error:
    Ambiguous occurrence ‘defaultTimeLocale’
    It could refer to
       either ‘Data.Time.defaultTimeLocale’,
              imported from ‘Data.Time’ at Yst/Util.hs:34:1-16
              (and originally defined in ‘time-1.9.3:Data.Time.Format.Locale’)
           or ‘System.Locale.defaultTimeLocale’,
              imported from ‘System.Locale’ at Yst/Util.hs:37:23-39
   |
46 |    where parsetimeWith = parseTime defaultTimeLocale
   |                                    ^^^^^^^^^^^^^^^^^
cabal: Failed to build yst-0.2.4.1. See the build log above for details.

`cabal install yst` fails

I'm sure that this is my fault, but I've never installed anything through cabal before, and when I run cabal install yst I get this message:

Resolving dependencies...
cabal: Could not resolve dependencies:
trying: base-4.9.0.0/installed-4.9... (dependency of yst-0.5.1)
next goal: pandoc (dependency of yst-0.5.1)
rejecting: pandoc-1.17.1, pandoc-1.17.0.3, pandoc-1.17.0.2, pandoc-1.17.0.1,
pandoc-1.17 (conflict: yst => pandoc>=1.10 && <1.17)
trying: pandoc-1.16.0.2
next goal: haddock-library (dependency of pandoc-1.16.0.2)
rejecting: haddock-library-1.4.2, haddock-library-1.4.1 (conflict: pandoc =>
haddock-library>=1.1 && <1.3)
rejecting: haddock-library-1.2.1, haddock-library-1.2.0 (conflict:
base==4.9.0.0/installed-4.9..., haddock-library => base>=4.5 && <4.9)
rejecting: haddock-library-1.1.1 (conflict: base==4.9.0.0/installed-4.9...,
haddock-library => base>=4.3 && <4.8)
rejecting: haddock-library-1.1.0 (conflict: base==4.9.0.0/installed-4.9...,
haddock-library => base>=4.5 && <4.8)
rejecting: haddock-library-1.0.1, haddock-library-1.0.0 (conflict: pandoc =>
haddock-library>=1.1 && <1.3)
Backjump limit reached (currently 2000, change with --max-backjumps or try to
run with --reorder-goals).

I get the same kind of message if I run it with --reorder-goals. If I increase the backjumps to infinity (by setting it to -1) it just hangs.

What do I need to do? I've tried this with the version of cabal-install that comes from brew, and the full haskell-package distribution from brew cask. I'm on Mac OSX El Capitan.

Thanks!

Newline in event.st necessary for proper behaviour

yst create mysite creates, among other things, event.st. Deleting the newlines at the end of this file causes the items to be all squished into one item. I guess this has something to do with moving to a new line for the new item. But this new line is important and perhaps the README should mention it.

Problem with WHERE caluses

I take it that the following lines (in a data definition) are supposed to have identical effect.

(1) paper: FROM kuku.yaml WHERE "riku"=id

(2*) paper: FROM kuku.yaml WHERE id="riku"

(3) paper : FROM kuku.yaml WHERE id = "riku"

But while (1) and (3) work and produces the expected result, line (2*) results in the following (confusing) error message.

yst: Error parsing data field: "FROM kuku.yaml WHERE id="riku"" (line 1, column 18):
unexpected "W"
expecting space, ";", white space or end of input

Passing Pandoc Arguments to YST

Is there any way to pass Pandoc command line arguments to YST? I am particularly interested in choosing a bibtex file and a CSL. I know Hakyll and Jekyll-Pandoc both have this feature, but I quite like YST's methodology and am hoping that the feature is buried somewhere in the code that I couldn't figure out. Any help would be greatly appreciated.

&reg; entity

If I put an entity like &amp; or &nbsp; into a .st file, it ends up unchanged in the final HTML, as expected, and all is well.

If I put in &reg;, it is unexpectedly converted to the Unicode character! I haven't found a workaround yet, and have resorted to "(R)" for now.

Ubuntu 9.04, ghc 6.10.1

yst fails to build with aeson >= 2

cabal install yst fails to build, however if I use cabal install yst --constraint='aeson<2 (as mentioned here) yst builds successfully.

Error message:

Configuring executable 'yst' for yst-0.7.1.2..
Preprocessing executable 'yst' for yst-0.7.1.2..
Building executable 'yst' for yst-0.7.1.2..
[ 1 of 11] Compiling Paths_yst        ( dist/build/yst/autogen/Paths_yst.hs, dist/build/yst/yst-tmp/Paths_yst.o )
[ 2 of 11] Compiling Yst.Types        ( Yst/Types.hs, dist/build/yst/yst-tmp/Yst/Types.o )

Yst/Types.hs:127:50: error:
    • Couldn't match type ‘H.HashMap T.Text Value’
                     with ‘Data.Aeson.KeyMap.KeyMap Value’
      Expected type: Object
        Actual type: H.HashMap T.Text Value
    • In the second argument of ‘($)’, namely ‘handleMerges h’
      In the first argument of ‘fromJSON’, namely
        ‘(Object $ handleMerges h)’
      In the expression: fromJSON (Object $ handleMerges h)
    |
127 |   parseJSON (Object h) = case fromJSON (Object $ handleMerges h) of
    |                                                  ^^^^^^^^^^^^^^

Yst/Types.hs:127:63: error:
    • Couldn't match type ‘Data.Aeson.KeyMap.KeyMap Value’
                     with ‘H.HashMap T.Text Value’
      Expected type: H.HashMap T.Text Value
        Actual type: Object
    • In the first argument of ‘handleMerges’, namely ‘h’
      In the second argument of ‘($)’, namely ‘handleMerges h’
      In the first argument of ‘fromJSON’, namely
        ‘(Object $ handleMerges h)’
    |
127 |   parseJSON (Object h) = case fromJSON (Object $ handleMerges h) of
    |                                                               ^

Yst/Types.hs:142:61: error:
    • Couldn't match type ‘Data.Aeson.KeyMap.KeyMap Value’
                     with ‘H.HashMap T.Text Value’
      Expected type: H.HashMap T.Text Value
        Actual type: Object
    • In the third argument of ‘H.foldrWithKey’, namely ‘h’
      In the expression: H.foldrWithKey go m h
      In an equation for ‘go’:
          go k (Object h) m | isMerge k = H.foldrWithKey go m h
    |
142 |   where go k (Object h) m | isMerge k = H.foldrWithKey go m h
    |                                                             ^
cabal: Failed to build exe:yst from yst-0.7.1.2. See the build log above for
details.

Wrong grid table processing

Using the new grid table syntax in markdown source file, it appears that empty cells are parsed erroneously as a sequence of white spaces in a

 block. Moreover, 
tag are added at the end of each line inside a cell. For example, if the file test.txt.st contains:

+----------+-----------------+
| table    | two by two      |
+==========+=================+
|          | a simple        |
|          | paragraph       |
+----------+-----------------+

yst outputs the following html table:

</tbody

tabletwo by two
     

a simple
paragraph

wheras

pandoc test.txt.st
outputs a more natural and desired html table:

table two by two
a simple paragraph

Build fails: yst-0.7.1.3 from Cabal on MacOS -- "writeDocbook5" capitalization?

I get the following error attempting to install/build yst from Cabal:

Configuring executable 'yst' for yst-0.7.1.3..
Preprocessing executable 'yst' for yst-0.7.1.3..
Building executable 'yst' for yst-0.7.1.3..
[ 1 of 11] Compiling Paths_yst        ( dist/build/yst/autogen/Paths_yst.hs, dist/build/yst/yst-tmp/Paths_yst.o )
[ 2 of 11] Compiling Yst.Types        ( Yst/Types.hs, dist/build/yst/yst-tmp/Yst/Types.o )
[ 3 of 11] Compiling Yst.Sqlite3      ( Yst/Sqlite3.hs, dist/build/yst/yst-tmp/Yst/Sqlite3.o )
[ 4 of 11] Compiling Yst.Util         ( Yst/Util.hs, dist/build/yst/yst-tmp/Yst/Util.o )
[ 5 of 11] Compiling Yst.CSV          ( Yst/CSV.hs, dist/build/yst/yst-tmp/Yst/CSV.o )
[ 6 of 11] Compiling Yst.Yaml         ( Yst/Yaml.hs, dist/build/yst/yst-tmp/Yst/Yaml.o )
[ 7 of 11] Compiling Yst.Data         ( Yst/Data.hs, dist/build/yst/yst-tmp/Yst/Data.o )
[ 8 of 11] Compiling Yst.Render       ( Yst/Render.hs, dist/build/yst/yst-tmp/Yst/Render.o )

Yst/Render.hs:165:43: error:
    Variable not in scope:
      writeDocbook5 :: WriterOptions -> Pandoc -> m T.Text
    Suggested fix:
      Perhaps use one of these:
        ‘writeDocBook5’ (imported from Text.Pandoc),
        ‘writeDocBook4’ (imported from Text.Pandoc)
    |
165 |                    DocBookFormat       -> writeDocbook5 (wopts "docbook5")
    |                                           ^^^^^^^^^^^^^
[10 of 11] Compiling Yst.Config       ( Yst/Config.hs, dist/build/yst/yst-tmp/Yst/Config.o )
Error: cabal: Failed to build exe:yst from yst-0.7.1.3. See the build log
above for details.

Assigning to the same key multiple times

My expectation was that if a key is assigned to more than once, all values are collected and the field is treated as having multiple values. e.g:

  • name: pegasus
    genus: horse
    genus: bird

However it seems that only the last value assigned is retained. If this is the desired behavior, I think giving an error message in situation like the one above is a good idea.

HDBC sqlite3 not installing with cabal

Hei, it seems that only from few days now, HDBC-sqlite3 is not resolving using the simple cabal installation. Also all the links to the package are broken, cabal seem to have the 2.3.x package but it will not install.

Typo in readme

On unix systems, the yst binary is by default in ~/.cabal/bin not in ~\.cabal\bin

Pandoc 2.9.* compatibility

yst seems to require Pandoc ==2.8.* while 2.9.1 is already out.
This breaks the yst package on some distributions like NixOS.

could not cabal-install on Debian 5.0

When I tried to cabal install yst on Debian 5.0 It failed because of template-haskell

cabal: cannot configure template-haskell-2.4.0.1. It requires base >=4.2 && <5
For the dependency on base >=4.2 && <5 there are these packages: base-4.2.0.0
and base-4.2.0.1. However none of them are available.
base-4.2.0.0 was excluded because of the top level dependency base -any
base-4.2.0.1 was excluded because of the top level dependency base -any

I am not sure if this has anything to do with yst or wether I should be reporting this to the makers of template-haskell.

Support citations?

Pandoc supports citations using hs-citeproc. Is it possible to expose this functionality in yst easily? My first though is that it just means passing extra command-line arguments to Pandoc, but I haven't looked at the code at all.

Passing data to templates

I'm starting to work with yst, and I am encountering an issue which may well be due to my lack of understanding. But, just in case: I'm trying to create a blog using yst; so far I'm trying to make this work:

index.yaml

- url      : index.html 
  title    : Hola
  template : index.st

- Blog:
  - url      : first-post.html
    title    : First Post
    data     : 
        title   : FROM first-post.yaml
        body    : FROM first-post.yaml
    template : blog.st

  - url      : second-post.html
    title    : Second Post
    data     : 
        title   : FROM second-post.yaml
        body    : FROM second-post.yaml
    template : blog.st

blog.st

# $title$

$body$

second-post.yaml

title: Test
body:   |

    Testing, testing, testing

For some reason, this combination of files does not populate blog.st with the title and text body in second-post.yaml. Instead, it does the following strange thing:

second-post.html

<html>
<head>
   <title>My Website - Second Post</title>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
   <link rel="stylesheet" type="text/css" href="css/screen.css" />
   <link rel="stylesheet" type="text/css" media="print" href="css/print.css" />
   <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript">    </script>
   <script src="js/nav.js" type="text/javascript"></script>
</head>
<body>
  <div id="doc3" class="yui-t1">
    <div id="yui-main">
      <div id="maincol" class="yui-b">
<h1 id="body">body: [</h1>
<p>Testing, testing, testing ]title: [Test]</p>
<p>body: [ Testing, testing, testing ]title: [Test]</p>
      </div>
    </div>
    <div id="nav" class="yui-b first">
<ul class="nav"
><li
  ><a href="index.html"
    >Hola</a
    ></li
  ><li class="active"
  ><a href="#"
    >Blog &#187;</a
    ><ul class="active"
    ><li
      ><a href="first-post.html"
    >First Post</a
    ></li
      ><li class="current"
      ><a href="second-post.html"
    >Second Post</a
    ></li
      ></ul
    ></li
  ></ul
>
    </div>
   </div>
</body>
</html>

What am I missing here? Or is this a bug? Thanks

yst: Could not load template: layout.tex.st

After running a simple:

yst create wob

It creates the directory, places in test files, and then promptly complains that it cannot find the layout file that it placed in the directory (I checked, it's there.) If I remove the ".tex.st" portion, it then explodes with a different useless error message (layout.tex.st is now layout_tex.st, and the config file is properly adjusted):

yst

yst: site\april_events.tex: commitBuffer: invalid argument (invalid character)

I'm a little baffled about this; it looks like there's some kind of internal library conflicts going on; I updated cabal, cabal-install, then reinstalled pandoc, hstringtemplate and yst. Now I'm down to:

yst: site\april_events.tex: commitBuffer: invalid argument (invalid character)

from the base install. It appears to be related to UTF characters in the Haskell API, from searching it looks like a few other Haskell programs have developed this issue in recent versions of GHC.

How can one implement dynamic pages. [feature request][discussion]

In the demo example - what do we do if we need to implement an event detail page.
for each event - if we need an event detail page - do we create each page in index.yaml ?

for 1000's of events - this could be a pain area.

example for event data - we have some more fields that need to be shown on event detail page.

  • date:
    • 2009-04-20
    • 2009-04-22
      speaker:karan
      id:10
      title: Seminar on web security
      videos:
      list of attendees:

and the event detail pages will be as :

events.html/9
events.html/10
events.html/11
events.html/12

and so on.

I am not stuck on this right away, but soon this could come up to work on for my site.
so discussing ways to implement dynamic pages would be great.

maybe we add queryparam to fetch the params from the data.
and then for each param the page is generated.

Make a new kind of template available to `layout.html.st`

I'm not sure if this is possible currently, I couldn't work out how, anyway. Basically, I'd like a way to define something in index.yaml such that I can put it somewhere in the layout.html.st file. So yst defines $nav$ and $content$ based on what it reads in index.yaml. I'd like to make it such that there could be a third column, for instance. Or a sort of headline banner that runs across both nav and content and displays a different picture on each page.

Obviously, I could make it part of $content$ and then do some CSS trickery to make it appear where I want, but it seems like a neater solution would be to just place it at the right place in the layout file.

Is this currently possible? Would implementing it be nontrivial?

yst won't install on Ubuntu 18.04

Hi,

Did a clean install of Ubuntu 18.04 LTS

apt-get update 
apt-get upgrade 
apt-get install cabal-install ghc
cabal install yst 
Resolving dependencies...
Segmentation fault (core dumped)

while Resolving dependencies... all of the 16GB of my VMWare VM are beeing used ... after about 15-20min I get the Segmentation fault error

Any ideas how to get yst working?

Thanks in advance,
BR,
Thomas

installation fails on nixos

hi,

yst seems exactly like what I am looking for. I have tried installing it on 'unstable' nixos (nixos.org) with its packages generated directly from hackage. There seems to be a dependancy problem and I am not familiar with the haskell ecosystem yet (that's part of the goal). The problem might stem from nixos but I thought I would ask.

configureFlags: --verbose --prefix=/nix/store/plxh7v91lg1hfy11bbqfhlpqyjz6qqrp-yst-0.5.1.1 --libdir=$prefix/lib/$compiler --libsubdir=$pkgid --datadir=/nix/store/z2jydslfjgwp2k5abd00b21w0p78q9ja-yst-0.5.1.1-data/share/ghc-8.0.2 --docdir=/nix/store/5y64mwkd5ix2ysx79cxaksii77h6akap-yst-0.5.1.1-doc/share/doc --with-gcc=gcc --package-db=/tmp/nix-build-yst-0.5.1.1.drv-0/package.conf.d --ghc-option=-optl=-Wl,-rpath=/nix/store/plxh7v91lg1hfy11bbqfhlpqyjz6qqrp-yst-0.5.1.1/lib/ghc-8.0.2/yst-0.5.1.1 --ghc-option=-j1 --disable-split-objs --disable-library-profiling --disable-profiling --enable-shared --disable-coverage --enable-library-vanilla --enable-executable-dynamic --enable-tests --ghc-option=-split-sections Configuring yst-0.5.1.1... 
Setup: Encountered missing dependencies: 
aeson >=0.7 && <0.12,  
pandoc >=1.10 && <1.18

In nixos, only "pandoc-1.19.2.4" is available (apart from reverting to an old version).
Multiple versions seem available for aeson but I am not sure which one it chose as a dependency.

haskellPackages.aeson_0_11_3_0                               aeson-0.11.3.0
haskellPackages.aeson_0_7_0_6                                aeson-0.7.0.6
haskellPackages.aeson                                        aeson-1.1.2.0

I guess my question would be, is it possible to relax the constraints for pandoc without any problem ? the gap in aeson versioning suggest it will be harder.

Relative links break for pages in subdirectories

yst doesn't work properly when you have a page at a url in a subdirectory

- url: sub/mypage.html

because all of the relative links break. There are two possible solutions: (1) make the links in the navigation list and the js and css links absolute; (2) keep them relative, but adjust them appropriately when the page being built is in a subdirectory (perhaps by adding a $base$ attribute to the layout template and changing the function that produces the menu). A drawback of (1) is that it would require you to use a webserver (like maid) to preview the site locally.

multilevel site

At the moment it is possible to make the navigation menu with multiple levels, but the first level in a multilevel structure has no content:

- Rooms:
  - url      : room101.html
    title    : Room 101
    source   : room101.txt

  - url      : room203.html
    title    : Room 203
    source   : room203.txt

but I also need content in the first level:

- url: rooms.html
  title: Rooms
  source: rooms.txt
  - url      : room101.html
    title    : Room 101
    source   : room101.txt
  - url      : room203.html
    title    : Room 203
    source   : room203.txt

Is it possible to achieve that with yst?

thanks,

christian

Where clauses and multiple valued fields

This is probably a "feature request" not a bug report.

Should WHERE clauses work with fields that have multiple values (you refer to them as lists)? The behavior that seems to me most appropriate is one of "OR"/"ANY", that is- if any of the values in the list match the criterion, the node is selected.

Getting a 'bus error'

I am using an Apple machine with OS X Snow Leopard.

I installed yst from cabal and then also tried using the latest build on github. Both of them created the default site tree successfully using yst create mysite. However when running yst in the top level folder, they failed with bus error.

I am happy to debug the problem myself if I can get some pointers as to where to start.

On new install, using demo site, yst fails on april_events.tex

I am just starting with YST, using windows 8 (ugh i know. Because, reasons.) Anyway, I did a fresh cabal install yst, dealt with the issue of sqllite3 not being on my system, and finally got it to run.

yst create mysite: This executed fine
cd mysite
yst

The last command failed with
yst: site\april_events.tex: commitBuffer: invalid argument (invalid character)

Looking at april_events.tex, the file looks incomplete, last line is "Jim Jones, \emph{"

(PS I think it might have something to do with the unicode in that file, and in index.st)

Install fails (Windows)

After installing the Haskell Platform (HaskellPlatform-2009.2.0.2-setup.exe), and cabal update, cabal install yst, per the installation instructions,I get

cabal: Error: some packages failed to install:
HStringTemplate-0.6.2 depends on template-haskell-2.4.0.0 which failed to install.
pandoc-1.4 depends on template-haskell-2.4.0.0 which failed to install.
syb-with-class-0.6.1 depends on template-haskell-2.4.0.0 which failed to install.
template-haskell-2.4.0.0 failed during the building phase. The exception was:
exit: ExitFailure 1
yst-0.2.3 depends on template-haskell-2.4.0.0 which failed to install.

Installation fails

I am using Arch Linux with GHC 8.10.1. Running cabal install yst fails with:

Resolving dependencies...
cabal: Could not resolve dependencies:
[__0] trying: yst-0.7.1 (user goal)
[__1] trying: time-1.9.3/installed-1.9.3 (dependency of yst)
[__2] trying: deepseq-1.4.4.0/installed-1.4.4.0 (dependency of time)
[__3] trying: array-0.5.4.0/installed-0.5.4.0 (dependency of deepseq)
[__4] trying: parsec-3.1.14.0/installed-3.1.14.0 (dependency of yst)
[__5] next goal: pandoc (dependency of yst)
[__5] rejecting: pandoc-2.9.2.1 (conflict: yst => pandoc>=2.8 && <2.9)
[__5] skipping: pandoc-2.9.2, pandoc-2.9.1.1, pandoc-2.9.1, pandoc-2.9 (has
the same characteristics that caused the previous version to fail: excluded by
constraint '>=2.8 && <2.9' from 'yst')
[__5] trying: pandoc-2.8.1
[__6] trying: zlib-0.6.2.1/installed-IaKBReZRhRdBDsfrN4q94r (dependency of
pandoc)
[__7] next goal: haddock-library (dependency of pandoc)
[__7] rejecting: haddock-library-1.9.0 (conflict: pandoc =>
haddock-library>=1.8 && <1.9)
[__7] rejecting: haddock-library-1.8.0 (conflict: time =>
base==4.14.0.0/installed-4.14.0.0, haddock-library => base>=4.7 && <4.14)
[__7] rejecting: haddock-library-1.7.0 (conflict: pandoc =>
haddock-library>=1.8 && <1.9)
[__7] skipping: haddock-library-1.6.0, haddock-library-1.5.0.1,
haddock-library-1.4.5, haddock-library-1.4.4, haddock-library-1.4.3,
haddock-library-1.4.2, haddock-library-1.4.1, haddock-library-1.2.1,
haddock-library-1.2.0, haddock-library-1.1.1, haddock-library-1.1.0,
haddock-library-1.0.1, haddock-library-1.0.0, haddock-library-1.6.1 (has the
same characteristics that caused the previous version to fail: excluded by
constraint '>=1.8 && <1.9' from 'pandoc')
[__7] fail (backjumping, conflict set: haddock-library, pandoc, time)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: base, pandoc, haddock-library,
HStringTemplate, time, yst, deepseq, array, pandoc:setup.Cabal, zlib, parsec
Try running with --minimize-conflict-set to improve the error message

Running with --minimize-conflict-set gives

Resolving dependencies...
cabal: Could not resolve dependencies:
[__0] trying: yst-0.7.1 (user goal)
[__1] next goal: pandoc (dependency of yst)
[__1] rejecting: pandoc-2.9.2.1 (conflict: yst => pandoc>=2.8 && <2.9)
[__1] skipping: pandoc-2.9.2, pandoc-2.9.1.1, pandoc-2.9.1, pandoc-2.9 (has
the same characteristics that caused the previous version to fail: excluded by
constraint '>=2.8 && <2.9' from 'yst')
[__1] trying: pandoc-2.8.1
[__2] next goal: haddock-library (dependency of pandoc)
[__2] rejecting: haddock-library-1.9.0 (conflict: pandoc =>
haddock-library>=1.8 && <1.9)
[__2] trying: haddock-library-1.8.0
[__3] next goal: base (dependency of yst)
[__3] rejecting: base-4.14.0.0/installed-4.14.0.0 (conflict: haddock-library
=> base>=4.7 && <4.14)
[__3] skipping: base-4.14.0.0 (has the same characteristics that caused the
previous version to fail: excluded by constraint '>=4.7 && <4.14' from
'haddock-library')
[__3] rejecting: base-4.13.0.0, base-4.12.0.0, base-4.11.1.0, base-4.11.0.0,
base-4.10.1.0, base-4.10.0.0, base-4.9.1.0, base-4.9.0.0, base-4.8.2.0,
base-4.8.1.0, base-4.8.0.0, base-4.7.0.2, base-4.7.0.1, base-4.7.0.0,
base-4.6.0.1, base-4.6.0.0, base-4.5.1.0, base-4.5.0.0, base-4.4.1.0,
base-4.4.0.0, base-4.3.1.0, base-4.3.0.0, base-4.2.0.2, base-4.2.0.1,
base-4.2.0.0, base-4.1.0.0, base-4.0.0.0, base-3.0.3.2, base-3.0.3.1
(constraint from non-upgradeable package requires installed instance)
[__3] fail (backjumping, conflict set: base, haddock-library, yst)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: pandoc, pandoc:setup.Cabal, yst, base,
haddock-library

Allow "plain" output format

Currently, it is not possible to get a completely plain txt output.

If I specify a layout with *.txt.st or *.markdown.st extension, it is equivalent
pandoc -t markdown

I think that it will be useful if *.txt.st is treated as
pandoc -t plain

yst.cabal is out of date, as it's no longer possible to install via "cabal install yst".

Unfortunately, I don't know much about Haskell to help with this, but I figured it'd be good idea to give a heads up.

$ cabal install yst
Resolving dependencies...
cabal: Could not resolve dependencies:
trying: yst-0.4.1.1 (user goal)
trying: HDBC-sqlite3-2.3.3.0 (dependency of yst-0.4.1.1)
trying: mtl-2.1.3.1/installed-96f... (dependency of HDBC-sqlite3-2.3.3.0)
trying: pandoc-1.13.2 (dependency of yst-0.4.1.1)
trying: temporary-1.2.0.3 (dependency of pandoc-1.13.2)
trying: exceptions-0.8 (dependency of temporary-1.2.0.3)
trying: transformers-compat-0.4.0.4 (dependency of exceptions-0.8)
trying: transformers-compat-0.4.0.4:-two
rejecting: transformers-compat-0.4.0.4:-three (conflict: mtl =>
transformers==0.3.0.0/installed-645..., transformers-compat-0.4.0.4:three =>
transformers>=0.4.1 && <0.5)
rejecting: transformers-compat-0.4.0.4:+three (manual flag can only be changed
explicitly)
Backjump limit reached (change with --max-backjumps).

$root$ in all templates

You have implemented $root$ for the layout.html.st. Can you pls also implement that for all other templates? I need it for files, that I reference multiple times in different subdirectories.

thx,

christian

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.