diff --git a/assets/images/icons.png b/assets/images/icons.png
index 7320379f..aac50a9a 100644
Binary files a/assets/images/icons.png and b/assets/images/icons.png differ
diff --git a/assets/images/icons@2x.png b/assets/images/icons@2x.png
index dda527a9..d3e7cddf 100644
Binary files a/assets/images/icons@2x.png and b/assets/images/icons@2x.png differ
diff --git a/assets/javascripts/templates/pages/about_tmpl.coffee b/assets/javascripts/templates/pages/about_tmpl.coffee
index a004fda3..d39ad867 100644
--- a/assets/javascripts/templates/pages/about_tmpl.coffee
+++ b/assets/javascripts/templates/pages/about_tmpl.coffee
@@ -165,6 +165,11 @@ credits = [
'2009-2013 The Dojo Foundation',
'MIT',
'https://raw.github.com/lodash/lodash/master/LICENSE.txt'
+ ], [
+ 'MaxCDN',
+ '2014 MaxCDN',
+ 'MIT',
+ 'https://raw.githubusercontent.com/MaxCDN/api-docs/master/LICENSE'
], [
'Moment.js',
'2011-2014 Tim Wood, Iskren Chernev, Moment.js contributors',
diff --git a/assets/javascripts/templates/pages/news_tmpl.coffee b/assets/javascripts/templates/pages/news_tmpl.coffee
index d91fcccb..ada08703 100644
--- a/assets/javascripts/templates/pages/news_tmpl.coffee
+++ b/assets/javascripts/templates/pages/news_tmpl.coffee
@@ -24,8 +24,8 @@ newsItem = (date, news) ->
result
app.news = [
- [ 1399075200000, # May 3, 2014
- """ New Express and Grunt documentations """,
+ [ 1399161600000, # May 4, 2014
+ """ New Express, Grunt, and MaxCDN documentations """,
], [
1396742400000, # April 6, 2014
""" New Go documentation """,
diff --git a/assets/javascripts/views/pages/maxcdn.coffee b/assets/javascripts/views/pages/maxcdn.coffee
new file mode 100644
index 00000000..02fe8617
--- /dev/null
+++ b/assets/javascripts/views/pages/maxcdn.coffee
@@ -0,0 +1,28 @@
+#= require views/pages/base
+
+class app.views.MaxcdnPage extends app.views.BasePage
+ @events:
+ click: 'onClick'
+
+ afterRender: ->
+ @highlightCode @findAll('.tab-pane[id^="ruby"] > pre'), 'ruby'
+ @highlightCode @findAll('.tab-pane[id^="python"] > pre'), 'python'
+ @highlightCode @findAll('.tab-pane[id^="node"] > pre, .tab-pane[id^="resp"] > pre'), 'javascript'
+ return
+
+ onClick: (event) ->
+ return unless (link = event.target).getAttribute('data-toggle') is 'tab'
+ $.stopEvent(event)
+
+ list = link.parentNode.parentNode
+ tabs = list.nextElementSibling
+
+ li = link.parentNode
+ position = 1
+ position++ while li = li.previousElementSibling
+
+ $('.active', list).classList.remove('active')
+ $('.active', tabs).classList.remove('active')
+
+ link.parentNode.classList.add('active')
+ $(".tab-pane:nth-child(#{position})", tabs).classList.add('active')
diff --git a/assets/stylesheets/application.css.scss b/assets/stylesheets/application.css.scss
index 011e97cb..d6b15b9c 100644
--- a/assets/stylesheets/application.css.scss
+++ b/assets/stylesheets/application.css.scss
@@ -41,6 +41,7 @@
'pages/grunt',
'pages/less',
'pages/lodash',
+ 'pages/maxcdn',
'pages/mdn',
'pages/moment',
'pages/node',
diff --git a/assets/stylesheets/global/_icons.scss b/assets/stylesheets/global/_icons.scss
index 0f0ab8d4..ab85f8a2 100644
--- a/assets/stylesheets/global/_icons.scss
+++ b/assets/stylesheets/global/_icons.scss
@@ -55,3 +55,4 @@
._icon-go:before { background-position: -1rem -8rem; }
._icon-express:before { background-position: -2rem -8rem; }
._icon-grunt:before { background-position: -3rem -8rem; }
+._icon-maxcdn:before { background-position: -4rem -8rem; }
diff --git a/assets/stylesheets/pages/_maxcdn.scss b/assets/stylesheets/pages/_maxcdn.scss
new file mode 100644
index 00000000..2cbdc4bc
--- /dev/null
+++ b/assets/stylesheets/pages/_maxcdn.scss
@@ -0,0 +1,49 @@
+._maxcdn {
+ padding-left: 1rem;
+
+ h1, h2, h3 { margin-left: -1rem; }
+ h2 { @extend %block-heading; }
+ h3 { @extend %block-label, %label-blue; }
+ h4 { font-size: 1em; }
+ p > code { @extend %label; }
+
+ .url {
+ padding: .5rem;
+ white-space: normal;
+ @extend %pre, %note-green;
+ }
+
+ .http_method { @extend %label; }
+
+ .nav-tabs {
+ height: 2rem;
+ padding: 0;
+ list-style: none;
+ border-bottom: 1px solid #ddd;
+
+ > li {
+ float: left;
+ margin: -1px 0;
+
+ > a {
+ display: block;
+ padding: .5rem 1em;
+ line-height: 1rem;
+ margin-right: 2px;
+ border: 1px solid transparent;
+ border-radius: 3px 3px 0 0;
+ }
+
+ &.active > a {
+ color: $textColor;
+ text-decoration: none;
+ background: white;
+ border-color: #ddd #ddd transparent;
+ cursor: default;
+ }
+ }
+ }
+
+ .tab-pane { display: none; }
+ .tab-pane.active { display: block; }
+}
diff --git a/lib/docs/filters/maxcdn/clean_html.rb b/lib/docs/filters/maxcdn/clean_html.rb
new file mode 100644
index 00000000..874e9a45
--- /dev/null
+++ b/lib/docs/filters/maxcdn/clean_html.rb
@@ -0,0 +1,25 @@
+module Docs
+ class Maxcdn
+ class CleanHtmlFilter < Filter
+ def call
+ css('hr', 'td:last-child:empty').remove
+
+ css('h1, h2, h3, h4').each do |node|
+ node.name = node.name.sub(/\d/) { |i| i.to_i + 1 }
+ end
+
+ at_css('h2').name = 'h1'
+
+ css('.path > a').each do |node|
+ node.before(node.children).remove
+ end
+
+ css('[name]').each do |node|
+ node.remove_attribute 'name'
+ end
+
+ doc
+ end
+ end
+ end
+end
diff --git a/lib/docs/filters/maxcdn/entries.rb b/lib/docs/filters/maxcdn/entries.rb
new file mode 100644
index 00000000..16638526
--- /dev/null
+++ b/lib/docs/filters/maxcdn/entries.rb
@@ -0,0 +1,30 @@
+module Docs
+ class Maxcdn
+ class EntriesFilter < Docs::EntriesFilter
+ def additional_entries
+ type = id_prefix = nil
+
+ doc.children.each_with_object [] do |node, entries|
+ if node.name == 'h2'
+ type = node.content.strip
+ type.remove! %r{ API\z}
+ type.remove! ' Custom Domains'
+ id_prefix = type.parameterize
+ type = 'Reports' if type.starts_with? 'Reports'
+ elsif node.name == 'h3'
+ next unless type
+ name = node.content.strip
+ id = "#{id_prefix}-#{name}".parameterize
+ node['id'] = id
+
+ if name.ends_with?('Domain') && ['Push Zone', 'Pull Zone', 'VOD Zone'].include?(type)
+ name << " (#{type})"
+ end
+
+ entries << [name, id, type]
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/docs/scrapers/maxcdn.rb b/lib/docs/scrapers/maxcdn.rb
new file mode 100644
index 00000000..9640314e
--- /dev/null
+++ b/lib/docs/scrapers/maxcdn.rb
@@ -0,0 +1,17 @@
+module Docs
+ class Maxcdn < UrlScraper
+ self.name = 'MaxCDN'
+ self.type = 'maxcdn'
+ self.base_url = 'http://docs.maxcdn.com/'
+
+ html_filters.push 'maxcdn/clean_html', 'maxcdn/entries'
+
+ options[:container] = '#readme-docs'
+ options[:skip_links] = true
+
+ options[:attribution] = <<-HTML
+ © 2014 MaxCDN
+ Licensed under the MIT License.
+ HTML
+ end
+end
diff --git a/public/icons/docs/maxcdn/16.png b/public/icons/docs/maxcdn/16.png
new file mode 100644
index 00000000..678fcc27
Binary files /dev/null and b/public/icons/docs/maxcdn/16.png differ
diff --git a/public/icons/docs/maxcdn/16@2x.png b/public/icons/docs/maxcdn/16@2x.png
new file mode 100644
index 00000000..3808d136
Binary files /dev/null and b/public/icons/docs/maxcdn/16@2x.png differ
diff --git a/public/icons/docs/maxcdn/SOURCE b/public/icons/docs/maxcdn/SOURCE
new file mode 100644
index 00000000..844d6c3a
--- /dev/null
+++ b/public/icons/docs/maxcdn/SOURCE
@@ -0,0 +1 @@
+https://github.com/MaxCDN/media