cartoonist 0.0.3.5 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/app/assets/javascripts/application.js.erb +2 -0
  2. data/app/assets/stylesheets/admin.css.scss +16 -0
  3. data/app/controllers/admin_controller.rb +93 -0
  4. data/app/controllers/application_controller.rb +38 -0
  5. data/app/controllers/cache_controller.rb +34 -0
  6. data/app/controllers/settings_controller.rb +35 -0
  7. data/app/controllers/site_controller.rb +49 -0
  8. data/app/controllers/static_cache_controller.rb +19 -0
  9. data/app/helpers/application_helper.rb +74 -0
  10. data/app/helpers/cache_helper.rb +17 -0
  11. data/app/models/backup.rb +11 -0
  12. data/app/models/database_file.rb +2 -0
  13. data/app/models/markdown.rb +17 -0
  14. data/app/models/page_cache.rb +102 -0
  15. data/app/models/setting.rb +258 -0
  16. data/app/models/simple_template.rb +20 -0
  17. data/app/models/sitemap_entry.rb +5 -0
  18. data/app/models/static_cache.rb +47 -0
  19. data/app/models/tweetable.rb +17 -0
  20. data/app/views/admin/main.html.erb +7 -0
  21. data/app/views/admin/sign_in.html.erb +19 -0
  22. data/app/views/cache/index.html.erb +61 -0
  23. data/app/views/layouts/admin.html.erb +43 -0
  24. data/app/views/layouts/application.html.erb +134 -0
  25. data/app/views/layouts/application.rss.erb +16 -0
  26. data/app/views/layouts/application.xml.erb +2 -0
  27. data/app/views/layouts/general_admin.html.erb +10 -0
  28. data/app/views/layouts/sign_in.html.erb +12 -0
  29. data/app/views/settings/initial_setup.html.erb +25 -0
  30. data/app/views/settings/show.html.erb +39 -0
  31. data/app/views/site/robots.text.erb +1 -0
  32. data/app/views/site/sitemap.xml.erb +12 -0
  33. data/app/views/static_cache/index.html.erb +29 -0
  34. data/cartoonist.gemspec +3 -2
  35. data/config/locales/en.yml +99 -0
  36. data/db/migrate/20120320043253_create_database_files.rb +9 -0
  37. data/db/migrate/20120401014029_create_settings.rb +12 -0
  38. data/lib/cartoonist/engine.rb +129 -0
  39. data/lib/cartoonist.rb +236 -0
  40. data/public/errors/404.html +13 -0
  41. data/public/errors/422.html +11 -0
  42. data/public/errors/500.html +13 -0
  43. metadata +41 -2
