sinatra-hexacta 0.0.2 → 0.3.2

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/lib/sinatra/extensions/antiquity.rb +34 -0
  3. data/lib/sinatra/extensions/date.rb +49 -0
  4. data/lib/sinatra/extensions/generalmail.rb +26 -0
  5. data/lib/sinatra/extensions/init.rb +8 -0
  6. data/lib/sinatra/extensions/mail.rb +35 -0
  7. data/lib/sinatra/extensions/mailbuilder.rb +38 -0
  8. data/lib/sinatra/extensions/mailsender.rb +88 -0
  9. data/lib/sinatra/extensions/notification.rb +44 -0
  10. data/lib/sinatra/handlers/errors.rb +11 -4
  11. data/lib/sinatra/handlers/init.rb +3 -1
  12. data/lib/sinatra/handlers/notifications.rb +17 -28
  13. data/lib/sinatra/handlers/params.rb +26 -0
  14. data/lib/sinatra/handlers/reports.rb +28 -1
  15. data/lib/sinatra/helpers/alerts.rb +27 -0
  16. data/lib/sinatra/helpers/cas.rb +92 -0
  17. data/lib/sinatra/helpers/charts.rb +21 -5
  18. data/lib/sinatra/helpers/init.rb +4 -0
  19. data/lib/sinatra/helpers/inputs.rb +3 -3
  20. data/lib/sinatra/helpers/libraries.rb +3 -3
  21. data/lib/sinatra/helpers/reports.rb +27 -0
  22. data/lib/sinatra/helpers/schedule.rb +68 -0
  23. data/lib/sinatra/helpers/subscriptions.rb +1 -1
  24. data/lib/sinatra/hexacta.rb +15 -9
  25. data/lib/sinatra/public/css/app.min.1.css +132 -6
  26. data/lib/sinatra/public/js/app.js +49 -42
  27. data/lib/sinatra/public/vendors/chartist/chartist-plugin-legend.js +237 -0
  28. data/lib/sinatra/public/vendors/typeahead.js/typeahead.bundle.min.js +1 -2
  29. data/lib/sinatra/views/alerts/empty.slim +7 -0
  30. data/lib/sinatra/views/alerts/error.slim +7 -0
  31. data/lib/sinatra/views/alerts/info.slim +7 -0
  32. data/lib/sinatra/views/alerts/warning.slim +7 -0
  33. data/lib/sinatra/views/charts/bar.slim +56 -0
  34. data/lib/sinatra/views/charts/gauge.slim +30 -0
  35. data/lib/sinatra/views/charts/{simple_line.slim → line.slim} +7 -8
  36. data/lib/sinatra/views/charts/pie.slim +34 -0
  37. data/lib/sinatra/views/charts/stacked_bar.slim +36 -0
  38. data/lib/sinatra/views/inputs/multiple_select.slim +4 -0
  39. data/lib/sinatra/views/inputs/select.slim +3 -0
  40. data/lib/sinatra/views/libraries/include_js_after.slim +0 -24
  41. data/lib/sinatra/views/libraries/include_js_before.slim +1 -0
  42. data/lib/sinatra/views/notifications.slim +37 -31
  43. data/lib/sinatra/views/notifications/form.slim +4 -4
  44. data/lib/sinatra/views/notifications/new.slim +4 -4
  45. data/lib/sinatra/views/notifications/widget.slim +9 -5
  46. data/lib/sinatra/views/reports/pick_date.slim +14 -0
  47. data/lib/sinatra/views/reports/pick_dates.slim +16 -0
  48. data/lib/sinatra/views/reports/pick_month.slim +14 -0
  49. data/lib/sinatra/views/reports/pick_year.slim +14 -0
  50. metadata +30 -4
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+ module Sinatra
3
+ module ParamsHandler
4
+
5
+ def enable_params
6
+ p "Enabling params handler..."
7
+
8
+ before "*" do
9
+ unless params.nil?
10
+ tmp = {}
11
+ for key in params.keys
12
+ value = params[key]
13
+ value = value.join(",").split(",") if value.respond_to? :join
14
+ tmp[key.to_sym] = value
15
+ end
16
+ @params.clear
17
+ @params = tmp
18
+ end
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+
25
+ register ParamsHandler
26
+ end
@@ -1 +1,28 @@
1
- #TOBEDONE
1
+ # encoding: utf-8
2
+ module Sinatra
3
+ module ReportHandler
4
+ extend Hexacta
5
+
6
+ def enable_reports
7
+ p "Enabling reports..."
8
+ before '/reports/*' do
9
+ error(403) if authenticated(User).permissions.empty?
10
+ end
11
+
12
+ get '/reports' do
13
+ slim :reports
14
+ end
15
+
16
+ get '/reports/:report_name' do |report_name|
17
+ date = Date.parse(params["date"]) unless params["date"].nil?
18
+ date ||= Date.today
19
+ headers "Content-Disposition" => "attachment;filename=#{report_name}.#{date}.xls",
20
+ "Content-Type" => "application/octet-stream"
21
+ slim "reports/#{report_name}".to_sym, locals: { :date => date }, :layout => false
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ register ReportHandler
28
+ end
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+ module Sinatra
3
+ module AlertHelper
4
+ extend Hexacta
5
+
6
+ def info_alert(option_hash)
7
+ slim "#{Hexacta::GEM_FILE_DIR}/alerts/info".to_sym, locals: option_hash
8
+ end
9
+
10
+ def empty_alert(option_hash)
11
+ slim "#{Hexacta::GEM_FILE_DIR}/alerts/empty".to_sym, locals: option_hash
12
+ end
13
+
14
+ def warning_alert(option_hash)
15
+ slim "#{Hexacta::GEM_FILE_DIR}/alerts/warning".to_sym, locals: option_hash
16
+ end
17
+
18
+ def error_alert(option_hash)
19
+ slim "#{Hexacta::GEM_FILE_DIR}/alerts/error".to_sym, locals: option_hash
20
+ end
21
+
22
+ setup_dir("/app/views/#{Hexacta::GEM_FILE_DIR}/alerts")
23
+ copy_all_files("/lib/sinatra/views/alerts","/app/views/#{Hexacta::GEM_FILE_DIR}/alerts")
24
+ end
25
+
26
+ helpers AlertHelper
27
+ end
@@ -0,0 +1,92 @@
1
+ require 'active_support/all' #bug in rubycas client requires this
2
+ require 'rubycas-client'
3
+
4
+ module Sinatra
5
+ module CasHelper
6
+
7
+ CAS_CLIENT = CASClient::Client.new(:cas_base_url => ENV['CAS_BASE_URL'], :log => Logger.new(STDOUT), :ticket_store_config => {:storage_dir => ENV['TICKET_STORE_DIR']})
8
+
9
+ def need_authentication(request, session)
10
+ if session[:cas_ticket]
11
+ if request[:ticket] && session[:cas_ticket] != request[:ticket]
12
+ true
13
+ else
14
+ false
15
+ end
16
+ else
17
+ true
18
+ end
19
+ end
20
+
21
+ def process_cas_login(request, session)
22
+ if request[:ticket] && request[:ticket] != session[:ticket]
23
+
24
+ service_url = read_service_url(request)
25
+ service_ticket = read_ticket(request[:ticket], service_url)
26
+
27
+ CAS_CLIENT.validate_service_ticket(service_ticket)
28
+
29
+ if service_ticket.success
30
+ session[:cas_ticket] = service_ticket.ticket
31
+ session[:cas_user] = service_ticket.user
32
+ else
33
+ redirect request.path_info
34
+ #raise "Service Ticket validation failed! #{st.failure_code} - #{st.failure_message}"
35
+ end
36
+ end
37
+
38
+ end
39
+
40
+ def logged_in?(request, session)
41
+ session[:cas_ticket] && !session[:cas_ticket].empty?
42
+ end
43
+
44
+ def require_authorization(request, session)
45
+ if !logged_in?(request, session)
46
+ service_url = read_service_url(request)
47
+ url = CAS_CLIENT.add_service_to_login_url(service_url)
48
+ redirect url
49
+ end
50
+ end
51
+
52
+ def authenticated(model)
53
+ raise 500 if session[:cas_user].nil? || session[:cas_user].empty?
54
+ model.find(:hxt_id => "#{session[:cas_user]}")
55
+ end
56
+
57
+ private
58
+ def read_ticket(ticket_str, service_url)
59
+ return nil unless ticket_str and !ticket_str.empty?
60
+
61
+ if ticket_str =~ /^PT-/
62
+ CASClient::ProxyTicket.new(ticket_str, service_url)
63
+ else
64
+ CASClient::ServiceTicket.new(ticket_str, service_url)
65
+ end
66
+ end
67
+
68
+ def read_service_url(request)
69
+ service_url = url(request.path_info)
70
+ if request.GET
71
+ params = request.GET.dup
72
+ params.delete(:ticket)
73
+ if params
74
+ [service_url, Rack::Utils.build_nested_query(params)].join('?')
75
+ end
76
+ end
77
+ return service_url
78
+ end
79
+
80
+ def logout_cas(request, session)
81
+ if logged_in?(request, session)
82
+ url = CAS_CLIENT.logout_url()
83
+ session.clear
84
+ str = request.referer
85
+ comeback = "=" + (str.include?("?")? str.slice(0..(str.index('?')-1)) : str) #Hack mal!
86
+ redirect url + (url.include?("?service")? "" : "?service") + comeback
87
+ end
88
+ end
89
+ end
90
+
91
+ helpers CasHelper
92
+ end
@@ -1,15 +1,31 @@
1
1
  # encoding: utf-8
