gnucash-invoice 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,44 @@
1
+ # GnuCash::Invoice
2
+
3
+ GnuCash invoice printer for human beings.
4
+
5
+
6
+ ## Installation
7
+
8
+ $ gem install gnucash-invoice
9
+
10
+
11
+ ## Usage
12
+
13
+ GnuCash invoice printer currently supports SQLite and the usage is dead simple.
14
+ List all invoices that can be printed:
15
+
16
+ $ gnucash-invoice --dbpath /path/to/db.sqlite3
17
+
18
+ #00004 Customer A (2012-11-24)
19
+ #00005 Customer B (2012-11-24)
20
+ ...
21
+
22
+ Print out invoice by it's number:
23
+
24
+ $ gnucash-invoice --dbpath /path/to/db.sqlite3 00004 > invoice-00004.html
25
+
26
+
27
+ ## TODO
28
+
29
+ * TESTS!!!
30
+ * Fix models backend to allow specify db host:port
31
+ * ??? Add backend for old-school XML format
32
+ * Use currency from an account book instead of hardcoded
33
+ * ??? Export into FreshBooks
34
+ * Built-in several templates
35
+ * Allow specify foot notice (using markdown)
36
+
37
+
38
+ ## Contributing
39
+
40
+ 1. Fork it
41
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
42
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
43
+ 4. Push to the branch (`git push origin my-new-feature`)
44
+ 5. Create new Pull Request
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+ $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
5
+
6
+
7
+ require 'gnucash/invoice'
8
+ GnuCash::Invoice::Runner.run ARGV
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/gnucash/invoice/version', __FILE__)
3
+
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = "gnucash-invoice"
7
+ gem.version = GnuCash::Invoice::VERSION
8
+ gem.homepage = "http://ixti.github.com/gnucash-invoice"
9
+ gem.authors = %w{Aleksey V Zapparov}
10
+ gem.email = %w{ixti@member.fsf.org}
11
+ gem.summary = "gnucash-invoice-#{GnuCash::Invoice::VERSION}"
12
+ gem.description = %q{GnuCash invoice printer for human beings.}
13
+
14
+ gem.add_dependency "sequel", "~> 3.41"
15
+ gem.add_dependency "slim", "~> 1.3"
16
+ gem.add_dependency 'sass', '~> 3.2'
17
+ gem.add_dependency "sprockets", "~> 2.8"
18
+
19
+ gem.add_development_dependency "sqlite3"
20
+ gem.add_development_dependency "rake"
21
+
22
+ gem.files = `git ls-files`.split($\)
23
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
24
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
25
+
26
+ gem.require_paths = ["lib"]
27
+ end
@@ -0,0 +1,26 @@
1
+ # 3rd-party
2
+ require 'sequel'
3
+
4
+
5
+ # internal
6
+ require 'gnucash/timestamps'
7
+
8
+
9
+ module GnuCash
10
+ class NoDatabaseConnection < StandardError; end
11
+
12
+
13
+ def self.connection
14
+ @connection or raise NoDatabaseConnection
15
+ end
16
+
17
+
18
+ def self.connect! db
19
+ @connection = Sequel.connect "sqlite://#{db}"
20
+ end
21
+
22
+
23
+ def self.root
24
+ @root ||= Pathname.new File.realpath(File.join(__FILE__, '../..'))
25
+ end
26
+ end
@@ -0,0 +1,85 @@
1
+ # internal
2
+ require 'gnucash'
3
+ require 'gnucash/invoice/version'
4
+ require 'gnucash/invoice/entry'
5
+ require 'gnucash/invoice/customer'
6
+ require 'gnucash/invoice/supplier'
7
+ require 'gnucash/invoice/printer'
8
+ require 'gnucash/invoice/runner'
9
+
10
+
11
+ module GnuCash
12
+ class Invoice
13
+ class InvoiceNotFound < StandardError; end
14
+
15
+
16
+ include Timestamps
17
+
18
+
19
+ attr_reader :raw, :id, :opened_at, :posted_at, :notes
20
+
21
+
22
+ def initialize data
23
+ @raw = data
24
+
25
+ @id = data[:id]
26
+ @opened_at = from_timestamp data[:date_opened]
27
+ @posted_at = from_timestamp data[:date_posted]
28
+ @notes = data[:notes]
29
+ end
30
+
31
+
32
+ def posted?
33
+ posted_at.is_a? DateTime
34
+ end
35
+
36
+
37
+ def customer
38
+ @customer ||= Customer.find @raw[:owner_guid]
39
+ end
40
+
41
+
42
+ def entries
43
+ @entries ||= Entry.find @raw[:guid]
44
+ end
45
+
46
+
47
+ def total
48
+ entries.inject(0){ |memo,entry| memo + entry.total }
49
+ end
50
+
51
+
52
+ def to_s
53
+ open_date = "(#{opened_at.strftime '%Y/%m/%d'})"
54
+ post_date = ""
55
+
56
+ if posted?
57
+ post_date = "[#{posted_at.strftime '%Y/%m/%d'}]"
58
+ end
59
+
60
+ "%-16s %-32s %s %s" % [ id, customer.name, open_date, post_date ]
61
+ end
62
+
63
+
64
+ def self.all
65
+ dataset.map{ |data| new(data) }
66
+ end
67
+
68
+
69
+ def self.find id
70
+ unless data = dataset.where(:id => id).first
71
+ raise InvoiceNotFound, "ID: #{id}"
72
+ end
73
+
74
+ new(data)
75
+ end
76
+
77
+
78
+ private
79
+
80
+
81
+ def self.dataset
82
+ GnuCash.connection[:invoices].where(:owner_type => 2)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,51 @@
1
+ module GnuCash
2
+ class Invoice
3
+ class Customer
4
+ class CustomerNotFound < StandardError; end
5
+
6
+
7
+ include Timestamps
8
+
9
+
10
+ attr_reader :id, :name
11
+
12
+
13
+ def initialize data
14
+ @raw = data
15
+
16
+ @id = data[:id]
17
+ @name = data[:name]
18
+ end
19
+
20
+
21
+ def address_lines
22
+ @address_lines ||= [].tap do |lines|
23
+ (1..4).each do |i|
24
+ id = :"addr_addr#{i}"
25
+ lines << @raw[id] if @raw[id]
26
+ end
27
+ end
28
+ end
29
+
30
+
31
+ alias :to_s :name
32
+
33
+
34
+ def self.find guid
35
+ unless data = dataset.where(:guid => guid).first
36
+ raise CustomerNotFound, "GUID: #{guid}"
37
+ end
38
+
39
+ new(data)
40
+ end
41
+
42
+
43
+ private
44
+
45
+
46
+ def self.dataset
47
+ GnuCash.connection[:customers]
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,39 @@
1
+ module GnuCash
2
+ class Invoice
3
+ class Entry
4
+ include Timestamps
5
+
6
+
7
+ attr_reader :raw, :date, :description, :action, :quantity, :price
8
+
9
+
10
+ def initialize data
11
+ @raw = data
12
+
13
+ @date = from_timestamp(data[:date]).to_date
14
+ @description = data[:description]
15
+ @action = data[:action]
16
+ @quantity = data[:quantity_num].to_f / data[:quantity_denom]
17
+ @price = data[:i_price_num].to_f / data[:i_price_denom]
18
+ end
19
+
20
+
21
+ def total
22
+ price * quantity
23
+ end
24
+
25
+
26
+ def self.find invoice_guid
27
+ dataset.where(:invoice => invoice_guid).map{ |data| new(data) }
28
+ end
29
+
30
+
31
+ private
32
+
33
+
34
+ def self.dataset
35
+ GnuCash.connection[:entries]
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,46 @@
1
+ require 'slim'
2
+ require 'sass'
3
+ require 'sprockets'
4
+
5
+
6
+ module GnuCash
7
+ class Invoice
8
+ class Printer
9
+ def initialize invoice_id
10
+ @invoice = Invoice.find(invoice_id)
11
+ end
12
+
13
+
14
+ def embedded_asset pathname
15
+ environment[pathname].to_s
16
+ end
17
+
18
+
19
+ def environment
20
+ @environment ||= Sprockets::Environment.new(template_dir).tap do |env|
21
+ env.append_path 'assets/stylesheets'
22
+ env.css_compressor = :sass
23
+ end
24
+ end
25
+
26
+
27
+ def render
28
+ template = Slim::Template.new template_dir('invoice.slim').to_s
29
+ template.render(self, {
30
+ :invoice => @invoice,
31
+ :entries => @invoice.entries,
32
+ :customer => @invoice.customer
33
+ })
34
+ end
35
+
36
+
37
+ protected
38
+
39
+
40
+ def template_dir *args
41
+ args.unshift 'templates'
42
+ GnuCash.root.join(*args)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,52 @@
1
+ # stdlib
2
+ require 'ostruct'
3
+ require 'optparse'
4
+ require 'pathname'
5
+
6
+
7
+ module GnuCash
8
+ class Invoice
9
+ module Runner
10
+ class InvalidArguments < StandardError; end
11
+
12
+
13
+ def self.run argv
14
+ options = parse argv
15
+
16
+ GnuCash.connect! options.dbpath
17
+
18
+ # Print out invoice
19
+ unless argv.empty?
20
+ puts Printer.new(options.invoice_id).render
21
+ exit
22
+ end
23
+
24
+ # Show known invoices
25
+ Invoice.all.each do |invoice|
26
+ puts invoice
27
+ end
28
+ end
29
+
30
+
31
+ protected
32
+
33
+
34
+ def self.parse argv
35
+ options = OpenStruct.new
36
+
37
+ OptionParser.new do |opts|
38
+ opts.on('-d', '--dbpath [DATABASE]', 'SQLite database path') do |path|
39
+ options.dbpath = Pathname.new path
40
+ end
41
+ end.parse! argv
42
+
43
+ raise InvalidArguments, "No database selected" unless options.dbpath
44
+ raise InvalidArguments, "Can't find specified database" unless options.dbpath.exist?
45
+
46
+ options.invoice_id = argv.first
47
+
48
+ options
49
+ end
50
+ end
51
+ end
52
+ end
File without changes
@@ -0,0 +1,5 @@
1
+ module GnuCash
2
+ class Invoice
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,23 @@
1
+ module GnuCash
2
+ module Timestamps
3
+ FORMAT = "%Y%m%d%H%M%S"
4
+
5
+
6
+ def from_timestamp value
7
+ case value
8
+ when ::DateTime then value
9
+ when ::Numeric, /\A\d+\z/ then parse value.to_s
10
+ when ::String, /\A\d+\z/ then parse value
11
+ end
12
+ end
13
+
14
+
15
+ private
16
+
17
+
18
+ def parse str
19
+ ::DateTime.strptime str, FORMAT
20
+ end
21
+ end
22
+ end
23
+
@@ -0,0 +1,907 @@
1
+ /*!
2
+ * Bootstrap v2.2.1
3
+ *
4
+ * Copyright 2012 Twitter, Inc
5
+ * Licensed under the Apache License v2.0
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
9
+ */
10
+ .clearfix {
11
+ *zoom: 1;
12
+ }
13
+ .clearfix:before,
14
+ .clearfix:after {
15
+ display: table;
16
+ content: "";
17
+ line-height: 0;
18
+ }
19
+ .clearfix:after {
20
+ clear: both;
21
+ }
22
+ .hide-text {
23
+ font: 0/0 a;
24
+ color: transparent;
25
+ text-shadow: none;
26
+ background-color: transparent;
27
+ border: 0;
28
+ }
29
+ .input-block-level {
30
+ display: block;
31
+ width: 100%;
32
+ min-height: 30px;
33
+ -webkit-box-sizing: border-box;
34
+ -moz-box-sizing: border-box;
35
+ box-sizing: border-box;
36
+ }
37
+ body {
38
+ margin: 0;
39
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
40
+ font-size: 14px;
41
+ line-height: 20px;
42
+ color: #333333;
43
+ background-color: #ffffff;
44
+ }
45
+ a {
46
+ color: #0088cc;
47
+ text-decoration: none;
48
+ }
49
+ a:hover {
50
+ color: #005580;
51
+ text-decoration: underline;
52
+ }
53
+ .img-rounded {
54
+ -webkit-border-radius: 6px;
55
+ -moz-border-radius: 6px;
56
+ border-radius: 6px;
57
+ }
58
+ .img-polaroid {
59
+ padding: 4px;
60
+ background-color: #fff;
61
+ border: 1px solid #ccc;
62
+ border: 1px solid rgba(0, 0, 0, 0.2);
63
+ -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
64
+ -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
65
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
66
+ }
67
+ .img-circle {
68
+ -webkit-border-radius: 500px;
69
+ -moz-border-radius: 500px;
70
+ border-radius: 500px;
71
+ }
72
+ .row {
73
+ margin-left: -20px;
74
+ *zoom: 1;
75
+ }
76
+ .row:before,
77
+ .row:after {
78
+ display: table;
79
+ content: "";
80
+ line-height: 0;
81
+ }
82
+ .row:after {
83
+ clear: both;
84
+ }
85
+ [class*="span"] {
86
+ float: left;
87
+ min-height: 1px;
88
+ margin-left: 20px;
89
+ }
90
+ .container,
91
+ .navbar-static-top .container,
92
+ .navbar-fixed-top .container,
93
+ .navbar-fixed-bottom .container {
94
+ width: 940px;
95
+ }
96
+ .span12 {
97
+ width: 940px;
98
+ }
99
+ .span11 {
100
+ width: 860px;
101
+ }
102
+ .span10 {
103
+ width: 780px;
104
+ }
105
+ .span9 {
106
+ width: 700px;
107
+ }
108
+ .span8 {
109
+ width: 620px;
110
+ }
111
+ .span7 {
112
+ width: 540px;
113
+ }
114
+ .span6 {
115
+ width: 460px;
116
+ }
117
+ .span5 {
118
+ width: 380px;
119
+ }
120
+ .span4 {
121
+ width: 300px;
122
+ }
123
+ .span3 {
124
+ width: 220px;
125
+ }
126
+ .span2 {
127
+ width: 140px;
128
+ }
129
+ .span1 {
130
+ width: 60px;
131
+ }
132
+ .offset12 {
133
+ margin-left: 980px;
134
+ }
135
+ .offset11 {
136
+ margin-left: 900px;
137
+ }
138
+ .offset10 {
139
+ margin-left: 820px;
140
+ }
141
+ .offset9 {
142
+ margin-left: 740px;
143
+ }
144
+ .offset8 {
145
+ margin-left: 660px;
146
+ }
147
+ .offset7 {
148
+ margin-left: 580px;
149
+ }
150
+ .offset6 {
151
+ margin-left: 500px;
152
+ }
153
+ .offset5 {
154
+ margin-left: 420px;
155
+ }
156
+ .offset4 {
157
+ margin-left: 340px;
158
+ }
159
+ .offset3 {
160
+ margin-left: 260px;
161
+ }
162
+ .offset2 {
163
+ margin-left: 180px;
164
+ }
165
+ .offset1 {
166
+ margin-left: 100px;
167
+ }
168
+ .row-fluid {
169
+ width: 100%;
170
+ *zoom: 1;
171
+ }
172
+ .row-fluid:before,
173
+ .row-fluid:after {
174
+ display: table;
175
+ content: "";
176
+ line-height: 0;
177
+ }
178
+ .row-fluid:after {
179
+ clear: both;
180
+ }
181
+ .row-fluid [class*="span"] {
182
+ display: block;
183
+ width: 100%;
184
+ min-height: 30px;
185
+ -webkit-box-sizing: border-box;
186
+ -moz-box-sizing: border-box;
187
+ box-sizing: border-box;
188
+ float: left;
189
+ margin-left: 2.127659574468085%;
190
+ *margin-left: 2.074468085106383%;
191
+ }
192
+ .row-fluid [class*="span"]:first-child {
193
+ margin-left: 0;
194
+ }
195
+ .row-fluid .controls-row [class*="span"] + [class*="span"] {
196
+ margin-left: 2.127659574468085%;
197
+ }
198
+ .row-fluid .span12 {
199
+ width: 100%;
200
+ *width: 99.94680851063829%;
201
+ }
202
+ .row-fluid .span11 {
203
+ width: 91.48936170212765%;
204
+ *width: 91.43617021276594%;
205
+ }
206
+ .row-fluid .span10 {
207
+ width: 82.97872340425532%;
208
+ *width: 82.92553191489361%;
209
+ }
210
+ .row-fluid .span9 {
211
+ width: 74.46808510638297%;
212
+ *width: 74.41489361702126%;
213
+ }
214
+ .row-fluid .span8 {
215
+ width: 65.95744680851064%;
216
+ *width: 65.90425531914893%;
217
+ }
218
+ .row-fluid .span7 {
219
+ width: 57.44680851063829%;
220
+ *width: 57.39361702127659%;
221
+ }
222
+ .row-fluid .span6 {
223
+ width: 48.93617021276595%;
224
+ *width: 48.88297872340425%;
225
+ }
226
+ .row-fluid .span5 {
227
+ width: 40.42553191489362%;
228
+ *width: 40.37234042553192%;
229
+ }
230
+ .row-fluid .span4 {
231
+ width: 31.914893617021278%;
232
+ *width: 31.861702127659576%;
233
+ }
234
+ .row-fluid .span3 {
235
+ width: 23.404255319148934%;
236
+ *width: 23.351063829787233%;
237
+ }
238
+ .row-fluid .span2 {
239
+ width: 14.893617021276595%;
240
+ *width: 14.840425531914894%;
241
+ }
242
+ .row-fluid .span1 {
243
+ width: 6.382978723404255%;
244
+ *width: 6.329787234042553%;
245
+ }
246
+ .row-fluid .offset12 {
247
+ margin-left: 104.25531914893617%;
248
+ *margin-left: 104.14893617021275%;
249
+ }
250
+ .row-fluid .offset12:first-child {
251
+ margin-left: 102.12765957446808%;
252
+ *margin-left: 102.02127659574467%;
253
+ }
254
+ .row-fluid .offset11 {
255
+ margin-left: 95.74468085106382%;
256
+ *margin-left: 95.6382978723404%;
257
+ }
258
+ .row-fluid .offset11:first-child {
259
+ margin-left: 93.61702127659574%;
260
+ *margin-left: 93.51063829787232%;
261
+ }
262
+ .row-fluid .offset10 {
263
+ margin-left: 87.23404255319149%;
264
+ *margin-left: 87.12765957446807%;
265
+ }
266
+ .row-fluid .offset10:first-child {
267
+ margin-left: 85.1063829787234%;
268
+ *margin-left: 84.99999999999999%;
269
+ }
270
+ .row-fluid .offset9 {
271
+ margin-left: 78.72340425531914%;
272
+ *margin-left: 78.61702127659572%;
273
+ }
274
+ .row-fluid .offset9:first-child {
275
+ margin-left: 76.59574468085106%;
276
+ *margin-left: 76.48936170212764%;
277
+ }
278
+ .row-fluid .offset8 {
279
+ margin-left: 70.2127659574468%;
280
+ *margin-left: 70.10638297872339%;
281
+ }
282
+ .row-fluid .offset8:first-child {
283
+ margin-left: 68.08510638297872%;
284
+ *margin-left: 67.9787234042553%;
285
+ }
286
+ .row-fluid .offset7 {
287
+ margin-left: 61.70212765957446%;
288
+ *margin-left: 61.59574468085106%;
289
+ }
290
+ .row-fluid .offset7:first-child {
291
+ margin-left: 59.574468085106375%;
292
+ *margin-left: 59.46808510638297%;
293
+ }
294
+ .row-fluid .offset6 {
295
+ margin-left: 53.191489361702125%;
296
+ *margin-left: 53.085106382978715%;
297
+ }
298
+ .row-fluid .offset6:first-child {
299
+ margin-left: 51.063829787234035%;
300
+ *margin-left: 50.95744680851063%;
301
+ }
302
+ .row-fluid .offset5 {
303
+ margin-left: 44.68085106382979%;
304
+ *margin-left: 44.57446808510638%;
305
+ }
306
+ .row-fluid .offset5:first-child {
307
+ margin-left: 42.5531914893617%;
308
+ *margin-left: 42.4468085106383%;
309
+ }
310
+ .row-fluid .offset4 {
311
+ margin-left: 36.170212765957444%;
312
+ *margin-left: 36.06382978723405%;
313
+ }
314
+ .row-fluid .offset4:first-child {
315
+ margin-left: 34.04255319148936%;
316
+ *margin-left: 33.93617021276596%;
317
+ }
318
+ .row-fluid .offset3 {
319
+ margin-left: 27.659574468085104%;
320
+ *margin-left: 27.5531914893617%;
321
+ }
322
+ .row-fluid .offset3:first-child {
323
+ margin-left: 25.53191489361702%;
324
+ *margin-left: 25.425531914893618%;
325
+ }
326
+ .row-fluid .offset2 {
327
+ margin-left: 19.148936170212764%;
328
+ *margin-left: 19.04255319148936%;
329
+ }
330
+ .row-fluid .offset2:first-child {
331
+ margin-left: 17.02127659574468%;
332
+ *margin-left: 16.914893617021278%;
333
+ }
334
+ .row-fluid .offset1 {
335
+ margin-left: 10.638297872340425%;
336
+ *margin-left: 10.53191489361702%;
337
+ }
338
+ .row-fluid .offset1:first-child {
339
+ margin-left: 8.51063829787234%;
340
+ *margin-left: 8.404255319148938%;
341
+ }
342
+ [class*="span"].hide,
343
+ .row-fluid [class*="span"].hide {
344
+ display: none;
345
+ }
346
+ [class*="span"].pull-right,
347
+ .row-fluid [class*="span"].pull-right {
348
+ float: right;
349
+ }
350
+ .container {
351
+ margin-right: auto;
352
+ margin-left: auto;
353
+ *zoom: 1;
354
+ }
355
+ .container:before,
356
+ .container:after {
357
+ display: table;
358
+ content: "";
359
+ line-height: 0;
360
+ }
361
+ .container:after {
362
+ clear: both;
363
+ }
364
+ .container-fluid {
365
+ padding-right: 20px;
366
+ padding-left: 20px;
367
+ *zoom: 1;
368
+ }
369
+ .container-fluid:before,
370
+ .container-fluid:after {
371
+ display: table;
372
+ content: "";
373
+ line-height: 0;
374
+ }
375
+ .container-fluid:after {
376
+ clear: both;
377
+ }
378
+ p {
379
+ margin: 0 0 10px;
380
+ }
381
+ .lead {
382
+ margin-bottom: 20px;
383
+ font-size: 21px;
384
+ font-weight: 200;
385
+ line-height: 30px;
386
+ }
387
+ small {
388
+ font-size: 85%;
389
+ }
390
+ strong {
391
+ font-weight: bold;
392
+ }
393
+ em {
394
+ font-style: italic;
395
+ }
396
+ cite {
397
+ font-style: normal;
398
+ }
399
+ .muted {
400
+ color: #999999;
401
+ }
402
+ .text-warning {
403
+ color: #c09853;
404
+ }
405
+ a.text-warning:hover {
406
+ color: #a47e3c;
407
+ }
408
+ .text-error {
409
+ color: #b94a48;
410
+ }
411
+ a.text-error:hover {
412
+ color: #953b39;
413
+ }
414
+ .text-info {
415
+ color: #3a87ad;
416
+ }
417
+ a.text-info:hover {
418
+ color: #2d6987;
419
+ }
420
+ .text-success {
421
+ color: #468847;
422
+ }
423
+ a.text-success:hover {
424
+ color: #356635;
425
+ }
426
+ h1,
427
+ h2,
428
+ h3,
429
+ h4,
430
+ h5,
431
+ h6 {
432
+ margin: 10px 0;
433
+ font-family: inherit;
434
+ font-weight: bold;
435
+ line-height: 20px;
436
+ color: inherit;
437
+ text-rendering: optimizelegibility;
438
+ }
439
+ h1 small,
440
+ h2 small,
441
+ h3 small,
442
+ h4 small,
443
+ h5 small,
444
+ h6 small {
445
+ font-weight: normal;
446
+ line-height: 1;
447
+ color: #999999;
448
+ }
449
+ h1,
450
+ h2,
451
+ h3 {
452
+ line-height: 40px;
453
+ }
454
+ h1 {
455
+ font-size: 38.5px;
456
+ }
457
+ h2 {
458
+ font-size: 31.5px;
459
+ }
460
+ h3 {
461
+ font-size: 24.5px;
462
+ }
463
+ h4 {
464
+ font-size: 17.5px;
465
+ }
466
+ h5 {
467
+ font-size: 14px;
468
+ }
469
+ h6 {
470
+ font-size: 11.9px;
471
+ }
472
+ h1 small {
473
+ font-size: 24.5px;
474
+ }
475
+ h2 small {
476
+ font-size: 17.5px;
477
+ }
478
+ h3 small {
479
+ font-size: 14px;
480
+ }
481
+ h4 small {
482
+ font-size: 14px;
483
+ }
484
+ .page-header {
485
+ padding-bottom: 9px;
486
+ margin: 20px 0 30px;
487
+ border-bottom: 1px solid #eeeeee;
488
+ }
489
+ ul,
490
+ ol {
491
+ padding: 0;
492
+ margin: 0 0 10px 25px;
493
+ }
494
+ ul ul,
495
+ ul ol,
496
+ ol ol,
497
+ ol ul {
498
+ margin-bottom: 0;
499
+ }
500
+ li {
501
+ line-height: 20px;
502
+ }
503
+ ul.unstyled,
504
+ ol.unstyled {
505
+ margin-left: 0;
506
+ list-style: none;
507
+ }
508
+ dl {
509
+ margin-bottom: 20px;
510
+ }
511
+ dt,
512
+ dd {
513
+ line-height: 20px;
514
+ }
515
+ dt {
516
+ font-weight: bold;
517
+ }
518
+ dd {
519
+ margin-left: 10px;
520
+ }
521
+ .dl-horizontal {
522
+ *zoom: 1;
523
+ }
524
+ .dl-horizontal:before,
525
+ .dl-horizontal:after {
526
+ display: table;
527
+ content: "";
528
+ line-height: 0;
529
+ }
530
+ .dl-horizontal:after {
531
+ clear: both;
532
+ }
533
+ .dl-horizontal dt {
534
+ float: left;
535
+ width: 160px;
536
+ clear: left;
537
+ text-align: right;
538
+ overflow: hidden;
539
+ text-overflow: ellipsis;
540
+ white-space: nowrap;
541
+ }
542
+ .dl-horizontal dd {
543
+ margin-left: 180px;
544
+ }
545
+ hr {
546
+ margin: 20px 0;
547
+ border: 0;
548
+ border-top: 1px solid #eeeeee;
549
+ border-bottom: 1px solid #ffffff;
550
+ }
551
+ abbr[title],
552
+ abbr[data-original-title] {
553
+ cursor: help;
554
+ border-bottom: 1px dotted #999999;
555
+ }
556
+ abbr.initialism {
557
+ font-size: 90%;
558
+ text-transform: uppercase;
559
+ }
560
+ blockquote {
561
+ padding: 0 0 0 15px;
562
+ margin: 0 0 20px;
563
+ border-left: 5px solid #eeeeee;
564
+ }
565
+ blockquote p {
566
+ margin-bottom: 0;
567
+ font-size: 16px;
568
+ font-weight: 300;
569
+ line-height: 25px;
570
+ }
571
+ blockquote small {
572
+ display: block;
573
+ line-height: 20px;
574
+ color: #999999;
575
+ }
576
+ blockquote small:before {
577
+ content: '\2014 \00A0';
578
+ }
579
+ blockquote.pull-right {
580
+ float: right;
581
+ padding-right: 15px;
582
+ padding-left: 0;
583
+ border-right: 5px solid #eeeeee;
584
+ border-left: 0;
585
+ }
586
+ blockquote.pull-right p,
587
+ blockquote.pull-right small {
588
+ text-align: right;
589
+ }
590
+ blockquote.pull-right small:before {
591
+ content: '';
592
+ }
593
+ blockquote.pull-right small:after {
594
+ content: '\00A0 \2014';
595
+ }
596
+ q:before,
597
+ q:after,
598
+ blockquote:before,
599
+ blockquote:after {
600
+ content: "";
601
+ }
602
+ address {
603
+ display: block;
604
+ margin-bottom: 20px;
605
+ font-style: normal;
606
+ line-height: 20px;
607
+ }
608
+ .label,
609
+ .badge {
610
+ display: inline-block;
611
+ padding: 2px 4px;
612
+ font-size: 11.844px;
613
+ font-weight: bold;
614
+ line-height: 14px;
615
+ color: #ffffff;
616
+ vertical-align: baseline;
617
+ white-space: nowrap;
618
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
619
+ background-color: #999999;
620
+ }
621
+ .label {
622
+ -webkit-border-radius: 3px;
623
+ -moz-border-radius: 3px;
624
+ border-radius: 3px;
625
+ }
626
+ .badge {
627
+ padding-left: 9px;
628
+ padding-right: 9px;
629
+ -webkit-border-radius: 9px;
630
+ -moz-border-radius: 9px;
631
+ border-radius: 9px;
632
+ }
633
+ a.label:hover,
634
+ a.badge:hover {
635
+ color: #ffffff;
636
+ text-decoration: none;
637
+ cursor: pointer;
638
+ }
639
+ .label-important,
640
+ .badge-important {
641
+ background-color: #b94a48;
642
+ }
643
+ .label-important[href],
644
+ .badge-important[href] {
645
+ background-color: #953b39;
646
+ }
647
+ .label-warning,
648
+ .badge-warning {
649
+ background-color: #f89406;
650
+ }
651
+ .label-warning[href],
652
+ .badge-warning[href] {
653
+ background-color: #c67605;
654
+ }
655
+ .label-success,
656
+ .badge-success {
657
+ background-color: #468847;
658
+ }
659
+ .label-success[href],
660
+ .badge-success[href] {
661
+ background-color: #356635;
662
+ }
663
+ .label-info,
664
+ .badge-info {
665
+ background-color: #3a87ad;
666
+ }
667
+ .label-info[href],
668
+ .badge-info[href] {
669
+ background-color: #2d6987;
670
+ }
671
+ .label-inverse,
672
+ .badge-inverse {
673
+ background-color: #333333;
674
+ }
675
+ .label-inverse[href],
676
+ .badge-inverse[href] {
677
+ background-color: #1a1a1a;
678
+ }
679
+ .btn .label,
680
+ .btn .badge {
681
+ position: relative;
682
+ top: -1px;
683
+ }
684
+ .btn-mini .label,
685
+ .btn-mini .badge {
686
+ top: 0;
687
+ }
688
+ table {
689
+ max-width: 100%;
690
+ background-color: transparent;
691
+ border-collapse: collapse;
692
+ border-spacing: 0;
693
+ }
694
+ .table {
695
+ width: 100%;
696
+ margin-bottom: 20px;
697
+ }
698
+ .table th,
699
+ .table td {
700
+ padding: 8px;
701
+ line-height: 20px;
702
+ text-align: left;
703
+ vertical-align: top;
704
+ border-top: 1px solid #dddddd;
705
+ }
706
+ .table th {
707
+ font-weight: bold;
708
+ }
709
+ .table thead th {
710
+ vertical-align: bottom;
711
+ }
712
+ .table caption + thead tr:first-child th,
713
+ .table caption + thead tr:first-child td,
714
+ .table colgroup + thead tr:first-child th,
715
+ .table colgroup + thead tr:first-child td,
716
+ .table thead:first-child tr:first-child th,
717
+ .table thead:first-child tr:first-child td {
718
+ border-top: 0;
719
+ }
720
+ .table tbody + tbody {
721
+ border-top: 2px solid #dddddd;
722
+ }
723
+ .table-condensed th,
724
+ .table-condensed td {
725
+ padding: 4px 5px;
726
+ }
727
+ .table-bordered {
728
+ border: 1px solid #dddddd;
729
+ border-collapse: separate;
730
+ *border-collapse: collapse;
731
+ border-left: 0;
732
+ -webkit-border-radius: 4px;
733
+ -moz-border-radius: 4px;
734
+ border-radius: 4px;
735
+ }
736
+ .table-bordered th,
737
+ .table-bordered td {
738
+ border-left: 1px solid #dddddd;
739
+ }
740
+ .table-bordered caption + thead tr:first-child th,
741
+ .table-bordered caption + tbody tr:first-child th,
742
+ .table-bordered caption + tbody tr:first-child td,
743
+ .table-bordered colgroup + thead tr:first-child th,
744
+ .table-bordered colgroup + tbody tr:first-child th,
745
+ .table-bordered colgroup + tbody tr:first-child td,
746
+ .table-bordered thead:first-child tr:first-child th,
747
+ .table-bordered tbody:first-child tr:first-child th,
748
+ .table-bordered tbody:first-child tr:first-child td {
749
+ border-top: 0;
750
+ }
751
+ .table-bordered thead:first-child tr:first-child th:first-child,
752
+ .table-bordered tbody:first-child tr:first-child td:first-child {
753
+ -webkit-border-top-left-radius: 4px;
754
+ border-top-left-radius: 4px;
755
+ -moz-border-radius-topleft: 4px;
756
+ }
757
+ .table-bordered thead:first-child tr:first-child th:last-child,
758
+ .table-bordered tbody:first-child tr:first-child td:last-child {
759
+ -webkit-border-top-right-radius: 4px;
760
+ border-top-right-radius: 4px;
761
+ -moz-border-radius-topright: 4px;
762
+ }
763
+ .table-bordered thead:last-child tr:last-child th:first-child,
764
+ .table-bordered tbody:last-child tr:last-child td:first-child,
765
+ .table-bordered tfoot:last-child tr:last-child td:first-child {
766
+ -webkit-border-radius: 0 0 0 4px;
767
+ -moz-border-radius: 0 0 0 4px;
768
+ border-radius: 0 0 0 4px;
769
+ -webkit-border-bottom-left-radius: 4px;
770
+ border-bottom-left-radius: 4px;
771
+ -moz-border-radius-bottomleft: 4px;
772
+ }
773
+ .table-bordered thead:last-child tr:last-child th:last-child,
774
+ .table-bordered tbody:last-child tr:last-child td:last-child,
775
+ .table-bordered tfoot:last-child tr:last-child td:last-child {
776
+ -webkit-border-bottom-right-radius: 4px;
777
+ border-bottom-right-radius: 4px;
778
+ -moz-border-radius-bottomright: 4px;
779
+ }
780
+ .table-bordered caption + thead tr:first-child th:first-child,
781
+ .table-bordered caption + tbody tr:first-child td:first-child,
782
+ .table-bordered colgroup + thead tr:first-child th:first-child,
783
+ .table-bordered colgroup + tbody tr:first-child td:first-child {
784
+ -webkit-border-top-left-radius: 4px;
785
+ border-top-left-radius: 4px;
786
+ -moz-border-radius-topleft: 4px;
787
+ }
788
+ .table-bordered caption + thead tr:first-child th:last-child,
789
+ .table-bordered caption + tbody tr:first-child td:last-child,
790
+ .table-bordered colgroup + thead tr:first-child th:last-child,
791
+ .table-bordered colgroup + tbody tr:first-child td:last-child {
792
+ -webkit-border-top-right-radius: 4px;
793
+ border-top-right-radius: 4px;
794
+ -moz-border-radius-topright: 4px;
795
+ }
796
+ .table-striped tbody tr:nth-child(odd) td,
797
+ .table-striped tbody tr:nth-child(odd) th {
798
+ background-color: #f9f9f9;
799
+ }
800
+ .table-hover tbody tr:hover td,
801
+ .table-hover tbody tr:hover th {
802
+ background-color: #f5f5f5;
803
+ }
804
+ table td[class*="span"],
805
+ table th[class*="span"],
806
+ .row-fluid table td[class*="span"],
807
+ .row-fluid table th[class*="span"] {
808
+ display: table-cell;
809
+ float: none;
810
+ margin-left: 0;
811
+ }
812
+ .table td.span1,
813
+ .table th.span1 {
814
+ float: none;
815
+ width: 44px;
816
+ margin-left: 0;
817
+ }
818
+ .table td.span2,
819
+ .table th.span2 {
820
+ float: none;
821
+ width: 124px;
822
+ margin-left: 0;
823
+ }
824
+ .table td.span3,
825
+ .table th.span3 {
826
+ float: none;
827
+ width: 204px;
828
+ margin-left: 0;
829
+ }
830
+ .table td.span4,
831
+ .table th.span4 {
832
+ float: none;
833
+ width: 284px;
834
+ margin-left: 0;
835
+ }
836
+ .table td.span5,
837
+ .table th.span5 {
838
+ float: none;
839
+ width: 364px;
840
+ margin-left: 0;
841
+ }
842
+ .table td.span6,
843
+ .table th.span6 {
844
+ float: none;
845
+ width: 444px;
846
+ margin-left: 0;
847
+ }
848
+ .table td.span7,
849
+ .table th.span7 {
850
+ float: none;
851
+ width: 524px;
852
+ margin-left: 0;
853
+ }
854
+ .table td.span8,
855
+ .table th.span8 {
856
+ float: none;
857
+ width: 604px;
858
+ margin-left: 0;
859
+ }
860
+ .table td.span9,
861
+ .table th.span9 {
862
+ float: none;
863
+ width: 684px;
864
+ margin-left: 0;
865
+ }
866
+ .table td.span10,
867
+ .table th.span10 {
868
+ float: none;
869
+ width: 764px;
870
+ margin-left: 0;
871
+ }
872
+ .table td.span11,
873
+ .table th.span11 {
874
+ float: none;
875
+ width: 844px;
876
+ margin-left: 0;
877
+ }
878
+ .table td.span12,
879
+ .table th.span12 {
880
+ float: none;
881
+ width: 924px;
882
+ margin-left: 0;
883
+ }
884
+ .table tbody tr.success td {
885
+ background-color: #dff0d8;
886
+ }
887
+ .table tbody tr.error td {
888
+ background-color: #f2dede;
889
+ }
890
+ .table tbody tr.warning td {
891
+ background-color: #fcf8e3;
892
+ }
893
+ .table tbody tr.info td {
894
+ background-color: #d9edf7;
895
+ }
896
+ .table-hover tbody tr.success:hover td {
897
+ background-color: #d0e9c6;
898
+ }
899
+ .table-hover tbody tr.error:hover td {
900
+ background-color: #ebcccc;
901
+ }
902
+ .table-hover tbody tr.warning:hover td {
903
+ background-color: #faf2cc;
904
+ }
905
+ .table-hover tbody tr.info:hover td {
906
+ background-color: #c4e3f3;
907
+ }