@@ -0,0 +1,25 @@
1
+ <%= form_tag "/settings/save_initial_setup", :method => :post do %>
2
+ <p>
3
+ <%= t "settings.initial_setup.username" %><input type="text" name="admin_username" value="<%= t "settings.initial_setup.default_username" %>" autofocus="autofocus" />
4
+ </p>
5
+
6
+ <p>
7
+ <%= t "settings.initial_setup.name" %><input type="text" name="admin_name" value="<%= t "settings.initial_setup.default_name" %>" />
8
+ </p>
9
+
10
+ <p>
11
+ <%= t "settings.initial_setup.password" %><input type="password" name="admin_password" />
12
+ </p>
13
+
14
+ <p>
15
+ <%= t "settings.initial_setup.domain" %><input type="text" name="domain" />
16
+ </p>
17
+
18
+ <p>
19
+ <%= t "settings.initial_setup.site_name" %><input type="text" name="site_name" />
20
+ </p>
21
+
22
+ <p>
23
+ <input type="submit" value="<%= t "settings.initial_setup.save" %>" />
24
+ </p>
25
+ <% end %>
@@ -0,0 +1,39 @@
1
+ <div class="tabs">
2
+ <% Setting.tabs.each do |tab| %>
3
+ <a href="/settings/<%= tab %>" class="tab <%= "selected_tab" if tab == params[:id].to_sym %>"><%= t tab, :scope => "settings.show.tabs" %></a>
4
+ <% end %>
5
+ </div>
6
+
7
+ <%= form_tag "/settings/#{@tab.label}", :method => :put do %>
8
+ <% @tab.sections.each do |section| %>
9
+ <div class="section">
10
+ <h2><%= t section, :scope => "settings.show.sections.#{@tab.label}" %></h2>
11
+
12
+ <% @tab[section].settings.each do |setting| %>
13
+ <%# Other setting types to come later %>
14
+ <% next unless Setting::Meta[setting].select_from || [:string, :boolean, :int].include?(Setting::Meta[setting].type) %>
15
+ <p>
16
+ <input type="hidden" name="included_settings[]" value="<%= setting %>" />
17
+ <label>
18
+ <%= t setting, :scope => "settings.show.settings" %>
19
+ <% if Setting::Meta[setting].select_from %>
20
+ <select name="<%= setting %>">
21
+ <% Setting::Meta[setting].select_from_options.each do |option| %>
22
+ <option value="<%= option %>" <%= selected option, Setting[setting] %>><%= option %></option>
23
+ <% end %>
24
+ <select name="<%= setting %>" value="<%= Setting[setting] %>">
25
+ <% elsif Setting::Meta[setting].type == :string %>
26
+ <input type="text" name="<%= setting %>" value="<%= Setting[setting] %>" size="60" />
27
+ <% elsif [:int, :float].include?(Setting::Meta[setting].type) %>
28
+ <input type="text" name="<%= setting %>" value="<%= Setting[setting] %>" size="10" />
29
+ <% elsif Setting::Meta[setting].type == :boolean %>
30
+ <input type="checkbox" name="<%= setting %>" value="true" <%= checked Setting[setting] %> />
31
+ <% end %>
32
+ </label>
33
+ </p>
34
+ <% end %>
35
+ </div>
36
+ <% end %>
37
+
38
+ <input type="submit" value="<%= t "settings.show.save" %>" />
39
+ <% end %>
@@ -0,0 +1 @@
1
+ Sitemap: http://<%= Setting[:domain] %>/sitemap.xml
@@ -0,0 +1,12 @@
1
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
2
+ <% @entries.each do |entry| %>
3
+ <url>
4
+ <loc>http://<%= Setting[:domain] %><%= entry.path %></loc>
5
+ <lastmod><%= entry.formatted_lastmod %></lastmod>
6
+ <changefreq><%= entry.changefreq %></changefreq>
7
+ <% if entry.priority %>
8
+ <priority><%= entry.priority %></priority>
9
+ <% end %>
10
+ </url>
11
+ <% end %>
12
+ </urlset>
@@ -0,0 +1,29 @@
1
+ <p>
2
+ <%= form_tag "/static_cache/expire_all", :method => :post, :class => "inline" do %>
3
+ <input type="submit" value="<%= t "static_cache.index.expire_all" %>" />
4
+ <% end %>
5
+ </p>
6
+
7
+ <p>
8
+ <table class="cache">
9
+ <thead>
10
+ <tr>
11
+ <th><%= t "static_cache.index.page" %></th>
12
+ <th></th>
13
+ </tr>
14
+ </thead>
15
+ <tbody>
16
+ <% @caches.each do |cache| %>
17
+ <tr>
18
+ <td><%= cache.name %></td>
19
+
20
+ <td>
21
+ <%= form_tag "/static_cache/#{u cache.name}", :method => :delete do %>
22
+ <input type="submit" value="<%= t "static_cache.index.expire" %>" />
23
+ <% end %>
24
+ </td>
25
+ </tr>
26
+ <% end %>
27
+ </tbody>
28
+ </table>
29
+ </p>
data/cartoonist.gemspec CHANGED
@@ -1,7 +1,8 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "cartoonist"
3
- s.version = "0.0.3.5"
4
- s.date = "2012-04-12"
3
+ raise "Cannot find version file!" unless File.exists?(File.join(File.dirname(__FILE__), "../CARTOONIST_VERSION"))
4
+ s.version = File.read File.join(File.dirname(__FILE__), "../CARTOONIST_VERSION")
5
+ s.date = Time.now.strftime "%Y-%m-%d"
5
6
  s.summary = "Cartoonist Core"
6
7
  s.description = "This provides the main functionality and plugin api for Cartoonist."