2
2
  module Sinatra
3
- module ChartsHandler
3
+ module ChartsHelper
4
4
  extend Hexacta
5
5
 
6
- def simple_line(option_hash)
7
- slim "#{Hexacta::GEM_FILE_DIR}/charts/simple_line".to_sym, locals: option_hash
6
+ def line_chart(option_hash)
7
+ slim "#{Hexacta::GEM_FILE_DIR}/charts/line".to_sym, locals: option_hash
8
+ end
9
+
10
+ def bar_chart(option_hash)
11
+ slim "#{Hexacta::GEM_FILE_DIR}/charts/bar".to_sym, locals: option_hash
12
+ end
13
+
14
+ def pie_chart(option_hash)
15
+ slim "#{Hexacta::GEM_FILE_DIR}/charts/pie".to_sym, locals: option_hash
16
+ end
17
+
18
+ def gauge_chart(option_hash)
19
+ slim "#{Hexacta::GEM_FILE_DIR}/charts/gauge".to_sym, locals: option_hash
20
+ end
21
+
22
+ def stacked_bar_chart(option_hash)
23
+ slim "#{Hexacta::GEM_FILE_DIR}/charts/stacked_bar".to_sym, locals: option_hash
8
24
  end
9
25
 
10
26
  setup_dir("/app/views/#{Hexacta::GEM_FILE_DIR}/charts")
