tributary 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.rspec +6 -0
- data/LICENCE +661 -0
- data/README.md +99 -0
- data/Rakefile +5 -0
- data/config.ru +9 -0
- data/lib/tributary/app.rb +61 -0
- data/lib/tributary/item.rb +66 -0
- data/lib/tributary/plugins/dummy.rb +7 -0
- data/lib/tributary/plugins/mnml.rb +14 -0
- data/lib/tributary/plugins/unbreak_my_art.rb +22 -0
- data/lib/tributary/stream.rb +51 -0
- data/lib/tributary.rb +8 -0
- data/spec/fixtures/index.en.en+pl.xml +50 -0
- data/spec/fixtures/index.en.en.xml +50 -0
- data/spec/fixtures/index.en.xml +50 -0
- data/spec/fixtures/index.pl.pl.xml +50 -0
- data/spec/fixtures/index.pl.xml +50 -0
- data/spec/fixtures/index.xml +50 -0
- data/spec/fixtures/layout.css +22 -0
- data/spec/fixtures/pages.css +2 -0
- data/spec/site/articles/600.en.md +5 -0
- data/spec/site/articles/600.md +5 -0
- data/spec/site/articles/bilingual.en.md +4 -0
- data/spec/site/articles/bilingual.pl.md +4 -0
- data/spec/site/articles/unix-millennium-bug.en.md +4 -0
- data/spec/site/articles/welcome.md +4 -0
- data/spec/site/beeps/beep.md +3 -0
- data/spec/site/beeps/dated.md +3 -0
- data/spec/site/beeps/english.en.md +3 -0
- data/spec/site/beeps/link.md +3 -0
- data/spec/site/beeps/polish.pl.md +3 -0
- data/spec/site/beeps/quote.md +4 -0
- data/spec/site/i18n/en.yml +12 -0
- data/spec/site/i18n/pl.yml +12 -0
- data/spec/site/pages/about.md +5 -0
- data/spec/site/views/articles.haml +4 -0
- data/spec/site/views/articles.index.haml +6 -0
- data/spec/site/views/articles.index.sass +0 -0
- data/spec/site/views/articles.sass +2 -0
- data/spec/site/views/beeps.haml +1 -0
- data/spec/site/views/beeps.sass +2 -0
- data/spec/site/views/error.haml +8 -0
- data/spec/site/views/error.sass +6 -0
- data/spec/site/views/index.haml +6 -0
- data/spec/site/views/index.sass +2 -0
- data/spec/site/views/index.xml.haml +17 -0
- data/spec/site/views/layout.haml +56 -0
- data/spec/site/views/layout.sass +22 -0
- data/spec/site/views/pages.haml +3 -0
- data/spec/site/views/pages.sass +2 -0
- data/spec/tributary/app_spec.rb +266 -0
- data/spec/tributary/item_spec.rb +129 -0
- data/spec/tributary/plugins/dummy_spec.rb +12 -0
- data/spec/tributary/plugins/mnml_spec.rb +16 -0
- data/spec/tributary/plugins/unbreak_my_art_spec.rb +36 -0
- data/spec/tributary/stream_spec.rb +155 -0
- data/tributary.gemspec +18 -0
- metadata +204 -0
data/README.md
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
tributary
|
2
|
+
=========
|
3
|
+
|
4
|
+
A tiny, heavily [toto](http://cloudhead.io/toto)-inspired and (no less heavily) [Sinatra](http://www.sinatrarb.com/)-powered blogging engine.
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
Overview
|
9
|
+
--------
|
10
|
+
|
11
|
+
tributary aggregates a set of `Item`s, representing individual website contents (blog posts, photolog entries, standalone pages, etc.) stored in YAML-enhanced Markdown files, and allows accessing them with a simple 1:1 URL-to-filename mapping. All `Item`s with a publication date are combined into a `Stream`, which can be interated over (to, e.g., display the seven most recent `Item`s, or all photos) or navigated from inside (to get the `Item` that’s previous/subsequent to the current one).
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
Items
|
16
|
+
-----
|
17
|
+
|
18
|
+
An `Item` is represented in the filesystem in the form of text file with a Markdown body and a YAML header:
|
19
|
+
|
20
|
+
date: 2010-07-15
|
21
|
+
title: welcome to tributary
|
22
|
+
|
23
|
+
tributary _welcome_ article
|
24
|
+
|
25
|
+
The above example, if stored as `articles/welcome.md`, will be seen in tributary as an `Item` object with `Item#body` returning the kramdown-generated `<p>tributary <em>welcome</em> article</p>\n`, `Item#title` and `Item#date` returning YAML-parsed `welcome to tributary` and `2010-07-15 00:00:00 +0200`, while `Item#type` and `Item#path` will be inherited from the filesystem location and return `:articles` and `welcome`, respectively.
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
Item types
|
30
|
+
----------
|
31
|
+
|
32
|
+
Every `Item` has a type, inherited from the `Item`’s position in the filesystem and returned by `Item#type`. When a given `Item` is requested over HTTP (via its `Item#path`) the view associated with its type is rendered; this allows rendering different HTML/CSS layouts for different content types (‘static’ pages vs blog posts vs photolog entries, for example).
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
Views
|
37
|
+
-----
|
38
|
+
|
39
|
+
As mentioned above, every `Item` has an associated type, and this type defines the HTML view displayed when the given `Item` is requested; this allows for different rendering of e.g. static pages vs photolog entries. The views are written in [Haml](http://haml-lang.com/) and are located in `views/*.haml` files, with the file’s basename equal to the `Item`’s type.
|
40
|
+
|
41
|
+
Additionally, for every type the URL with that type’s name can be accessed (for example `http://…/pages`, assuming at least in one case `Item#type` returns `:pages`). In this case, the relevant `views/*.index.haml` Haml view is rendered (so `views/pages.index.haml` in the aforementioned example). These views can be used to create custom category-like pages – e.g., a page indexing all of your photographs that renders their thumbnails.
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
Stream
|
46
|
+
------
|
47
|
+
|
48
|
+
The `Stream` object contains all tributary `Item`s ordered by their publication date (if present) and can be queried to return a given number of the most recent `Item`s or an `Item` previous of (or subsequent to) a given `Item` (the returned `Item`(s) take into account the current `locale` and `lang_limit` settings). Every such query can additionally filter the `Stream` and for example request the subsequent `Item` that is also a photolog entry.
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
Multilingual support
|
53
|
+
--------------------
|
54
|
+
|
55
|
+
There are two session variables governing the user’s language preferences: `locale` and `lang_limit`. The first sets the user’s preferred language (and, for example, allows for a localised user interface), while the second limits the contents returned from the `Stream`.
|
56
|
+
|
57
|
+
Every `Item` can have multiple language versions (stored in `<type>/<path>.*.md` files, where `*` maps to the relevant locale) and/or a language-agnostic version (stored in the `<type>/<path>.md` file). When a given `Item` is requested (via the `http://…/<path>` URL) tributary chooses the language version most suitable for the request, based on either an explicit `locale` cookie sent along with the request or the `Accept-Language` HTTP header. If the preferred language version is not available, tributary falls back to the language-agnostic version or (if there’s no such version) to a language version that’s not explicitely filtered out by the `lang_limit` setting.
|
58
|
+
|
59
|
+
The site’s interface can be multilingualised using [R18n](http://r18n.rubyforge.org/) (via [R18n for Sinatra](http://r18n.rubyforge.org/sinatra.html)). The `t` object (available in views) can be sent messages like `t.recent_items`, which are translated to the relevant localised strings based on YAML entries in `i18n/*.yml` files (where `*` maps to the current user’s `locale`). The example `i18n/en.yml` file (in the `spec/site` directory) contains
|
60
|
+
|
61
|
+
recent_items: recent items
|
62
|
+
|
63
|
+
while the example `i18n/pl.yml` file contains
|
64
|
+
|
65
|
+
recent_items: najnowsze
|
66
|
+
|
67
|
+
– and so the `views/index.haml` view used by the spec site can call `t.recent_items` to get a properly localised string (note that `Tributary::App` already registers `Sinatra::R18n` and exposes `locale` to the session, while also setting the `locale` to either the user’s preference, their browser configuration’s default or English, so there’s nothing more that needs to be done).
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
Configuration
|
72
|
+
-------------
|
73
|
+
|
74
|
+
Application-level configuration is stored right on the `App` object itself; see the example `config.ru`, which happens to serve the site used by specs:
|
75
|
+
|
76
|
+
Tributary::App.configure do |config|
|
77
|
+
config.set :author, 'Ary Tribut'
|
78
|
+
config.set :root, 'spec/site'
|
79
|
+
config.set :sitename, 'a tributary site'
|
80
|
+
end
|
81
|
+
|
82
|
+
User-level configuration is also stored on the `App` object and can be operated on by visiting the `/set?option=value` URLs – for example, setting the `locale` to English and `lang_limit` to English and Polish can be done by visiting the `/set?locale=en&lang_limit=en+pl` URL.
|
83
|
+
|
84
|
+
The `user_prefs` config option contains a list of settings that can be altered by visiting `/set` (and defaults to `[:lang_limit, :locale]`) – changing this option (by setting it as above in `config.ru`, for example) allows the users to alter other (e.g., nonexistent by default) settings and see the changes reflected on the `App` object.
|
85
|
+
|
86
|
+
The settings altered by the user are kept in the given user’s session and so persist between requests and visits.
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
Plugins
|
91
|
+
-------
|
92
|
+
|
93
|
+
Plugins (put in the `App.plugins` `Array`) are objects which can be sent a `handle` method with an `Item` as a parameter and are expected to return the `Item` (so the calls to subsequent plugins are chainable). See the `Mnml` plugin for an example implementation utilising a `SimpleDelegator` to filter the given `Item`’s `body` and `title` methods.
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
---
|
98
|
+
|
99
|
+
© MMX Piotr Szotkowski <chastell@chastell.net>, licensed under AGPL 3 (see LICENCE)
|
data/Rakefile
ADDED
data/config.ru
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module Tributary class App < Sinatra::Base
|
2
|
+
|
3
|
+
register Sinatra::R18n
|
4
|
+
|
5
|
+
use Rack::Session::Cookie, expire_after: 60 * 60 * 24 * 365 * 7
|
6
|
+
|
7
|
+
def self.configure *args, &block
|
8
|
+
set :cache?, production?
|
9
|
+
set :lang_limit, nil
|
10
|
+
set :locale, nil
|
11
|
+
set :plugins, []
|
12
|
+
set :user_prefs, [:lang_limit, :locale]
|
13
|
+
super
|
14
|
+
set :stream, cache? ? Tributary::Stream.new : nil
|
15
|
+
end
|
16
|
+
|
17
|
+
before do
|
18
|
+
Tributary::App.locale = session[:locale]
|
19
|
+
Tributary::App.lang_limit = session[:lang_limit] && session[:lang_limit].split
|
20
|
+
@stream = Tributary::App.stream || Tributary::Stream.new
|
21
|
+
end
|
22
|
+
|
23
|
+
get '/' do
|
24
|
+
@item = OpenStruct.new type: :index
|
25
|
+
haml @item.type
|
26
|
+
end
|
27
|
+
|
28
|
+
get '/set' do
|
29
|
+
params.each { |key, value| session[key.to_sym] = value if App.user_prefs.map(&:to_s).include? key }
|
30
|
+
redirect request.referer
|
31
|
+
end
|
32
|
+
|
33
|
+
get '/:feed.xml' do |feed|
|
34
|
+
content_type 'application/atom+xml'
|
35
|
+
feed, App.locale, lang_limit = feed.split '.'
|
36
|
+
App.lang_limit = lang_limit.split if lang_limit
|
37
|
+
File.exists?("#{App.views}/#{feed}.xml.haml") ? haml("#{feed}.xml".to_sym, layout: false) : 404
|
38
|
+
end
|
39
|
+
|
40
|
+
get '/:style.css' do |style|
|
41
|
+
content_type 'text/css'
|
42
|
+
File.exists?("#{App.views}/#{style}.sass") ? sass(style.to_sym) : 404
|
43
|
+
end
|
44
|
+
|
45
|
+
get '/:path' do |path|
|
46
|
+
if @stream.types.map(&:to_s).include? path
|
47
|
+
@item = OpenStruct.new path: path, type: "#{path}.index".to_sym
|
48
|
+
else
|
49
|
+
@item = @stream.pick_item path
|
50
|
+
end
|
51
|
+
@item ? haml(@item.type) : 404
|
52
|
+
end
|
53
|
+
|
54
|
+
error 400...600 do
|
55
|
+
unless response.content_type
|
56
|
+
@item = OpenStruct.new type: :error
|
57
|
+
haml @item.type
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Tributary class Item < OpenStruct
|
4
|
+
|
5
|
+
def initialize file
|
6
|
+
@file = file
|
7
|
+
yaml, @body = File.read(@file).split "\n\n", 2
|
8
|
+
super YAML.load yaml
|
9
|
+
end
|
10
|
+
|
11
|
+
def <=> other
|
12
|
+
case
|
13
|
+
when other.date && date then other.date <=> date
|
14
|
+
when date then -1
|
15
|
+
when other.date then 1
|
16
|
+
else 0
|
17
|
+
end.nonzero? or
|
18
|
+
(other.path <=> path).nonzero? or
|
19
|
+
case
|
20
|
+
when lang == App.locale then -1
|
21
|
+
when other.lang == App.locale then 1
|
22
|
+
when lang.nil? then -1
|
23
|
+
when other.lang.nil? then 1
|
24
|
+
else lang <=> other.lang
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def body
|
29
|
+
Kramdown::Document.new(@body).to_html
|
30
|
+
end
|
31
|
+
|
32
|
+
def date
|
33
|
+
@date ||= case @table[:date]
|
34
|
+
when Date then @table[:date].to_time
|
35
|
+
when String then Time.parse @table[:date]
|
36
|
+
when Time then @table[:date]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
alias eql? ==
|
41
|
+
|
42
|
+
def hash
|
43
|
+
@file.hash
|
44
|
+
end
|
45
|
+
|
46
|
+
def lang
|
47
|
+
File.basename(@file, '.md').split('.')[1]
|
48
|
+
end
|
49
|
+
|
50
|
+
def path
|
51
|
+
@path ||= File.basename(@file, '.md').split('.').first
|
52
|
+
end
|
53
|
+
|
54
|
+
def published?
|
55
|
+
date and date < Time.now
|
56
|
+
end
|
57
|
+
|
58
|
+
def title
|
59
|
+
@table[:title] or @body.scan(/\p{L}+/).first + '…'
|
60
|
+
end
|
61
|
+
|
62
|
+
def type
|
63
|
+
File.dirname(@file).split('/').last.to_sym
|
64
|
+
end
|
65
|
+
|
66
|
+
end end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Tributary module Plugins class UnbreakMyArt
|
4
|
+
|
5
|
+
def handle item
|
6
|
+
unbroken = SimpleDelegator.new item
|
7
|
+
def unbroken.body
|
8
|
+
Plugins::UnbreakMyArt.unbreak super
|
9
|
+
end
|
10
|
+
def unbroken.title
|
11
|
+
Plugins::UnbreakMyArt.unbreak super
|
12
|
+
end
|
13
|
+
unbroken
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def self.unbreak string
|
19
|
+
string.gsub /((^|[^\p{L}<])\p{L}\p{P}?) /, '\1 '
|
20
|
+
end
|
21
|
+
|
22
|
+
end end end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Tributary class Stream
|
2
|
+
|
3
|
+
def initialize root = App.root, plugins = App.plugins
|
4
|
+
@items = Dir["#{root}/*/*.md"].map { |file| Item.new file }
|
5
|
+
plugins.each do |plugin|
|
6
|
+
@items.map! { |item| plugin.handle item }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def langs
|
11
|
+
@items.map(&:lang).uniq.compact.sort
|
12
|
+
end
|
13
|
+
|
14
|
+
def pick_item path
|
15
|
+
path, lang = path.split '.'
|
16
|
+
(lang ? @items.select { |item| item.lang == lang } : @items).sort.find { |item| item.path == path }
|
17
|
+
end
|
18
|
+
|
19
|
+
def previous item, filter = {}
|
20
|
+
published(filter)[published(filter).index { |i| i.path == item.path } + 1] rescue nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def recent limit = nil, filter = {}
|
24
|
+
published(filter).take limit || @items.size
|
25
|
+
end
|
26
|
+
|
27
|
+
def subsequent item, filter = {}
|
28
|
+
published(filter).reverse[published(filter).reverse.index { |i| i.path == item.path } + 1] rescue nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def types
|
32
|
+
@items.map(&:type).uniq.sort
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def items_ltd filter = {}
|
38
|
+
items_ltd = @items.sort
|
39
|
+
items_ltd.delete_if { |item| item.lang and not App.lang_limit.include? item.lang } if App.lang_limit and not App.lang_limit.empty?
|
40
|
+
filter.each do |method, value|
|
41
|
+
items_ltd = items_ltd.select { |item| item.send(method) == value }
|
42
|
+
end
|
43
|
+
items_ltd.select { |item| item == items_ltd.find { |i| i.path == item.path } }
|
44
|
+
end
|
45
|
+
|
46
|
+
def published filter = {}
|
47
|
+
@published ||= {}
|
48
|
+
@published[[App.lang_limit, App.locale, filter]] ||= items_ltd({published?: true}.merge filter)
|
49
|
+
end
|
50
|
+
|
51
|
+
end end
|
data/lib/tributary.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
<?xml version='1.0' encoding='utf-8' ?>
|
2
|
+
<feed xmlns='http://www.w3.org/2005/Atom'>
|
3
|
+
<author>
|
4
|
+
<name>Ary Tribut</name>
|
5
|
+
</author>
|
6
|
+
<generator uri='http://github.com/chastell/tributary'>tributary</generator>
|
7
|
+
<id>http://example.org/</id>
|
8
|
+
<link href='http://example.org/' rel='alternate' />
|
9
|
+
<link href='http://example.org/index.en.en+pl.xml' rel='self' />
|
10
|
+
<title>a tributary site</title>
|
11
|
+
<updated>2010-07-23T02:00:00+02:00</updated>
|
12
|
+
<entry>
|
13
|
+
<id>http://example.org/polish</id>
|
14
|
+
<link href='http://example.org/polish' rel='alternate' />
|
15
|
+
<title>ten…</title>
|
16
|
+
<updated>2010-07-23T02:00:00+02:00</updated>
|
17
|
+
<content type='html'><p>ten beep jest tylko po polsku.</p></content>
|
18
|
+
</entry>
|
19
|
+
<entry>
|
20
|
+
<id>http://example.org/english</id>
|
21
|
+
<link href='http://example.org/english' rel='alternate' />
|
22
|
+
<title>this…</title>
|
23
|
+
<updated>2010-07-23T01:00:00+02:00</updated>
|
24
|
+
<content type='html'><p>this beep is only in English.</p></content>
|
25
|
+
</entry>
|
26
|
+
<entry>
|
27
|
+
<id>http://example.org/600</id>
|
28
|
+
<link href='http://example.org/600' rel='alternate' />
|
29
|
+
<title>600th anniversary (English)</title>
|
30
|
+
<updated>2010-07-15T12:00:00+02:00</updated>
|
31
|
+
<content type='html'>
|
32
|
+
<p>600 years ago <a href="http://en.wikipedia.org/wiki/Battle_of_Grunwald">something supposedly important</a>
|
33
|
+
happened around these parts of the world</p>
|
34
|
+
</content>
|
35
|
+
</entry>
|
36
|
+
<entry>
|
37
|
+
<id>http://example.org/bilingual</id>
|
38
|
+
<link href='http://example.org/bilingual' rel='alternate' />
|
39
|
+
<title>bilinguality</title>
|
40
|
+
<updated>2010-07-15T06:00:00+02:00</updated>
|
41
|
+
<content type='html'><p>this article is also available <a href="bilingual.pl">in Polish</a></p></content>
|
42
|
+
</entry>
|
43
|
+
<entry>
|
44
|
+
<id>http://example.org/dated</id>
|
45
|
+
<link href='http://example.org/dated' rel='alternate' />
|
46
|
+
<title>a…</title>
|
47
|
+
<updated>2010-07-15T03:00:00+02:00</updated>
|
48
|
+
<content type='html'><p>a dated beep.</p></content>
|
49
|
+
</entry>
|
50
|
+
</feed>
|
@@ -0,0 +1,50 @@
|
|
1
|
+
<?xml version='1.0' encoding='utf-8' ?>
|
2
|
+
<feed xmlns='http://www.w3.org/2005/Atom'>
|
3
|
+
<author>
|
4
|
+
<name>Ary Tribut</name>
|
5
|
+
</author>
|
6
|
+
<generator uri='http://github.com/chastell/tributary'>tributary</generator>
|
7
|
+
<id>http://example.org/</id>
|
8
|
+
<link href='http://example.org/' rel='alternate' />
|
9
|
+
<link href='http://example.org/index.en.en.xml' rel='self' />
|
10
|
+
<title>a tributary site</title>
|
11
|
+
<updated>2010-07-23T01:00:00+02:00</updated>
|
12
|
+
<entry>
|
13
|
+
<id>http://example.org/english</id>
|
14
|
+
<link href='http://example.org/english' rel='alternate' />
|
15
|
+
<title>this…</title>
|
16
|
+
<updated>2010-07-23T01:00:00+02:00</updated>
|
17
|
+
<content type='html'><p>this beep is only in English.</p></content>
|
18
|
+
</entry>
|
19
|
+
<entry>
|
20
|
+
<id>http://example.org/600</id>
|
21
|
+
<link href='http://example.org/600' rel='alternate' />
|
22
|
+
<title>600th anniversary (English)</title>
|
23
|
+
<updated>2010-07-15T12:00:00+02:00</updated>
|
24
|
+
<content type='html'>
|
25
|
+
<p>600 years ago <a href="http://en.wikipedia.org/wiki/Battle_of_Grunwald">something supposedly important</a>
|
26
|
+
happened around these parts of the world</p>
|
27
|
+
</content>
|
28
|
+
</entry>
|
29
|
+
<entry>
|
30
|
+
<id>http://example.org/bilingual</id>
|
31
|
+
<link href='http://example.org/bilingual' rel='alternate' />
|
32
|
+
<title>bilinguality</title>
|
33
|
+
<updated>2010-07-15T06:00:00+02:00</updated>
|
34
|
+
<content type='html'><p>this article is also available <a href="bilingual.pl">in Polish</a></p></content>
|
35
|
+
</entry>
|
36
|
+
<entry>
|
37
|
+
<id>http://example.org/dated</id>
|
38
|
+
<link href='http://example.org/dated' rel='alternate' />
|
39
|
+
<title>a…</title>
|
40
|
+
<updated>2010-07-15T03:00:00+02:00</updated>
|
41
|
+
<content type='html'><p>a dated beep.</p></content>
|
42
|
+
</entry>
|
43
|
+
<entry>
|
44
|
+
<id>http://example.org/welcome</id>
|
45
|
+
<link href='http://example.org/welcome' rel='alternate' />
|
46
|
+
<title>welcome to tributary</title>
|
47
|
+
<updated>2010-07-15T00:00:00+02:00</updated>
|
48
|
+
<content type='html'><p>tributary <em>welcome</em> article</p></content>
|
49
|
+
</entry>
|
50
|
+
</feed>
|
@@ -0,0 +1,50 @@
|
|
1
|
+
<?xml version='1.0' encoding='utf-8' ?>
|
2
|
+
<feed xmlns='http://www.w3.org/2005/Atom'>
|
3
|
+
<author>
|
4
|
+
<name>Ary Tribut</name>
|
5
|
+
</author>
|
6
|
+
<generator uri='http://github.com/chastell/tributary'>tributary</generator>
|
7
|
+
<id>http://example.org/</id>
|
8
|
+
<link href='http://example.org/' rel='alternate' />
|
9
|
+
<link href='http://example.org/index.en.xml' rel='self' />
|
10
|
+
<title>a tributary site</title>
|
11
|
+
<updated>2010-07-23T02:00:00+02:00</updated>
|
12
|
+
<entry>
|
13
|
+
<id>http://example.org/polish</id>
|
14
|
+
<link href='http://example.org/polish' rel='alternate' />
|
15
|
+
<title>ten…</title>
|
16
|
+
<updated>2010-07-23T02:00:00+02:00</updated>
|
17
|
+
<content type='html'><p>ten beep jest tylko po polsku.</p></content>
|
18
|
+
</entry>
|
19
|
+
<entry>
|
20
|
+
<id>http://example.org/english</id>
|
21
|
+
<link href='http://example.org/english' rel='alternate' />
|
22
|
+
<title>this…</title>
|
23
|
+
<updated>2010-07-23T01:00:00+02:00</updated>
|
24
|
+
<content type='html'><p>this beep is only in English.</p></content>
|
25
|
+
</entry>
|
26
|
+
<entry>
|
27
|
+
<id>http://example.org/600</id>
|
28
|
+
<link href='http://example.org/600' rel='alternate' />
|
29
|
+
<title>600th anniversary (English)</title>
|
30
|
+
<updated>2010-07-15T12:00:00+02:00</updated>
|
31
|
+
<content type='html'>
|
32
|
+
<p>600 years ago <a href="http://en.wikipedia.org/wiki/Battle_of_Grunwald">something supposedly important</a>
|
33
|
+
happened around these parts of the world</p>
|
34
|
+
</content>
|
35
|
+
</entry>
|
36
|
+
<entry>
|
37
|
+
<id>http://example.org/bilingual</id>
|
38
|
+
<link href='http://example.org/bilingual' rel='alternate' />
|
39
|
+
<title>bilinguality</title>
|
40
|
+
<updated>2010-07-15T06:00:00+02:00</updated>
|
41
|
+
<content type='html'><p>this article is also available <a href="bilingual.pl">in Polish</a></p></content>
|
42
|
+
</entry>
|
43
|
+
<entry>
|
44
|
+
<id>http://example.org/dated</id>
|
45
|
+
<link href='http://example.org/dated' rel='alternate' />
|
46
|
+
<title>a…</title>
|
47
|
+
<updated>2010-07-15T03:00:00+02:00</updated>
|
48
|
+
<content type='html'><p>a dated beep.</p></content>
|
49
|
+
</entry>
|
50
|
+
</feed>
|
@@ -0,0 +1,50 @@
|
|
1
|
+
<?xml version='1.0' encoding='utf-8' ?>
|
2
|
+
<feed xmlns='http://www.w3.org/2005/Atom'>
|
3
|
+
<author>
|
4
|
+
<name>Ary Tribut</name>
|
5
|
+
</author>
|
6
|
+
<generator uri='http://github.com/chastell/tributary'>tributary</generator>
|
7
|
+
<id>http://example.org/</id>
|
8
|
+
<link href='http://example.org/' rel='alternate' />
|
9
|
+
<link href='http://example.org/index.pl.pl.xml' rel='self' />
|
10
|
+
<title>a tributary site</title>
|
11
|
+
<updated>2010-07-23T02:00:00+02:00</updated>
|
12
|
+
<entry>
|
13
|
+
<id>http://example.org/polish</id>
|
14
|
+
<link href='http://example.org/polish' rel='alternate' />
|
15
|
+
<title>ten…</title>
|
16
|
+
<updated>2010-07-23T02:00:00+02:00</updated>
|
17
|
+
<content type='html'><p>ten beep jest tylko po polsku.</p></content>
|
18
|
+
</entry>
|
19
|
+
<entry>
|
20
|
+
<id>http://example.org/600</id>
|
21
|
+
<link href='http://example.org/600' rel='alternate' />
|
22
|
+
<title>600th anniversary (intl.)</title>
|
23
|
+
<updated>2010-07-15T12:00:00+02:00</updated>
|
24
|
+
<content type='html'>
|
25
|
+
<p>600 years ago <a href="http://en.wikipedia.org/wiki/Battle_of_Grunwald">something supposedly important</a>
|
26
|
+
happened around these parts of the world</p>
|
27
|
+
</content>
|
28
|
+
</entry>
|
29
|
+
<entry>
|
30
|
+
<id>http://example.org/bilingual</id>
|
31
|
+
<link href='http://example.org/bilingual' rel='alternate' />
|
32
|
+
<title>dwujęzyczność</title>
|
33
|
+
<updated>2010-07-15T06:00:00+02:00</updated>
|
34
|
+
<content type='html'><p>ten wpis jest także dostępny <a href="bilingual.en">po angielsku</a></p></content>
|
35
|
+
</entry>
|
36
|
+
<entry>
|
37
|
+
<id>http://example.org/dated</id>
|
38
|
+
<link href='http://example.org/dated' rel='alternate' />
|
39
|
+
<title>a…</title>
|
40
|
+
<updated>2010-07-15T03:00:00+02:00</updated>
|
41
|
+
<content type='html'><p>a dated beep.</p></content>
|
42
|
+
</entry>
|
43
|
+
<entry>
|
44
|
+
<id>http://example.org/welcome</id>
|
45
|
+
<link href='http://example.org/welcome' rel='alternate' />
|
46
|
+
<title>welcome to tributary</title>
|
47
|
+
<updated>2010-07-15T00:00:00+02:00</updated>
|
48
|
+
<content type='html'><p>tributary <em>welcome</em> article</p></content>
|
49
|
+
</entry>
|
50
|
+
</feed>
|
@@ -0,0 +1,50 @@
|
|
1
|
+
<?xml version='1.0' encoding='utf-8' ?>
|
2
|
+
<feed xmlns='http://www.w3.org/2005/Atom'>
|
3
|
+
<author>
|
4
|
+
<name>Ary Tribut</name>
|
5
|
+
</author>
|
6
|
+
<generator uri='http://github.com/chastell/tributary'>tributary</generator>
|
7
|
+
<id>http://example.org/</id>
|
8
|
+
<link href='http://example.org/' rel='alternate' />
|
9
|
+
<link href='http://example.org/index.pl.xml' rel='self' />
|
10
|
+
<title>a tributary site</title>
|
11
|
+
<updated>2010-07-23T02:00:00+02:00</updated>
|
12
|
+
<entry>
|
13
|
+
<id>http://example.org/polish</id>
|
14
|
+
<link href='http://example.org/polish' rel='alternate' />
|
15
|
+
<title>ten…</title>
|
16
|
+
<updated>2010-07-23T02:00:00+02:00</updated>
|
17
|
+
<content type='html'><p>ten beep jest tylko po polsku.</p></content>
|
18
|
+
</entry>
|
19
|
+
<entry>
|
20
|
+
<id>http://example.org/english</id>
|
21
|
+
<link href='http://example.org/english' rel='alternate' />
|
22
|
+
<title>this…</title>
|
23
|
+
<updated>2010-07-23T01:00:00+02:00</updated>
|
24
|
+
<content type='html'><p>this beep is only in English.</p></content>
|
25
|
+
</entry>
|
26
|
+
<entry>
|
27
|
+
<id>http://example.org/600</id>
|
28
|
+
<link href='http://example.org/600' rel='alternate' />
|
29
|
+
<title>600th anniversary (intl.)</title>
|
30
|
+
<updated>2010-07-15T12:00:00+02:00</updated>
|
31
|
+
<content type='html'>
|
32
|
+
<p>600 years ago <a href="http://en.wikipedia.org/wiki/Battle_of_Grunwald">something supposedly important</a>
|
33
|
+
happened around these parts of the world</p>
|
34
|
+
</content>
|
35
|
+
</entry>
|
36
|
+
<entry>
|
37
|
+
<id>http://example.org/bilingual</id>
|
38
|
+
<link href='http://example.org/bilingual' rel='alternate' />
|
39
|
+
<title>dwujęzyczność</title>
|
40
|
+
<updated>2010-07-15T06:00:00+02:00</updated>
|
41
|
+
<content type='html'><p>ten wpis jest także dostępny <a href="bilingual.en">po angielsku</a></p></content>
|
42
|
+
</entry>
|
43
|
+
<entry>
|
44
|
+
<id>http://example.org/dated</id>
|
45
|
+
<link href='http://example.org/dated' rel='alternate' />
|
46
|
+
<title>a…</title>
|
47
|
+
<updated>2010-07-15T03:00:00+02:00</updated>
|
48
|
+
<content type='html'><p>a dated beep.</p></content>
|
49
|
+
</entry>
|
50
|
+
</feed>
|
@@ -0,0 +1,50 @@
|
|
1
|
+
<?xml version='1.0' encoding='utf-8' ?>
|
2
|
+
<feed xmlns='http://www.w3.org/2005/Atom'>
|
3
|
+
<author>
|
4
|
+
<name>Ary Tribut</name>
|
5
|
+
</author>
|
6
|
+
<generator uri='http://github.com/chastell/tributary'>tributary</generator>
|
7
|
+
<id>http://example.org/</id>
|
8
|
+
<link href='http://example.org/' rel='alternate' />
|
9
|
+
<link href='http://example.org/index.xml' rel='self' />
|
10
|
+
<title>a tributary site</title>
|
11
|
+
<updated>2010-07-23T02:00:00+02:00</updated>
|
12
|
+
<entry>
|
13
|
+
<id>http://example.org/polish</id>
|
14
|
+
<link href='http://example.org/polish' rel='alternate' />
|
15
|
+
<title>ten…</title>
|
16
|
+
<updated>2010-07-23T02:00:00+02:00</updated>
|
17
|
+
<content type='html'><p>ten beep jest tylko po polsku.</p></content>
|
18
|
+
</entry>
|
19
|
+
<entry>
|
20
|
+
<id>http://example.org/english</id>
|
21
|
+
<link href='http://example.org/english' rel='alternate' />
|
22
|
+
<title>this…</title>
|
23
|
+
<updated>2010-07-23T01:00:00+02:00</updated>
|
24
|
+
<content type='html'><p>this beep is only in English.</p></content>
|
25
|
+
</entry>
|
26
|
+
<entry>
|
27
|
+
<id>http://example.org/600</id>
|
28
|
+
<link href='http://example.org/600' rel='alternate' />
|
29
|
+
<title>600th anniversary (intl.)</title>
|
30
|
+
<updated>2010-07-15T12:00:00+02:00</updated>
|
31
|
+
<content type='html'>
|
32
|
+
<p>600 years ago <a href="http://en.wikipedia.org/wiki/Battle_of_Grunwald">something supposedly important</a>
|
33
|
+
happened around these parts of the world</p>
|
34
|
+
</content>
|
35
|
+
</entry>
|
36
|
+
<entry>
|
37
|
+
<id>http://example.org/bilingual</id>
|
38
|
+
<link href='http://example.org/bilingual' rel='alternate' />
|
39
|
+
<title>bilinguality</title>
|
40
|
+
<updated>2010-07-15T06:00:00+02:00</updated>
|
41
|
+
<content type='html'><p>this article is also available <a href="bilingual.pl">in Polish</a></p></content>
|
42
|
+
</entry>
|
43
|
+
<entry>
|
44
|
+
<id>http://example.org/dated</id>
|
45
|
+
<link href='http://example.org/dated' rel='alternate' />
|
46
|
+
<title>a…</title>
|
47
|
+
<updated>2010-07-15T03:00:00+02:00</updated>
|
48
|
+
<content type='html'><p>a dated beep.</p></content>
|
49
|
+
</entry>
|
50
|
+
</feed>
|