7
8
  s.authors = ["Mike Virata-Stone"]
@@ -0,0 +1,99 @@
1
+ en:
2
+ admin:
3
+ general:
4
+ actions:
5
+ backup: Download Backup
6
+ reload: Update and Reload
7
+ layout:
8
+ actions: Actions
9
+ cache: Cache
10
+ section: General
11
+ settings: Settings
12
+ static_cache: Static Cache
13
+ layout:
14
+ tab:
15
+ general: General
16
+ logout: Logout
17
+ not_live_warning: development
18
+ production_warning: PRODUCTION
19
+ user_heading: "%{user}:"
20
+ application:
21
+ layout:
22
+ disqus:
23
+ noscript_pre_link: "Please enable JavaScript to view the "
24
+ noscript_link: Disqus comments.
25
+ noscript_post_link:
26
+ logo: Logo
27
+ navigation:
28
+ follow_on_twitter: Follow us on Twitter
29
+ follow_on_twitter_title: Follow us on Twitter
30
+ cache:
31
+ index:
32
+ cached: cached
33
+ expire: Expire
34
+ expire_all: Expire all
35
+ expire_m: Expire m
36
+ expire_tmp: Expire tmp
37
+ expire_www: Expire www
38
+ m: m
39
+ m_tmp: m tmp
40
+ not_cached: not cached
41
+ page: Page
42
+ www: www
43
+ www_tmp: www tmp
44
+ settings:
45
+ initial_setup:
46
+ default_name: Anonymous
47
+ default_username: admin
48
+ domain: "Domain: "
49
+ name: "Name: "
50
+ password: "Password: "
51
+ save: Save
52
+ site_name: "Site Name: "
53
+ username: "Username: "
54
+ show:
55
+ save: Save
56
+ sections:
57
+ advanced:
58
+ general: General
59
+ general:
60
+ general: General
61
+ social_and_analytics:
62
+ disqus: Disqus
63
+ google_analytics: Google Analytics
64
+ twitter: Twitter
65
+ settings:
66
+ domain: "Domain: "
67
+ site_name: "Site Name: "
68
+ site_heading: "Site Heading: "
69
+ site_update_description: "Site Update Description: "
70
+ theme: "Theme: "
71
+ schedule: "Schedule: "
72
+ copyright_starting_year: "Copyright Starting Year: "
73
+ copyright_owners: "Copyright Owners: "
74
+ default_title: "Default Title: "
75
+ default_tweet: "Default Tweet: "
76
+ twitter_enabled: "Twitter Enabled: "
77
+ twitter_handle: "Twitter Handle: "
78
+ twitter_consumer_key: "Twitter Consumer Key: "
79
+ twitter_consumer_secret: "Twitter Consumer Secret: "
80
+ twitter_oauth_token: "Twitter Oauth Token: "
81
+ twitter_oauth_token_secret: "Twitter Oauth Token Secret: "
82
+ google_analytics_enabled: "Google Analytics Enabled: "
83
+ google_analytics_account: "Google Analytics Account: "
84
+ disqus_enabled: "Disqus Enabled: "
85
+ disqus_shortname: "Disqus Shortname: "
86
+ disqus_comic_category: "Disqus Comic Category: "
87
+ disqus_blog_post_category: "Disqus Blog Post Category: "
88
+ disqus_page_category: "Disqus Page Category: "
89
+ admin_users: "Admin Users: "
90
+ secret_token: "Secret Token: "
91
+ tabs:
92
+ advanced: Advanced
93
+ general: General
94
+ social_and_analytics: Social & Analytics
95
+ static_cache:
96
+ index:
97
+ expire: Expire
98
+ expire_all: Expire all
99
+ page: Page
@@ -0,0 +1,9 @@
1
+ class CreateDatabaseFiles < ActiveRecord::Migration
2
+ def change
3
+ create_table :database_files do |t|
4
+ t.string :filename
5
+ t.binary :content, :null => false
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ class CreateSettings < ActiveRecord::Migration
2
+ def change
3
+ create_table :settings do |t|
4
+ t.string :label, :null => false
5
+ t.text :value
6
+ t.boolean :locked, :default => false, :null => false
7
+ t.timestamps
8
+ end
9
+
10
+ add_index :settings, :label, :unique => true
11
+ end
12
+ end
@@ -1,4 +1,133 @@
1
1
  module Cartoonist