11
- symlink_all("/lib/sinatra/views/charts","/app/views/#{Hexacta::GEM_FILE_DIR}/charts")
27
+ copy_all_files("/lib/sinatra/views/charts","/app/views/#{Hexacta::GEM_FILE_DIR}/charts")
12
28
  end
13
29
 
14
- helpers ChartsHandler
30
+ helpers ChartsHelper
15
31
  end
@@ -3,3 +3,7 @@ require_relative 'libraries'
3
3
  require_relative 'inputs'
4
4
  require_relative 'charts'
5
5
  require_relative 'subscriptions'
6
+ require_relative 'cas'
7
+ require_relative 'schedule'
8
+ require_relative 'alerts'
9
+ require_relative 'reports'
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
  module Sinatra
3
- module InputHandler
3
+ module InputHelper
4
4
  extend Hexacta
5
5
 
6
6
  def date_input(option_hash)
@@ -40,8 +40,8 @@ module Sinatra
40
40
  end
41
41
 
42
42
  setup_dir("/app/views/#{Hexacta::GEM_FILE_DIR}/inputs")
43
- symlink_all("/lib/sinatra/views/inputs","/app/views/#{Hexacta::GEM_FILE_DIR}/inputs")
43
+ copy_all_files("/lib/sinatra/views/inputs","/app/views/#{Hexacta::GEM_FILE_DIR}/inputs")
44
44
  end
45
45
 
46
- helpers InputHandler
46
+ helpers InputHelper
47
47
  end
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
  module Sinatra
3
- module LibrariesHandler
3
+ module LibrariesHelper
4
4
  extend Hexacta
5
5
 
6
6
  def include_css
