tributary 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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>
|