2
2
  class Engine < ::Rails::Engine
3
+ config.before_initialize do
4
+ # Add in various configuration from plugins
5
+ Rails.application.config.assets.precompile += ["admin.css"]
6
+ Rails.application.config.assets.precompile += Cartoonist::Asset.all
7
+ Rails.application.config.paths["db/migrate"] += Cartoonist::Migration.all
8
+
9
+ if File.directory? File.join(Rails.root, "public/errors")
10
+ Rails.application.config.exceptions_app = ActionDispatch::PublicExceptions.new(File.join Rails.root, "public/errors")
11
+ else
12
+ Rails.application.config.exceptions_app = ActionDispatch::PublicExceptions.new(File.join File.dirname(__FILE__), "../../public/errors")
13
+ end
14
+ end
15
+
16
+ config.to_prepare do
17
+ if Setting.table_exists?
18
+ secret_token_changed = lambda do
19
+ # Your secret key for verifying the integrity of signed cookies.
20
+ # If you change this key, all old signed cookies will become invalid!
21
+ # Make sure the secret is at least 30 characters and all random,
22
+ # no regular words or you'll be exposed to dictionary attacks.
23
+ Cartoonist::Application.config.secret_token = Setting[:secret_token]
24
+ end
25
+
26
+ twitter_auth_changed = lambda do
27
+ Twitter.configure do |config|
28
+ config.consumer_key = Setting[:twitter_consumer_key]
29
+ config.consumer_secret = Setting[:twitter_consumer_secret]
30
+ config.oauth_token = Setting[:twitter_oauth_token]
31
+ config.oauth_token_secret = Setting[:twitter_oauth_token_secret]
32
+ end
33
+ end
34
+
35
+ Setting.define :domain, :order => 1
36
+ Setting.define :site_name, :order => 2
37
+ Setting.define :site_heading, :order => 3
38
+ Setting.define :site_update_description, :order => 4
39
+ Setting.define :theme, :type => :symbol, :default => :cartoonist_default_theme, :order => 5, :select_from => lambda { Cartoonist::Theme.all }
40
+ Setting.define :schedule, :type => :array, :default => [:monday, :wednesday, :friday], :order => 6
41
+ Setting.define :copyright_starting_year, :type => :int, :order => 7
42
+ Setting.define :copyright_owners, :order => 8
43
+ Setting.define :default_title, :order => 9
44
+ Setting.define :admin_users, :type => :hash, :order => 10
45
+
46
+ Setting::Tab.define :social_and_analytics, :order => 1 do
47
+ Setting::Section.define :google_analytics, :order => 1 do
48
+ Setting.define :google_analytics_enabled, :type => :boolean, :order => 1
49
+ Setting.define :google_analytics_account, :order => 2
50
+ end
51
+
52
+ Setting::Section.define :twitter, :order => 2 do
53
+ Setting.define :twitter_enabled, :type => :boolean, :order => 1
54
+ Setting.define :default_tweet, :order => 2
55
+ Setting.define :twitter_handle, :order => 3
56
+ Setting.define :twitter_consumer_key, :onchange => twitter_auth_changed, :order => 4
57
+ Setting.define :twitter_consumer_secret, :onchange => twitter_auth_changed, :order => 5
58
+ Setting.define :twitter_oauth_token, :onchange => twitter_auth_changed, :order => 6
59
+ Setting.define :twitter_oauth_token_secret, :onchange => twitter_auth_changed, :order => 7
60
+ end
61
+
62
+ Setting::Section.define :disqus, :order => 3 do
63
+ Setting.define :disqus_enabled, :type => :boolean, :order => 1
64
+ Setting.define :disqus_shortname, :order => 2
65
+ Setting.define :disqus_comic_category, :order => 3
66
+ Setting.define :disqus_blog_post_category, :order => 4
67
+ Setting.define :disqus_page_category, :order => 5
68
+ end
69
+ end
70
+
71
+ Setting::Tab.define :advanced, :order => 2 do
72
+ Setting.define :secret_token, :default => "ThisTokenMustBeRegenerated....", :onchange => secret_token_changed
73
+ end
74
+
75
+ secret_token_changed.call
76
+ twitter_auth_changed.call
77
+ end
78
+ end
79
+
80
+ Cartoonist::Admin::Tab.add :general, :url => "/admin", :order => 3
81
+ Cartoonist::Navigation::Link.add :url => (lambda { "https://twitter.com/#{Setting[:twitter_handle]}" }), :class => "follow-us", :label => "application.layout.navigation.follow_on_twitter", :title => "application.layout.navigation.follow_on_twitter_title", :order => 2
82
+ Cartoonist::Migration.add_for self
83
+
84
+ Cartoonist::Backup.for :files do
85
+ DatabaseFile.order(:id).all
86
+ end
87
+
88
+ Cartoonist::Backup.for :settings do
89
+ Setting.order(:id).all
90
+ end
91
+
92
+ Cartoonist::Routes.add do
93
+ match "favicon" => "site#favicon", :defaults => { :format => "ico" }
94
+ match "sitemap" => "site#sitemap", :defaults => { :format => "xml" }
95
+ match "robots" => "site#robots", :defaults => { :format => "text" }
96
+
97
+ resources :cache do
98
+ collection do
99
+ post "expire_www"
100
+ post "expire_m"
101
+ post "expire_tmp"
102
+ post "expire_all"
103
+ end
104
+ end
105
+
106
+ resources :static_cache, :constraints => { :id => /.*/ } do
107
+ collection do
108
+ post "expire_all"
109
+ end
110
+ end
111
+
112
+ resources :admin do
113
+ collection do
114
+ get "cache_cron"
115
+ get "backup"
116
+ get "logout"
117
+ get "main"
118
+ get "reload"
119
+ get "sign_in"
120
+ post "sign_in"
121
+ get "tweet_cron"
122
+ end
123
+ end
124
+
125
+ resources :settings do
126
+ collection do
127
+ get "initial_setup"
128
+ post "save_initial_setup"
129
+ end
130
+ end
131
+ end
3
132
  end