@@ -18,8 +18,8 @@ module Sinatra
18
18
  p "Setting up libraries directory..."
19
19
  copy_dir_structure("/lib/sinatra/public","/app/public/#{Hexacta::GEM_FILE_DIR}")
20
20
  setup_dir("/app/views/#{Hexacta::GEM_FILE_DIR}/libraries")
21
- symlink_all("/lib/sinatra/views/libraries","/app/views/#{Hexacta::GEM_FILE_DIR}/libraries")
21
+ copy_all_files("/lib/sinatra/views/libraries","/app/views/#{Hexacta::GEM_FILE_DIR}/libraries")
22
22
  end
23
23
 
24
- helpers LibrariesHandler
24
+ helpers LibrariesHelper
25
25
  end
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+ module Sinatra
3
+ module ReportHelper
4
+ extend Hexacta
5
+
6
+ def pick_date_input(option_hash)
7
+ slim "#{Hexacta::GEM_FILE_DIR}/reports/pick_date".to_sym, locals: option_hash
8
+ end
9
+
10
+ def pick_dates_input(option_hash)
11
+ slim "#{Hexacta::GEM_FILE_DIR}/reports/pick_dates".to_sym, locals: option_hash
12
+ end
13
+
14
+ def pick_month_input(option_hash)
15
+ slim "#{Hexacta::GEM_FILE_DIR}/reports/pick_month".to_sym, locals: option_hash
16
+ end
17
+
18
+ def pick_year_input(option_hash)
19
+ slim "#{Hexacta::GEM_FILE_DIR}/reports/pick_year".to_sym, locals: option_hash
20
+ end
21
+
22
+ setup_dir("/app/views/#{Hexacta::GEM_FILE_DIR}/reports")
23
+ copy_all_files("/lib/sinatra/views/reports","/app/views/#{Hexacta::GEM_FILE_DIR}/reports")
24
+ end
25
+
26
+ helpers ReportHelper
27
+ end
@@ -0,0 +1,68 @@
1
+ require 'timeout'
2
+ # encoding: utf-8
3
+ module Sinatra
4
+ module ScheduleHelper
5
+
6
+ @@scheduler = Rufus::Scheduler.new
7
+
8
+ def schedule_every(time)
9
+ @@scheduler.every time do
10
+ begin
11
+ file_path = "/tmp/schedule.lock";
12
+ f = File.open(file_path, "w+")
13
+ # if file was previosly locked then flock throw a exception
14
+ f.flock(File::LOCK_EX)
15
+ ten_minutes = 600
16
+ # if the process overcome ten minutes, the timeout api throw a exception
17
+ Timeout::timeout(ten_minutes) do
18
+
19
+ begin
20
+ yield
21
+ rescue StandardError => error
22
+ title = error.message.split(':')[0].gsub('#<','');
23
+ message = error.backtrace.join(',');
24
+ NotificationSender.instance.send_error(nil,title,message)
25
+ end
26
+
27
+ end
28
+ ensure
29
+ unless f.nil?
30
+ f.flock(File::LOCK_UN)
31
+ f.close
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ def schedule_at(cron_expression)
38
+ @@scheduler.cron cron_expression do
39
+ begin
40
+ file_path = "/tmp/schedule.lock";
41
+ f = File.open(file_path, "w+")
42
+ # if file was previosly locked then flock throw a exception
43
+ f.flock(File::LOCK_EX)
44
+ ten_minutes = 600
45
+ # if the process overcome ten minutes, the timeout api throw a exception
46
+ Timeout::timeout(ten_minutes) do
47
+
48
+ begin
49
+ yield
50
+ rescue error
51
+ title = error.message.split(':')[0].gsub('#<','');
52
+ message = error.backtrace.join(',');
53
+ NotificationSender.instance.send_error(nil,title,message)
54
+ end
55
+
56
+ end
57
+ ensure
58
+ unless f.nil?
59
+ f.flock(File::LOCK_UN)
60
+ f.close
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ register ScheduleHelper
68
+ end
@@ -3,7 +3,6 @@ module Sinatra
3
3
  module SubscriptionHelper
4
4
 
5
5
  def notify_to(user,creator,title,message,label,link=nil)
