rffw 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+