4
133
  end
data/lib/cartoonist.rb CHANGED
@@ -1,3 +1,239 @@
1
1
  module Cartoonist
2
+ module Admin
3
+ class Tab
4
+ attr_reader :key, :url, :order
5
+
6
+ @@all = {}
7
+ @@cached_order = []
8
+
9
+ def initialize(key, options)
10
+ @key = key
11
+ @url = options[:url]
12
+ @order = options[:order]
13
+ end
14
+
15
+ class << self
16
+ def all
17
+ @@cached_order
18
+ end
19
+
20
+ def [](key)
21
+ @@all[key].url
22
+ end
23
+
24
+ def add(key, options)
25
+ @@all[key] = Cartoonist::Admin::Tab.new key, options
26
+ @@cached_order = @@all.values.sort do |a, b|
27
+ if a.order && b.order
28
+ a.order <=> b.order
29
+ elsif a.order && !b.order
30
+ -1
31
+ elsif b.order && !a.order
32
+ 1
33
+ else
34
+ a.key <=> b.key
35
+ end
36
+ end.map &:key
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ class Asset
43
+ @@all = []
44
+ @@included_js = []
45
+
46
+ class << self
47
+ # This does not include javascript files included in
48
+ # application.js. This is purely standalone assets.
49
+ def all
50
+ @@all
51
+ end
52
+
53
+ # Include the following js files into application.js.
54
+ def include_js(*js_files)
55
+ @@included_js.push *js_files
56
+ @@included_js.tap &:uniq!
57
+ end
58
+
59
+ def included_js
60
+ @@included_js
61
+ end
62
+
63
+ def included_js?
64
+ @@included_js.present?
65
+ end
66
+
67
+ def add(*assets)
68
+ @@all.push *assets
69
+ @@all.tap &:uniq!
70
+ end
71
+ end
72
+ end
73
+
74
+ class Backup
75
+ @@all = {}
76
+
77
+ class << self
78
+ def all
79
+ @@all
80
+ end
81
+
82
+ def for(key, &block)
83
+ @@all[key.to_sym] = block
84
+ end
85
+ end
86
+ end
87
+
88
+ class Migration
89
+ @@all = []
90
+
91
+ class << self
92
+ def all
93
+ @@all
94
+ end
95
+
96
+ def add_for(engine)
97
+ add_dirs engine.paths["db/migrate"].existent
98
+ end
99
+
100
+ def add_dirs(*dirs)
101
+ @@all.push *dirs
102
+ @@all.tap &:uniq!
103
+ end
104
+ end
105
+ end
106
+
107
+ class Navigation
108
+ class Link
109
+ attr_reader :preview_url, :class, :label, :title, :order
110
+
111
+ @@all = []
112
+ @@cached_order = []
113
+
114
+ def initialize(options)
115
+ @url = options[:url]
116
+ @preview_url = options[:preview_url]
117
+ @class = options[:class]
118
+ @label = options[:label]
119
+ @title = options[:title]
120
+ @order = options[:order]
121
+ end
122
+
123
+ def url(preview = false)
124
+ if preview && @preview_url
125
+ result = @preview_url
126
+ else
127
+ result = @url
128
+ end
129
+
130
+ if result.kind_of? Proc
131
+ result.call
132
+ else
133
+ result
134
+ end
135
+ end
136
+
137
+ class << self
138
+ def all
139
+ @@cached_order
140
+ end
141
+
142
+ def add(options)
143
+ @@all << Cartoonist::Navigation::Link.new(options)
144
+ @@cached_order = @@all.sort { |x, y| x.order <=> y.order }
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ class Routes
151
+ @@begin = []
152
+ @@middle = []
153
+ @@end = []
154
+
155
+ class << self
156
+ def add_begin(&block)
157
+ @@begin << block
158
+ end
159
+
160
+ def add(&block)
161
+ @@middle << block
162
+ end
163
+
164
+ def add_end(&block)
165
+ @@end << block
166
+ end
167
+
168
+ def load!(instance)
169
+ @@begin.each do |routes|
170
+ instance.instance_exec &routes
171
+ end
172
+
173
+ @@middle.each do |routes|
174
+ instance.instance_exec &routes
175
+ end
176
+
177
+ @@end.each do |routes|
178
+ instance.instance_exec &routes
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ class Sitemap
185
+ @@all = []
186
+
187
+ class << self
188
+ def all
189
+ @@all.map(&:call).flatten
190
+ end
191
+
192
+ def add(&block)
193
+ @@all << block
194
+ end
195
+ end
196
+ end
197
+
198
+ class Theme
199
+ @@all = []
200
+ @@themes = {}
201
+
202
+ class << self
203
+ def all
204
+ @@all
205
+ end
206
+
207
+ def add(theme, options)
208
+ (@@all << theme.to_sym).sort! unless @@all.include? theme.to_sym
209
+ @@themes[theme.to_sym] = options unless @@themes.include? theme.to_sym
210
+ end
211
+
212
+ def add_assets(*assets)
213
+ Cartoonist::Asset.add *assets
214
+ end
215
+
216
+ def [](key)
217
+ @@themes[key.to_sym] || {}
218
+ end
219
+
220
+ def current
221
+ self[Setting[:theme]]
222
+ end
223
+
224
+ def favicon
225
+ current[:favicon]
226
+ end
227
+
228
+ def css
229
+ current[:css]
230
+ end
231
+
232
+ def rss_logo
233
+ current[:rss_logo]
234
+ end
235
+ end
236
+ end
237
+
2
238
  require "cartoonist/engine"
3
239
  end
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Something's missing (404)</title>
5
+ </head>
6
+
7
+ <body>
8
+ <center>
9
+ <h1>Something's missing...</h1>
10
+ <p>We hope you what you are looking for!</p>
11
+ </center>
12
+ </body>
13
+ </html>
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Rejected! (422)</title>
5
+ </head>
6
+
7
+ <body>
8
+ <h1>Rejected!</h1>
9
+ <p>Sorry, please don't try again.</p>
10
+ </body>
11
+ </html>
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Internal error (500)</title>
5
+ </head>
6
+
7
+ <body>
8
+ <center>
9
+ <h1>Internal error!</h1>
10
+ <p>Something went wrong... we are sorry!</p>
11
+ </center>
12
+ </body>
13
+ </html>