6
- #return if creator.id == user.id
7
6
  notification = Notification.find_or_create(:user_id => user.id,
8
7
  :creator_id => creator.id,
9
8
  :title => title,
@@ -26,6 +25,7 @@ module Sinatra
26
25
 
27
26
  def notify_error(creator,title,message)
28
27
  Subscription.where(:label => 'error').all.each do |subscription|
28
+ creator = subscription.user if creator.nil?
29
29
  notification = Notification.find(:user_id => subscription.user_id,
30
30
  :creator_id => creator.id,
31
31
  :title => title,
@@ -1,32 +1,38 @@
1
1
  # encoding: utf-8
2
2
  require 'sinatra/base'
3
3
  require 'fileutils'
4
+ require 'sucker_punch'
5
+ require 'rufus-scheduler'
4
6
 
5
7
  module Sinatra
8
+
6
9
  module Hexacta
7
10
  GEM_FILE_DIR = "sinatra-hexacta"
8
11
 
9
- def symlink(original_path, link_path)
10
- #p "Symlinking #{original_path} #{link_path}"
11
- File.symlink "#{Gem.loaded_specs["sinatra-hexacta"].gem_dir}#{original_path}", "#{link_path}" unless Gem.loaded_specs["sinatra-hexacta"].nil? || File.exist?("#{link_path}")
12
+ def gem_path
13
+ File.expand_path("../..",__dir__)
14
+ end
15
+
16
+ def copy_file(original_path, link_path)
17
+ IO.copy_stream("#{gem_path}#{original_path}",link_path) unless File.exist?(link_path) && FileUtils.compare_file("#{gem_path}#{original_path}",link_path)
12
18
  end
13
19
 
14
- def symlink_all(original_path, link_path)
15
- Dir.foreach("#{Gem.loaded_specs["sinatra-hexacta"].gem_dir}#{original_path}") do |child|
16
- symlink("#{original_path}/#{child}","#{link_path}/#{child}") unless child == '.' || child == '..'
20
+ def copy_all_files(original_path, link_path)
21
+ Dir.foreach("#{gem_path}#{original_path}") do |child|
22
+ copy_file("#{original_path}/#{child}","#{link_path}/#{child}") unless child == '.' || child == '..'
17
23
  end
18
24
  end
19
25
 
20
26
  def setup_dir(path)
21
- FileUtils.mkdir_p path unless Dir.exist? path
27
+ FileUtils.mkdir_p path
22
28
  end
23
29
 
24
30
  def copy_dir_structure(original_path, destination_path)
25
- FileUtils.remove_dir destination_path if Dir.exist? destination_path
26
- FileUtils.copy_entry("#{Gem.loaded_specs["sinatra-hexacta"].gem_dir}#{original_path}", destination_path)
31
+ FileUtils.copy_entry("#{gem_path}#{original_path}", destination_path)
27
32
  end
28
33
  end
29
34
  end
30
35
 
31
36
  require_relative 'helpers/init'
32
37
  require_relative 'handlers/init'
38
+ require_relative 'extensions/init'
@@ -10550,10 +10550,6 @@ h6 small,
10550
10550
  left: 0;
10551
10551
  top: 0;
10552
10552
  padding: 0 11px;
10553
- transition: all .5s ease-out;
10554
- -moz-transition: all .5s ease-out;
10555
- -o-transition: all .5s ease-out;
10556
- -webkit-transition: all .5s ease-out;
10557
10553
  }
10558
10554
 
10559
10555
  #header:not(.sidebar-toggled).header-up {
@@ -10594,8 +10590,8 @@ h6 small,
10594
10590
  color: white;
10595
10591
  }
10596
10592
 
10597
- #header input[type="text"]::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
10598
- color: rgba(255,255,255,0.6);;
10593
+ #header input[type="text"]::placeholder {
10594
+ color: rgba(255,255,255,0.6);;
10599
10595
  }
10600
10596
 
10601
10597
  #top-search-wrap input[type="text"] {
@@ -11925,6 +11921,10 @@ a.lv-footer:hover {
11925
11921
  width: 100%;
11926
11922
  }
11927
11923
 
11924
+ .chart-table table {
11925
+ font-size: 11px;
11926
+ }
11927
+
11928
11928
  /*
11929
11929
  * Sparkline Tooltip
11930
11930
  */
