rffw 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.
Files changed (55) hide show
  1. data/.gitignore +5 -0
  2. data/.rvmrc +1 -0
  3. data/Gemfile +4 -0
  4. data/README.md +60 -0
  5. data/Rakefile +41 -0
  6. data/bin/rffw +16 -0
  7. data/lib/rffw.rb +7 -0
  8. data/lib/rffw/app.rb +36 -0
  9. data/lib/rffw/app/app_handler.rb +59 -0
  10. data/lib/rffw/app/data/images/bg.png +0 -0
  11. data/lib/rffw/app/data/index.html +56 -0
  12. data/lib/rffw/app/data/javascripts/application.js +110 -0
  13. data/lib/rffw/app/data/stylesheets/style.css +338 -0
  14. data/lib/rffw/app/data/template.html +42 -0
  15. data/lib/rffw/app/db.rb +19 -0
  16. data/lib/rffw/app/description_handler.rb +12 -0
  17. data/lib/rffw/app/dir_handler.rb +36 -0
  18. data/lib/rffw/app/record.rb +43 -0
  19. data/lib/rffw/app/show_handler.rb +25 -0
  20. data/lib/rffw/app/upload_handler.rb +32 -0
  21. data/lib/rffw/app/upload_status_handler.rb +40 -0
  22. data/lib/rffw/app/urlencode_chars.data +224 -0
  23. data/lib/rffw/app/view_helpers.rb +30 -0
  24. data/lib/rffw/parser.rb +9 -0
  25. data/lib/rffw/parser/http_request.rb +137 -0
  26. data/lib/rffw/parser/http_response.rb +29 -0
  27. data/lib/rffw/parser/mime_parser.rb +46 -0
  28. data/lib/rffw/server.rb +15 -0
  29. data/lib/rffw/server/buffered_client.rb +57 -0
  30. data/lib/rffw/server/client.rb +53 -0
  31. data/lib/rffw/server/http_client.rb +49 -0
  32. data/lib/rffw/server/server.rb +46 -0
  33. data/lib/rffw/version.rb +3 -0
  34. data/rffw.db +0 -0
  35. data/rffw.gemspec +21 -0
  36. data/test/fixtures/image.jpg +0 -0
  37. data/test/fixtures/mime_image.data +0 -0
  38. data/test/fixtures/mime_image.png +0 -0
  39. data/test/fixtures/post_form_data.http +14 -0
  40. data/test/fixtures/raw_request.txt +8 -0
  41. data/test/fixtures/request.http +9 -0
  42. data/test/fixtures/upload.http +0 -0
  43. data/test/fixtures/upload_status_request.http +10 -0
  44. data/test/helper.rb +97 -0
  45. data/test/test_buffered_client.rb +50 -0
  46. data/test/test_client.rb +47 -0
  47. data/test/test_db.rb +21 -0
  48. data/test/test_http_client.rb +26 -0
  49. data/test/test_http_request.rb +52 -0
  50. data/test/test_mime_parser.rb +22 -0
  51. data/test/test_record.rb +49 -0
  52. data/test/test_upload_status_handler.rb +18 -0
  53. data/test/test_uploader_handler.rb +10 -0
  54. data/test/test_view_helpers.rb +24 -0
  55. metadata +122 -0
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .DS_Store
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rffw.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ RFFW
2
+ ====
3
+
4
+ Recive File From Web Server
5
+
6
+
7
+ USAGE
8
+ =====
9
+
10
+ rffw [(--port|-p) 8080] [(-l|--listen) 127.0.0.1]
11
+
12
+
13
+ INTERNALS
14
+ =========
15
+
16
+ * HTML:
17
+ _ There is two forms. One for description, and one for the input file.
18
+ - #input_file_submit.onchange => submit with form[target=hidden_iframe]
19
+ - On load, generate a random uuid, and assign that uuid to the input and
20
+ description.
21
+ - Delay each upload progress check 20 ms after the last one check.
22
+ - There is no index view.
23
+ - There seems to be a bug, that causes google chrome to upload the same file
24
+ twice at the same time.
25
+
26
+ * Server (Just a mini abstraction of kernel.select and socket)
27
+ - Server: Kernel.select.
28
+ - Client: Kind of overload Socket through delegation.
29
+ - BufferedClient: Overloads Client to add cache in disk the requests.
30
+ - HttpClient: Overloads BufferedClient to understand http connections.
31
+
32
+ * App
33
+ - AppHandler: Overloads HttpClient, and acts as an app router.
34
+ - (DescriptionHandler | ShowHandler | UploadHandler | UploadStatusHandler |
35
+ DirHandler: Like http actions. They are modules included in AppHandler.
36
+ - ViewHelpers.
37
+ - data: html/js/css/img
38
+ - Db: Overloads DBM. Used as a backend.
39
+ - Record: Abstraction of Db.
40
+ * Parser
41
+ - HttpRequest: StringScanner http request parsers.
42
+ - HttpRespone: Well... not a parser it self, it generate http responses.
43
+ - MimeParser: Process Mime attachments.
44
+
45
+ USED LIBRARIES
46
+ ==============
47
+
48
+ * Ruby: TempDir
49
+ * Ruby: TCPServer
50
+ * Ruby: TCPClient
51
+ * Ruby: Kernel.select
52
+
53
+
54
+ TEST
55
+ ====
56
+ * The tests, that not cover the full code, were just used as a tool for
57
+ helping me to develop the code itself. More were written before the code.
58
+
59
+
60
+
data/Rakefile ADDED
@@ -0,0 +1,41 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << "test"
7
+ t.test_files = FileList['test/test*.rb']
8
+ t.verbose = false
9
+ end
10
+
11
+ task :default do
12
+
13
+ begin
14
+ require 'rubygems'
15
+ gem 'minitest'
16
+ require 'minitest/pride'
17
+ rescue LoadError, Gem::LoadError
18
+ $stderr.puts "Minitest gem not found. Usign ruby minitest."
19
+ end
20
+
21
+ base = File.expand_path("..", __FILE__)
22
+ $:.unshift File.join(base,"lib")
23
+ $:.unshift File.join(base,'test')
24
+ Dir[File.expand_path("../test/test_*", __FILE__)].each{|f| require f}
25
+ MiniTest::Unit.autorun
26
+
27
+ end
28
+
29
+ desc "Run the server"
30
+ task :run do
31
+ exec("ruby -rubygems -I lib bin/rffw")
32
+ end
33
+
34
+
35
+ task :commit do
36
+ system("git add . && git commit -m 'WIP' && git push origin master:master")
37
+ end
38
+
39
+ task :deploy => [:commit] do
40
+ system(%{ssh soundcloud "sudo su - guillermo ; cd rffw && git pull && sudo killall "})
41
+ end
data/bin/rffw ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rffw'
4
+
5
+ params = ARGV.join(" ")
6
+
7
+ port = (params[/((\-\-port|\-p) (\d+))/,3] || 8080).to_i
8
+ listen = (params[/((\-l|\-\-listen) ((\d+)\.(\d+)\.(\d+)\.(\d+)))/,3] || "0.0.0.0").to_i
9
+
10
+ if params[/(-h|--help)/]
11
+ $stderr.puts "#{$0} [(-p|--port) port_number] [(-l|--listen) ip]"
12
+ $stderr.puts ""
13
+ exit(-1)
14
+ end
15
+
16
+ RFFW::App.start(port,listen)
data/lib/rffw.rb ADDED
@@ -0,0 +1,7 @@
1
+ require "rffw/version"
2
+
3
+ module RFFW
4
+ autoload(:Server, 'rffw/server')
5
+ autoload(:App, 'rffw/app')
6
+ autoload(:Parser, 'rffw/parser')
7
+ end
data/lib/rffw/app.rb ADDED
@@ -0,0 +1,36 @@
1
+
2
+ module RFFW
3
+ module App
4
+ require 'rffw/app/db'
5
+ require 'rffw/app/record'
6
+
7
+ require 'rffw/app/view_helpers'
8
+ require 'rffw/app/upload_handler'
9
+ require 'rffw/app/upload_status_handler'
10
+ require 'rffw/app/dir_handler'
11
+ require 'rffw/app/description_handler'
12
+ require 'rffw/app/show_handler'
13
+
14
+ require 'rffw/app/app_handler'
15
+
16
+ def self.start(port = 8080, listen = "127.0.0.1", dir = Dir.pwd)
17
+ trap("SIGINT") { throw :ctrl_c }
18
+ @@dir = dir
19
+ start_db(@@dir)
20
+ server = RFFW::Server::Server.new( RFFW::App::AppHandler, port, listen )
21
+ end
22
+
23
+ def self.start_db(dir)
24
+ @@db = Db.new(File.join(dir,'rffw'))
25
+ end
26
+
27
+ def self.db
28
+ @@db
29
+ end
30
+
31
+ def self.dir
32
+ @@dir
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,59 @@
1
+ module RFFW::App
2
+ class AppHandler < RFFW::Server::HttpClient
3
+ include RFFW::Server
4
+ include RFFW::App::DirHandler
5
+ include RFFW::App::UploadHandler
6
+ include RFFW::App::UploadStatusHandler
7
+ include RFFW::App::DescriptionHandler
8
+ include RFFW::App::ShowHandler
9
+
10
+ attr_reader :request
11
+
12
+ def on_data
13
+ super
14
+ if request && request.post? && request.path == '/upload'
15
+ memory_usage = `ps -o rss= -p #{$$}`.to_i
16
+ $stderr.puts "[#{memory_usage}kB] #{Time.now.utc} #{fileno} (#{self.class.all.size}) UPLOADING A FILE: #{request.upload_progress}"
17
+ end
18
+ end
19
+
20
+ def on_request(r)
21
+ memory_usage = `ps -o rss= -p #{$$}`.to_i
22
+ $stderr.puts "[#{memory_usage}Kb] #{Time.now.utc} #{fileno} (#{self.class.all.size}) > <#{r.inspect}>"
23
+
24
+ response = case
25
+ when ! %w(get post).include?(r.method.downcase)
26
+ HttpResponse.new("Sorry! Method not allowed.", 405)
27
+ when r.method.downcase == 'get' && r.path == '/upload_status.js'
28
+ upload_status_handle(r)
29
+ when r.method.downcase == "post" && r.path == '/upload'
30
+ upload_handle(r)
31
+ when r.method.downcase == "post" && r.path == '/description'
32
+ description_handle(r)
33
+ when r.method.downcase == 'get' && r.path == '/show'
34
+ show_handle(r)
35
+ when r.method.downcase == "get"
36
+ dir_handle(r)
37
+ else
38
+ HttpResponse.new("No no no... Not found !", 404)
39
+ end
40
+ write response
41
+
42
+ rescue => e
43
+ $stderr.puts "#{e.message}\r\n#{e.inspect}\r\n#{e.backtrace.join("\n")}"
44
+ write HttpResponse.new("#{e.message}\r\n#{e.inspect}\r\n#{e.backtrace.join("\n")}", 505)
45
+ ensure
46
+ cleanup!
47
+ end
48
+
49
+ def cleanup!
50
+ disconeect! unless request.keep_alive?
51
+ @request = HttpRequest.new('')
52
+ clear_buffer
53
+ end
54
+
55
+ end
56
+ end
57
+
58
+
59
+
Binary file
@@ -0,0 +1,56 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <meta name="description" content="Recive files from webserver">
8
+ <meta name="author" content="Guillermo Álvarez Fernández <guillermo@cientifico.net>">
9
+
10
+ <title>rffw</title>
11
+
12
+ <link href='http://fonts.googleapis.com/css?family=Josefin+Sans:light,lightitalic,regular,regularitalic,bold&amp;v1' rel='stylesheet' type='text/css'>
13
+ <link href='http://fonts.googleapis.com/css?family=The+Girl+Next+Door&amp;v1' rel='stylesheet' type='text/css'>
14
+
15
+ <link rel="stylesheet" href="/stylesheets/style.css?v=2">
16
+ <script type="text/javascript" charset="utf-8" src="/javascripts/application.js"></script>
17
+
18
+ <style>
19
+
20
+ </style>
21
+ </head>
22
+ <body>
23
+
24
+ <div id="wrapper">
25
+
26
+ <header>
27
+ <h1>rffw</h1>
28
+ <h2>Recive files from webserver</h2>
29
+ </header>
30
+ <section class="center">
31
+ <p>
32
+ <form enctype="multipart/form-data" action="/upload" target="uploader" method="post" id="uploader_form">
33
+ <label>Select a file to upload
34
+ <input type="file" id="file_input" name="file" tabindex=1>
35
+ </label>
36
+ </form>
37
+ <iframe id="uploader" name="uploader"></iframe>
38
+ <p id="progress_bar">
39
+ <span id="porcentage">The progress is <b id="total_uploaded">80%</b>.</span>
40
+ </p>
41
+ <form action="/description" method="post" id="description_form">
42
+ <label>Description
43
+ <textarea name="description" placeholder="Write here a description" tabindex=2></textarea>
44
+ </label>
45
+ <input type="submit" value="Send the file" tabindex=3>
46
+ </form>
47
+ </p>
48
+ </section>
49
+ <div id="push"></div>
50
+ </div>
51
+
52
+ <footer>
53
+ <p>You can conact me at <a href="mailto:guillermo@cientifico.net">guillermo@cientifico.net</a>.</p>
54
+ </footer>
55
+ </body>
56
+ </html>
@@ -0,0 +1,110 @@
1
+ (function(){
2
+
3
+
4
+
5
+
6
+ Element.prototype.css = function(object){
7
+ for(property in object){
8
+ this.style.setProperty(property, object[property]);
9
+ }
10
+ };
11
+
12
+ Element.prototype.toggle = function(){
13
+ if (window.getComputedStyle(this, 'display') == "none"){
14
+ this.show();
15
+ } else {
16
+ this.hide();
17
+ }
18
+ };
19
+
20
+
21
+ Element.prototype.show = function(){
22
+ this.style.setProperty("display", "block");
23
+ };
24
+
25
+ Element.prototype.hide = function(){
26
+ this.style.setProperty("display", "none");
27
+ };
28
+
29
+
30
+ window.info = function(message){
31
+ var hover = document.getElementById('drop_the_file');
32
+ if (message == undefined){
33
+ hover.classList.remove("show");
34
+
35
+ }else{
36
+ hover.innerHTML = message;
37
+ hover.classList.add("show");
38
+ }
39
+ }
40
+ window.onload = function(){
41
+
42
+ function S4() {
43
+ return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
44
+ }
45
+ function new_guid(){
46
+ return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
47
+ }
48
+
49
+ document.getElementById("progress_bar").css({"display": "none"});
50
+
51
+
52
+ window.uuid = new_guid();
53
+
54
+ form = document.getElementById("uploader_form")
55
+ form.action = form.action+"?"+window.uuid;
56
+
57
+ description_form = document.getElementById("description_form")
58
+ description_form.action = description_form.action+"?"+window.uuid;
59
+
60
+ function check_status(){
61
+ setTimeout(function(){
62
+ var req = new XMLHttpRequest();
63
+ req.open('GET', '/upload_status.js?'+window.uuid, true);
64
+ req.onreadystatechange = function (aEvt) {
65
+ if (req.readyState == 4) {
66
+ if(req.status == 200){
67
+
68
+ record = JSON.parse(req.responseText);
69
+ if (record.progress){
70
+ var progress = record.progress.split("/");
71
+ d(progress)
72
+ var total = parseInt(progress[1]);
73
+ var partial = parseInt(progress[0]);
74
+ var porcentage = (100 * partial / total).toFixed();
75
+ if (porcentage > 100) porcentage = 100;
76
+
77
+ document.getElementById("porcentage").css({'width': porcentage+'%'});
78
+ document.getElementById("total_uploaded").innerHTML = porcentage+'%';
79
+ check_status();
80
+ } else {
81
+ document.getElementById("porcentage").css({'width': '100%'});
82
+ document.getElementById("total_uploaded").innerHTML = "Uploaded!"
83
+ }
84
+ }
85
+ else {
86
+ d("Error loading page\n");
87
+ }
88
+ }
89
+ };
90
+ req.send(null);
91
+ }, 200);
92
+ }
93
+
94
+ form.onchange = function(){
95
+ form.submit();
96
+ document.getElementById("file_input").css({"display": "none"});
97
+ document.getElementById("progress_bar").css({"display": "block"});
98
+ check_status();
99
+ };
100
+
101
+ window.d = function(msg){
102
+ window.console.debug(msg)
103
+ }
104
+
105
+
106
+
107
+
108
+ }
109
+
110
+ })();
@@ -0,0 +1,338 @@
1
+ /* @override http://localhost:8080/stylesheets/style.css?v=2 */
2
+
3
+ * {
4
+ font-family: 'Josefin Sans', arial, serif;
5
+ line-height: 16px;
6
+ font-size: 14px;
7
+ margin: 0;
8
+ padding: 0;
9
+ color: #002f2f;
10
+ font-weight: 300;
11
+ }
12
+
13
+ a {
14
+ -webkit-transition: all 0.2s ease-in-out;
15
+ -moz-transition: all 0.2s ease-in-out;
16
+ -o-transition: all 0.2s ease-in-out;
17
+ transition: all 0.2s ease-in-out;
18
+ }
19
+
20
+ html, body {
21
+ background: url("/images/bg.png"), #a7a37e;
22
+ height: 100%;
23
+ }
24
+
25
+ h1 {
26
+ font-family: 'The Girl Next Door', arial, serif;
27
+ }
28
+
29
+ header {
30
+ margin: 0 auto;
31
+ text-align: center;
32
+ display: block;
33
+ overflow: hidden;
34
+ padding-bottom: 12px;
35
+ }
36
+ header h1 {
37
+ padding-left: 12.5%;
38
+ padding-right: 12.5%;
39
+ font-size: 56px;
40
+ line-height: px;
41
+ margin-top: 32px;
42
+ }
43
+ header h2 {
44
+ font-size: 16px;
45
+ line-height: 16px;
46
+ color: #efecca;
47
+ }
48
+
49
+ #progress_bar {
50
+ background: red ;
51
+ width: 317px;
52
+ height: 39px;
53
+ margin: 0 auto;
54
+
55
+ -webkit-border-radius: 10px;
56
+ -moz-border-radius: 10px;
57
+ border-radius: 10px;
58
+
59
+ background: white;
60
+ background: white;
61
+ padding: 0;
62
+ position: relative;
63
+ }
64
+
65
+ #progress_bar span{
66
+ display: block;
67
+ background: #002f2f;
68
+ height: 39px;
69
+ width: 50%;
70
+ -webkit-border-radius: 10px;
71
+ -moz-border-radius: 10px;
72
+ border-radius: 10px;
73
+
74
+ transition: width 1s linear;
75
+
76
+ line-height: 200px;
77
+ overflow: hidden;
78
+ }
79
+
80
+ #progress_bar {
81
+ display: none;
82
+ }
83
+ #progress_bar span b{
84
+ position: absolute;
85
+ top: 0;
86
+ left: 0;
87
+ width: 317px;
88
+ text-align:center;
89
+ line-height: 39px;
90
+ vertical-align:middle;
91
+ font-size: 24px;
92
+ font-weight:bold;
93
+ text-shadow: white 0px 0px 2px;
94
+ }
95
+ /* Sticky Background */
96
+ #wrapper {
97
+ min-height: 100%;
98
+ height: auto !important;
99
+ height: 100%;
100
+ margin: 0 auto -112px;
101
+ }
102
+
103
+ footer, push {
104
+ height: 80px;
105
+ overflow: hidden;
106
+ }
107
+
108
+ /* end */
109
+ section {
110
+ display: block;
111
+ margin: 0 auto;
112
+ }
113
+ section.center {
114
+ max-width: 480px;
115
+ padding: 16px 80px;
116
+ position: relative;
117
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #efecca), color-stop(1, #a7a37e));
118
+ background: -moz-linear-gradient(top, #efecca, #a7a37e);
119
+ filter: progid:DXImageTransform.Microsoft.Gradient(endColorstr='$bg1', startColorstr='$bg2', gradientType='0');
120
+ text-align: center;
121
+ }
122
+ section.center h1 {
123
+ text-align: center;
124
+ font-size: 48px;
125
+ line-height: 48px;
126
+ }
127
+ section.center p {
128
+ text-align: justify;
129
+ font-size: 16px;
130
+ margin-bottom: 16px;
131
+ font-weight: 500;
132
+ text-shadow: #a7a37e 0.5px 0.5px 1px;
133
+ }
134
+ section.center p em {
135
+ font-weight: normal;
136
+ }
137
+ section.center p strong a, section.center p strong {
138
+ font-weight: 700;
139
+ }
140
+ section.center p a:active, section.center p a:focus {
141
+ background: #002f2f;
142
+ color: #a7a37e;
143
+ outline: 0;
144
+ text-decoration: none;
145
+ text-shadow: none;
146
+ }
147
+ section.center p a:hover {
148
+ text-decoration: none;
149
+ }
150
+ section.center img {
151
+ text-align: center;
152
+ display: block;
153
+ }
154
+ section.center h2 {
155
+ text-align: center;
156
+ font-size: 32px;
157
+ line-height: 32px;
158
+ }
159
+ section.list, section.posts {
160
+ background: url(/images/bg.png), #002f2f;
161
+ max-width: 100%;
162
+ padding: 32px 0 0;
163
+ text-align: center;
164
+ }
165
+ section.list h1, section.posts h1 {
166
+ color: #046380;
167
+ letter-spacing: 10px;
168
+ margin: 16px 0;
169
+ }
170
+ section.wide {
171
+ background: url(/images/bg.png), #002f2f;
172
+ width: 100%;
173
+ padding: 32px 0;
174
+ }
175
+ section.wide a {
176
+ color: #a7a37e;
177
+ }
178
+ section.wide > ul {
179
+ margin: 0 auto;
180
+ list-style: none;
181
+ text-align: center;
182
+ }
183
+ section.wide > ul li {
184
+ width: 320px;
185
+ vertical-align: top;
186
+ display: inline-block;
187
+ padding: 0 10px;
188
+ }
189
+ section.wide > ul li h1 {
190
+ text-align: center;
191
+ font-weight: 300;
192
+ margin-bottom: 32px;
193
+ }
194
+ section.wide > ul li h1 > a {
195
+ font-size: 40px;
196
+ line-height: 48px;
197
+ color: #046380;
198
+ text-decoration: none;
199
+ }
200
+ section.wide > ul li ul li {
201
+ margin-bottom: 8px;
202
+ }
203
+ section.wide > ul li ul, section.wide > ul li ul li, section.wide > ul li ul li a {
204
+ text-align: left;
205
+ font-size: 14px;
206
+ text-decoration: none;
207
+ color: #e6e2af;
208
+ }
209
+
210
+ #links, #posts {
211
+ max-width: 1040px;
212
+ list-style: none;
213
+ display: inline-block;
214
+ }
215
+ #links li, #posts li {
216
+ display: inline-block;
217
+ text-align: center;
218
+ }
219
+ #links a, #posts a {
220
+ text-decoration: none;
221
+ color: #e6e2af;
222
+ }
223
+ #links a:hover, #posts a:hover {
224
+ color: #a7a37e;
225
+ }
226
+
227
+ #links li {
228
+ width: 160px;
229
+ }
230
+
231
+ #posts li {
232
+ width: 240px;
233
+ }
234
+
235
+ em {
236
+ font-style: italic;
237
+ }
238
+
239
+ strong {
240
+ font-weight: 700;
241
+ }
242
+
243
+ footer {
244
+ background: url(/images/bg.png), #002f2f;
245
+ max-width: 100%;
246
+ padding: 32px 0 0;
247
+ text-align: center;
248
+ color: #a7a37e;
249
+ }
250
+ footer p {
251
+ padding: 32px 0;
252
+ }
253
+ footer a, footer p {
254
+ color: #a7a37e;
255
+ text-decoration: none;
256
+ }
257
+ footer a:hover {
258
+ color: #a7a37e;
259
+ }
260
+
261
+
262
+ iframe {
263
+ border: 0;
264
+ background: transparent;
265
+ }
266
+
267
+ section.center form {
268
+ font-size: 24px !important;
269
+ text-align: center;
270
+ }
271
+ section.center label {
272
+ font-size: 24px;
273
+ line-height: 36px;
274
+ text-align: center;
275
+ overflow:hidden;
276
+ }
277
+
278
+ section.center input{
279
+ font-size: 24px;
280
+ margin: 0 auto;
281
+ }
282
+ section.center input[type=file],
283
+ section.center textarea{
284
+ width: 300px;
285
+ background: white;
286
+ padding: 9px 5px 9px 12px;
287
+ line-height: 18px;
288
+ -webkit-border-radius: 10px;
289
+ -moz-border-radius: 10px;
290
+ border-radius: 10px;
291
+
292
+ border: 0px;
293
+ }
294
+
295
+
296
+ section.center input[type=file]:focus,
297
+ section.center textarea:focus{
298
+ border: 1px solid #002f2f;
299
+ outline: none;
300
+ margin: -1px;
301
+ }
302
+
303
+
304
+ section.center textarea{
305
+ width: 100%;
306
+ font-size: 24px;
307
+ height: 240px;
308
+ padding: 6px 5px;
309
+ line-height: 36px;
310
+ }
311
+
312
+ section.center iframe {
313
+ width: 0;
314
+ height: 0;
315
+ overflow: hidden;
316
+ }
317
+
318
+ section.center input[type=submit] {
319
+ width: 180px;
320
+ height: 40px;
321
+ padding: 20px;
322
+ margin: 24px 10px;
323
+ }
324
+ @media (max-width:640px) {
325
+ section.center {
326
+ padding: 16px 12.5%;
327
+ width: inherit;
328
+ max-width: inherit;
329
+ }
330
+ section.center img {
331
+ width: 100%;
332
+ }
333
+
334
+ }
335
+
336
+
337
+
338
+