Skip to content

Commit 41c6ea9

Browse files
committedJan 29, 2013
Initial commit
0 parents  commit 41c6ea9

22 files changed

+2072
-0
lines changed
 

‎.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
output
2+
tmp
3+
.DS_Store
4+
.bundle
5+
bin
6+
*.log

‎Gemfile

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
source "http://rubygems.org"
2+
3+
4+
gem 'redcarpet'
5+
gem 'nanoc'
6+
gem 'nokogiri'
7+
gem 'pygments.rb'
8+
#gem 'rake', '~> 0.9.2'
9+
#gem 'thin'
10+
11+
group :development do
12+
gem 'adsf'
13+
gem 'fssm'
14+
end

‎Gemfile.lock

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
GEM
2+
remote: http://rubygems.org/
3+
specs:
4+
adsf (1.1.1)
5+
rack (>= 1.0.0)
6+
colored (1.2)
7+
cri (2.3.0)
8+
colored (>= 1.2)
9+
fssm (0.2.10)
10+
nanoc (3.4.3)
11+
cri (~> 2.2)
12+
nokogiri (1.5.6)
13+
posix-spawn (0.3.6)
14+
pygments.rb (0.3.7)
15+
posix-spawn (~> 0.3.6)
16+
yajl-ruby (~> 1.1.0)
17+
rack (1.5.0)
18+
redcarpet (2.2.2)
19+
yajl-ruby (1.1.0)
20+
21+
PLATFORMS
22+
ruby
23+
24+
DEPENDENCIES
25+
adsf
26+
fssm
27+
nanoc
28+
nokogiri
29+
pygments.rb
30+
redcarpet

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Turbolinks Compatibility

‎Rules

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/usr/bin/env ruby
2+
3+
# A few helpful tips about the Rules file:
4+
#
5+
# * The string given to #compile and #route are matching patterns for
6+
# identifiers--not for paths. Therefore, you can’t match on extension.
7+
#
8+
# * The order of rules is important: for each item, only the first matching
9+
# rule is applied.
10+
#
11+
# * Item identifiers start and end with a slash (e.g. “/about/” for the file
12+
# “content/about.html”). To select all children, grandchildren, … of an
13+
# item, use the pattern “/about/*/”; “/about/*” will also select the parent,
14+
# because “*” matches zero or more characters.
15+
16+
# compile '/stylesheet/' do
17+
# # don’t filter or layout
18+
# end
19+
#
20+
# compile '/github/' do
21+
# # don’t filter or layout
22+
# end
23+
24+
compile '/static/*' do
25+
end
26+
27+
compile '*' do
28+
if item.binary?
29+
# don’t filter binary items
30+
else
31+
filter :erb
32+
filter :redcarpet, renderer: HTMLwithLanguage, options: { fenced_code_blocks: true }
33+
filter :colorize_syntax, default_colorizer: :pygmentsrb
34+
layout 'default'
35+
end
36+
end
37+
38+
# route '/stylesheet/' do
39+
# '/style.css'
40+
# end
41+
42+
route '/static/*' do
43+
item.identifier[7..-2]
44+
end
45+
46+
route '*' do
47+
if item.binary?
48+
# Write item with identifier /foo/ to /foo.ext
49+
item.identifier.chop + '.' + item[:extension]
50+
else
51+
# Write item with identifier /foo/ to /foo/index.html
52+
item.identifier + 'index.html'
53+
end
54+
end
55+
56+
layout '*', :erb