@@ -16229,3 +16229,129 @@ body.login-content:before {
16229
16229
  .error .chosen-container-active .chosen-single:after {
16230
16230
  background: #f6675d !Important;
16231
16231
  }
16232
+
16233
+ svg.ct-chart-bar, svg.ct-chart-line{
16234
+ overflow: visible;
16235
+ }
16236
+
16237
+ .ct-label.ct-label.ct-horizontal.ct-end {
16238
+ position: relative;
16239
+ justify-content: flex-end;
16240
+ text-align: right;
16241
+ transform-origin: 100% 0;
16242
+ transform: translate(-100%) rotate(-45deg);
16243
+ white-space:nowrap;
16244
+ }
16245
+
16246
+
16247
+ .ct-legend {
16248
+ position: relative;
16249
+ z-index: 10;
16250
+ list-style: none;
16251
+ text-align: left;
16252
+ cursor: pointer;
16253
+ }
16254
+
16255
+ .bar-chart .ct-legend, .line-chart .ct-legend {
16256
+ text-align: center;
16257
+ }
16258
+
16259
+ .ct-legend li {
16260
+ position: relative;
16261
+ padding-left: 23px;
16262
+ margin-bottom: 3px;
16263
+ }
16264
+
16265
+ .bar-chart .ct-legend li, .line-chart .ct-legend li{
16266
+ display: inline-block;
16267
+ margin: 10px;
16268
+ }
16269
+
16270
+ .ct-legend li:before {
16271
+ width: 12px;
16272
+ height: 12px;
16273
+ position: absolute;
16274
+ left: 0;
16275
+ content: '';
16276
+ border: 3px solid transparent;
16277
+ border-radius: 2px;
16278
+ }
16279
+
16280
+ .ct-legend li.inactive:before {
16281
+ background: transparent;
16282
+ }
16283
+
16284
+ .ct-legend .ct-series-0:before {
16285
+ background-color: #d70206;
16286
+ border-color: #d70206;
16287
+ }
16288
+
16289
+ .ct-legend .ct-series-1:before {
16290
+ background-color: #f05b4f;
16291
+ border-color: #f05b4f;
16292
+ }
16293
+
16294
+ .ct-legend .ct-series-2:before {
16295
+ background-color: #f4c63d;
16296
+ border-color: #f4c63d;
16297
+ }
16298
+
16299
+ .ct-legend .ct-series-3:before {
16300
+ background-color: #d17905;
16301
+ border-color: #d17905;
16302
+ }
16303
+
16304
+ .ct-legend .ct-series-4:before {
16305
+ background-color: #453d3f;
16306
+ border-color: #453d3f;
16307
+ }
16308
+
16309
+ .ct-legend .ct-series-5:before {
16310
+ background-color: #59922b;
16311
+ border-color: #59922b;
16312
+ }
16313
+
16314
+ .ct-legend .ct-series-6:before {
16315
+ background-color: #0544d3;
16316
+ border-color: #0544d3;
16317
+ }
16318
+
16319
+ .ct-legend .ct-series-7:before {
16320
+ background-color: #6b0392;
16321
+ border-color: #6b0392;
16322
+ }
16323
+
16324
+ .ct-legend .ct-series-8:before {
16325
+ background-color: #f05b4f;
16326
+ border-color: #f05b4f;
16327
+ }
16328
+
16329
+ .ct-legend .ct-series-9:before {
16330
+ background-color: #dda458;
16331
+ border-color: #dda458;
16332
+ }
16333
+
16334
+ .ct-legend .ct-series-10:before {
16335
+ background-color: #eacf7d;
16336
+ border-color: #eacf7d;
16337
+ }
16338
+
16339
+ .ct-legend .ct-series-11:before {
16340
+ background-color: #86797d;
16341
+ border-color: #86797d;
16342
+ }
16343
+
16344
+ .ct-legend .ct-series-12:before {
16345
+ background-color: #b2c326;
16346
+ border-color: #b2c326;
16347
+ }
16348
+
16349
+ .ct-legend .ct-series-13:before {
16350
+ background-color: #6188e2;
16351
+ border-color: #6188e2;
16352
+ }
16353
+
16354
+ .ct-legend .ct-series-14:before {
16355
+ background-color: #a748ca;
16356
+ border-color: #a748ca;
16357
+ }