‎config.yaml

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# A list of file extensions that nanoc will consider to be textual rather than
2+
# binary. If an item with an extension not in this list is found, the file
3+
# will be considered as binary.
4+
text_extensions: [ 'coffee', 'css', 'erb', 'haml', 'handlebars', 'hb', 'htm', 'html', 'js', 'less', 'markdown', 'md', 'ms', 'mustache', 'php', 'rb', 'sass', 'scss', 'txt', 'xhtml', 'xml' ]
5+
6+
# The path to the directory where all generated files will be written to. This
7+
# can be an absolute path starting with a slash, but it can also be path
8+
# relative to the site directory.
9+
output_dir: output
10+
11+
# A list of index filenames, i.e. names of files that will be served by a web
12+
# server when a directory is requested. Usually, index files are named
13+
# “index.html”, but depending on the web server, this may be something else,
14+
# such as “default.htm”. This list is used by nanoc to generate pretty URLs.
15+
index_filenames: [ 'index.html' ]
16+
17+
# Whether or not to generate a diff of the compiled content when compiling a
18+
# site. The diff will contain the differences between the compiled content
19+
# before and after the last site compilation.
20+
enable_output_diff: false
21+
22+
prune:
23+
# Whether to automatically remove files not managed by nanoc from the output
24+
# directory. For safety reasons, this is turned off by default.
25+
auto_prune: false
26+
27+
# Which files and directories you want to exclude from pruning. If you version
28+
# your output directory, you should probably exclude VCS directories such as
29+
# .git, .svn etc.
30+
exclude: [ '.git', '.hg', '.svn', 'CVS' ]
31+
32+
# The data sources where nanoc loads its data from. This is an array of
33+
# hashes; each array element represents a single data source. By default,
34+
# there is only a single data source that reads data from the “content/” and
35+
# “layout/” directories in the site directory.
36+
data_sources:
37+
-
38+
# The type is the identifier of the data source. By default, this will be
39+
# `filesystem_unified`.
40+
type: filesystem_unified
41+
42+
# The path where items should be mounted (comparable to mount points in
43+
# Unix-like systems). This is “/” by default, meaning that items will have
44+
# “/” prefixed to their identifiers. If the items root were “/en/”
45+
# instead, an item at content/about.html would have an identifier of
46+
# “/en/about/” instead of just “/about/”.
47+
items_root: /
48+
49+
# The path where layouts should be mounted. The layouts root behaves the
50+
# same as the items root, but applies to layouts rather than items.
51+
layouts_root: /
52+
53+
# Whether to allow periods in identifiers. When turned off, everything
54+
# past the first period is considered to be the extension, and when
55+
# turned on, only the characters past the last period are considered to
56+
# be the extension. For example, a file named “content/about.html.erb”
57+
# will have the identifier “/about/” when turned off, but when turned on
58+
# it will become “/about.html/” instead.
59+
allow_periods_in_identifiers: false
60+
61+
-
62+
type: static
63+
items_root: /static
64+
65+
# Configuration for the “watch” command, which watches a site for changes and
66+
# recompiles if necessary.
67+
watcher:
68+
# A list of directories to watch for changes. When editing this, make sure
69+
# that the “output/” and “tmp/” directories are _not_ included in this list,
70+
# because recompiling the site will cause these directories to change, which
71+
# will cause the site to be recompiled, which will cause these directories
72+
# to change, which will cause the site to be recompiled again, and so on.
73+
dirs_to_watch: [ 'content', 'layouts', 'lib' ]
74+
75+
# A list of single files to watch for changes. As mentioned above, don’t put
76+
# any files from the “output/” or “tmp/” directories in here.
77+
files_to_watch: [ 'config.yaml', 'Rules' ]
78+
79+
# When to send notifications (using Growl or notify-send).
80+
notify_on_compilation_success: true
81+
notify_on_compilation_failure: true

‎content/facebook.md

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
title: Facebook
3+
---
4+
5+
## Facebook Social Plugins
6+
7+
[developers.facebook.com/docs/plugins](http://developers.facebook.com/docs/plugins)
8+
9+
**Official Implementation**
10+
11+
```html
12+
<body>
13+
<div id="fb-root"></div>
14+
<script>
15+
(function(d, s, id){
16+
var js, fjs = d.getElementsByTagName(s)[0];
17+
if (d.getElementById(id)) return;
18+
js = d.createElement(s); js.id = id;
19+
js.src = "//connect.facebook.net/en_US/all.js#xfbml=1";
20+
fjs.parentNode.insertBefore(js, fjs);
21+
}(document, 'script', 'facebook-jssdk'));
22+
</script>
23+
24+
<!-- Like button -->
25+
<div class="fb-like" data-send="true" data-layout="button_count" data-width="450" data-show-faces="true"></div>
26+
</body>
27+
```
28+
29+
**Solution**
30+
31+
Remove the script from the body and load the following script inside the `<head>`.
32+
33+
```coffeescript
34+
fb_root = null
35+
36+
$ ->
37+
load_facebook_sdk()
38+
$(document)
39+
.on('page:fetch', saveFacebookRoot)
40+
.on('page:change', restoreFacebookRoot)
41+
.on('page:load', ->
42+
FB?.XFBML.parse()
43+
44+
saveFacebookRoot = ->
45+
fb_root = $('#fb-root').detach()
46+
47+
restoreFacebookRoot = ->
48+
if $('#fb-root').length > 0
49+
$('#fb-root').replaceWith fb_root
50+
else
51+
$('body').append fb_root
52+
53+
loadFacebookSDK = ->
54+
window.fbAsyncInit = initializeFacebookSDK
55+
$.getScript("//connect.facebook.net/en_US/all.js#xfbml=1")
56+
57+
initializeFacebookSDK = ->
58+
FB.init
59+
appId : 'YOUR_APP_ID'
60+
channelUrl: '//WWW.YOUR_DOMAIN.COM/channel.html'
61+
status : true
62+
cookie : true
63+
xfbml : true
64+
```
65+
66+
*Credit:* [Pierre Olivier Martel](https://github.com/pomartel) *(partial)*

‎content/fancybox.md

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
title: FancyBox
3+
---
4+
5+
## FancyBox
6+
7+
FancyBox (>= 2.1.2) is known to work with Turbolinks without modifications.
8+
9+
For version 1.3.4, just add this to your application's javascript:
10+
11+
```coffeescript
12+
$(document).bind 'page:change', ->
13+
$.fancybox.init()
14+
```
15+
16+
*Credit:* [Rose](https://github.com/R-osey), [Juan de Dios Herrero](https://github.com/jd-erreape)

‎content/google_analytics.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
title: "Google Analytics"
3+
---
4+
5+
## Google Analytics
6+
7+
Move the javascript snippet from the head to the body and load the following script inside the `<head>`.
8+
9+
```coffeescript
10+
$(document).on 'page:change', ->
11+
if window._gaq?
12+
_gaq.push ['_trackPageview']
13+
else if window.pageTracker?
14+
pageTracker._trackPageview()
15+
```
16+
17+
*Credit:* [Shuky Dvir](https://github.com/shukydvir)

‎content/index.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
title: Home
3+
---
4+
5+
## Plugins
6+
7+
[facebook](/facebook)
8+
[map-generator](/map_generator)

‎content/map_generator.md

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
---
2+
title: Map-Generator
3+
---
4+
5+
## Map-Generator
6+
7+
[map-generator.net](http://map-generator.net)
8+
9+
After customizing the map you want, you will be given a generated code snippet that looks something like this:
10+
11+
```html
12+
<div id="map_canvas_custom_48259" style="width:830px; height:350px" ></div>
13+
<script type="text/javascript">
14+
// Line breaks inserted for readability.
15+
(function(d, t) {
16+
var g = d.createElement(t), s = d.getElementsByTagName(t)[0];
17+
g.src = "http://map-generator.net/en/maps/48259.js?point=New+York%2C+NY%2C+USA";
18+
s.parentNode.insertBefore(g, s);
19+
}(document, "script"));
20+
</script>
21+
<a class="mapgen-link" style="font:8px Arial;text-decoration:none;color:#5C5C5C;text-align: right; display: block; width: 830px;" href="http://map-generator.net/en">map-generator.net</a>
22+
```
23+
24+
**Basic Solution**
25+
26+
If you only have one map on a single page of your application, you can get away with just adding the following to your application JS:
27+
28+
```coffeescript
29+
$(document).bind 'page:load', ->
30+
initializeMgMaps() if $('#mggapiloader')?
31+
```
32+
33+
**Advanced Solution**
34+
35+
This solution handles multiple maps on the same page or on separate pages of the application.
36+
37+
1. Add a class to the script tag for each map you have in your application.
38+
39+
```html
40+
<script class="init_map_generator" type="text/javascript">
41+
```
42+
43+
2. In your application JS, create a function to unload/remove Google Maps and bind it to both the `page:fetch` and `page:restore` events.
44+
45+
```coffeescript
46+
$(document).bind 'page:fetch', ->
47+
cleanMapGenerator()
48+
49+
$(document).bind 'page:restore', ->
50+
cleanMapGenerator true
51+
52+
cleanMapGenerator = (init) ->
53+
window.mapObjWrapper = undefined
54+
window.google.maps = undefined
55+
$('#mggapiloader').remove()
56+
$('[src*="google-analytics.com/ga.js"]').remove()
57+
$('[src*="map-generator.net"]').remove()
58+
$('[src*="maps.gstatic.com"]').remove()
59+
window.eval initMapGenerator.text() if init and (initMapGenerator = $('script.init_map_generator'))?
60+
```

‎content/olark.md

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
title: Olark
3+
---
4+
5+
## Olark chat widget
6+
7+
[olark.com](http://olark.com)
8+
9+
The supplied javascript will look something like this:
10+
11+
```html
12+
<script>
13+
window.olark || (function(c){
14+
// initialization code
15+
})({
16+
loader: "static.olark.com/jsclient/loader0.js",
17+
name: "olark",
18+
methods: ["configure", "extend", "declare", "identify"]
19+
});
20+
olark.identify('<your identity string>');
21+
</script>
22+
```
23+
24+
To get it working with Turbolinks:
25+
26+
1. Move the script inside the head tags.
27+
2. Convert the anonymous initialization function into a named function.
28+
3. Bind this new function to the `page:load` event.
29+
30+
An example solution, in jQuery:
31+
32+
```javascript
33+
function initOlark(){
34+
c = {
35+
loader: "static.olark.com/jsclient/loader0.js",
36+
name: "olark",
37+
methods: ["configure", "extend", "declare", "identify"]
38+
};
39+
//initialization code
40+
}
41+
42+
window.olark || initOlark();
43+
44+
$(document).bind('page:load', function(){
45+
initOlark();
46+
olark.identify('<your identity string>');
47+
});
48+
```
49+
50+
For a more detailed explanation, check out [empact.posterous.com/running-olark-under-turbolinks](http://empact.posterous.com/running-olark-under-turbolinks).
51+
52+
*Credit:* [Ben Woosley](https://github.com/Empact)

‎content/stripe.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
title: Stripe
3+
---
4+
5+
## Stripe Checkout
6+
7+
https://stripe.com/docs/checkout
8+
9+
As of version 2 of the Stripe API, the official implementation is Turbolinks-ready.

‎content/twitter.md

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
title: Twitter
3+
---
4+
5+
# Twitter Buttons
6+
7+
[twitter.com/about/resources/buttons](https://twitter.com/about/resources/buttons)
8+
9+
Fix: Replace the supplied javascript snippet with an external script tag pointing to platform.twitter.com/widgets.js.
10+
11+
**Before:**
12+
13+
```html
14+
<body>
15+
<a href="https://twitter.com/share" class="twitter-share-button" data-via="njreed86" data-size="large">Tweet</a>
16+
<script>
17+
!function(d,s,id){
18+
var js, fjs = d.getElementsByTagName(s)[0];
19+
if (!d.getElementById(id)){
20+
js = d.createElement(s);
21+
js.id = id;
22+
js.src = "//platform.twitter.com/widgets.js";
23+
fjs.parentNode.insertBefore(js,fjs);
24+
}
25+
}(document,"script","twitter-wjs");
26+
</script>
27+
</body>
28+
```
29+
30+
**After:**
31+
32+
```html
33+
<body>
34+
<a href="https://twitter.com/share" class="twitter-share-button" data-via="njreed86" data-size="large">Tweet</a>
35+
<script src="//platform.twitter.com/widgets.js"></script>
36+
</body>
37+
```

‎layouts/default.html

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<!DOCTYPE HTML>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Turbolinks Compatibility - <%= @item[:title] %></title>
6+
<link rel="stylesheet" type="text/css" href="/css/style.css" media="screen">
7+
<link rel="stylesheet" type="text/css" href="/css/bootstrap.css" media="screen">
8+
<link rel="stylesheet" type="text/css" href="/css/github.css" media="screen">
9+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
10+
<!-- you don't need to keep this, but it's cool for stats! -->
11+
<meta name="generator" content="nanoc <%= Nanoc::VERSION %>">
12+
</head>
13+
<body>
14+
<div class="container-fluid">
15+
<div class="page-header">
16+
<h1>Turbolinks <small>Compatibility</small></h1>
17+
</div>
18+
<div class="row-fluid">
19+
<div id="sidebar" class="span2">
20+
<ul class="nav nav-pills nav-stacked">
21+
<% @items.each do |item| %>
22+
<% if item[:title] %>
23+
<li <%= 'class="active"' if item == @item %>><a href="<%= item.path %>"><%= item[:title] %></a></li>
24+
<% end %>
25+
<% end %>
26+
</ul>
27+
</div>
28+
<div id="main" class="span10 markdown-body">
29+
<%= yield %>
30+
</div>
31+
</div>
32+
</div>
33+
</body>
34+
</html>

‎lib/default.rb

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# All files in the 'lib' directory will be loaded
2+
# before nanoc starts compiling.
3+
4+
require 'redcarpet'
5+
require 'cgi'
6+
7+
class HTMLwithLanguage < Redcarpet::Render::HTML
8+
def block_code(code, language)
9+
"<pre><code class=\"language-#{language}\">#{CGI::escapeHTML(code)}</code></pre>"
10+
end
11+
end

‎lib/github_filter.rb

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
class Github < Nanoc::Filter
2+
identifier :github
3+
4+
def run(content, params={})
5+
gfm(content)
6+
end
7+
8+
def gfm(content)
9+
text = content
10+
11+
# Extract pre blocks
12+
extractions = {}
13+
text = text.gsub(%r{<pre>.*?</pre>}m) do |match|
14+
md5 = Digest::MD5.hexdigest(match)
15+
extractions[md5] = match
16+
"{gfm-extraction-#{md5}}"
17+
end
18+
19+
# prevent foo_bar_baz from ending up with an italic word in the middle
20+
text = text.gsub(/(^(?! {4}|\t)\w+_\w+_\w[\w_]*)/) do |x|
21+
x.gsub('_', '\_') if x.split('').sort.to_s[0..1] == '__'
22+
end
23+
24+
# in very clear cases, let newlines become <br /> tags
25+
text = text.gsub(/^[\w\<][^\n]*\n+/) do |x|
26+
x =~ /\n{2}/ ? x : (x.strip!; x << " \n")
27+
end
28+
29+
# Insert pre block extractions
30+
text = text.gsub(/\{gfm-extraction-([0-9a-f]{32})\}/) do
31+
"\n\n" + extractions[$1]
32+
end
33+
34+
text
35+
end
36+
end

‎lib/static.rb

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
require 'digest/sha1'
2+
3+
module Nanoc3::DataSources
4+
5+
class Static < Nanoc3::DataSource
6+
7+
identifier :static
8+
9+
def items
10+
# Get prefix
11+
prefix = config[:prefix] || 'static'
12+
13+
# Get all files under prefix dir
14+
filenames = Dir[prefix + '/**/*'].select { |f| File.file?(f) }
15+
16+
# Convert filenames to items
17+
filenames.map do |filename|
18+
attributes = {
19+
:extension => File.extname(filename)[1..-1],
20+
:filename => filename,
21+
}
22+
identifier = filename[(prefix.length+1)..-1] + '/'
23+
24+
mtime = File.mtime(filename)
25+
checksum = checksum_for(filename)
26+
27+
Nanoc3::Item.new(
28+
filename,
29+
attributes,
30+
identifier,
31+
:binary => true, :mtime => mtime, :checksum => checksum
32+
)
33+
end
34+
end
35+
36+
private
37+
38+
# Returns a checksum of the given filenames
39+
# TODO un-duplicate this somewhere
40+
def checksum_for(*filenames)
41+
filenames.flatten.map do |filename|
42+
digest = Digest::SHA1.new
43+
File.open(filename, 'r') do |io|
44+
until io.eof
45+
data = io.readpartial(2**10)
46+
digest.update(data)
47+
end
48+
end
49+
digest.hexdigest
50+
end.join('-')
51+
end
52+
53+
end
54+
55+
end

‎static/css/bootstrap.css

+782
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎static/css/github.css

+592
Large diffs are not rendered by default.

‎static/css/style.css

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
body {
2+
background: url('/images/bg.gif') repeat center center;
3+
}
4+
#sidebar {
5+
padding-top: 30px;
6+
border-right: 1px solid #ccc;
7+
}
8+
9+
//* {
10+
// margin: 0;
11+
// padding: 0;
12+
//
13+
// font-family: Georgia, Palatino, Times, 'Times New Roman', sans-serif;
14+
//}
15+
//
16+
//body {
17+
// background: #fff;
18+
//}
19+
//
20+
//a {
21+
// text-decoration: none;
22+
//}
23+
//
24+
//a:link,
25+
//a:visited {
26+
// color: #f30;
27+
//}
28+
//
29+
//a:hover {
30+
// color: #f90;
31+
//}
32+
//
33+
//#main {
34+
// position: absolute;
35+
//
36+
// top: 40px;
37+
// left: 280px;
38+
//
39+
// width: 500px;
40+
//}
41+
//
42+
//#main h1 {
43+
// font-size: 40px;
44+
// font-weight: normal;
45+
//
46+
// line-height: 40px;
47+
//
48+
// letter-spacing: -1px;
49+
//}
50+
//
51+
//#main p {
52+
// margin: 20px 0;
53+
//
54+
// font-size: 15px;
55+
//
56+
// line-height: 20px;
57+
//}
58+
//
59+
//#main ul, #main ol {
60+
// margin: 20px;
61+
//}
62+
//
63+
//#main li {
64+
// font-size: 15px;
65+
//
66+
// line-height: 20px;
67+
//}
68+
//
69+
//#main ul li {
70+
// list-style-type: square;
71+
//}
72+
//
73+
//#sidebar {
74+
// position: absolute;
75+
//
76+
// top: 40px;
77+
// left: 20px;
78+
// width: 200px;
79+
//
80+
// padding: 20px 20px 0 0;
81+
//
82+
// border-right: 1px solid #ccc;
83+
//
84+
// text-align: right;
85+
//}
86+
//
87+
//#sidebar h2 {
88+
// text-transform: uppercase;
89+
//
90+
// font-size: 13px;
91+
//
92+
// color: #333;
93+
//
94+
// letter-spacing: 1px;
95+
//
96+
// line-height: 20px;
97+
//}
98+
//
99+
//#sidebar ul {
100+
// list-style-type: none;
101+
//
102+
// margin: 20px 0;
103+
//}
104+
//
105+
//#sidebar li {
106+
// font-size: 14px;
107+
//
108+
// line-height: 20px;
109+
//}

‎static/images/bg.gif

4.84 KB
Loading

0 commit comments

Comments
 (0)
Please sign in to comment.